How to update an XML node with LINQ? - c#

How do we update the a node name with a new value using LINQ?
<test xmlns="http://www.mydomain.com/test/xyz" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<Ribbon1>test</Ribbon1>
<Ribbon2>test</Ribbon2>
</test>
I was trying as below:
var query = from lst in XElement.Load(fileLoc).Elements(ns + "Ribbon1")
select lst.FirstNode ;
The below code is working now:
XNamespace ns = #"http://www.mydomain.com/test/xyz";
XElement xElement = XElement.Load(fileLoc);
foreach (XElement descendant in xElement.Descendants(ns + "Ribbon1"))
descendant.Value = "Borra";
xElement.Save(fileLoc);

Your code use Elemnts and that only looks at the given level. To find something at an arbitrary level:
//XElement.Load(fileLoc).Elements(ns + "Ribbon1")
XElement.Load(fileLoc).Descendants(ns + "Ribbon1")
or to adhere to the structure:
XElement.Load(fileLoc).Element(ns + "test").Elements(ns + "Ribbon1")
be careful about Element() and Elements()

XNamespace ns = #"http://www.mydomain.com/test/xyz";
XElement xElement = XElement.Load(fileLoc);
foreach (XElement descendant in xElement.Descendants(ns + "Ribbon1"))
descendant.Value = "Borra";
xElement.Save(fileLoc);

Related

Load data from XML nodes

i have this structure of data:
<?xml version="1.0" encoding="windows-1250"?>
<?xml-stylesheet type="text/xsl" href="usb71105.xsl"?>
<manas:usb xmlns:manas="http://www.manas.info/">
<manas:qr00>
<manas:verzemanas>26052708</manas:verzemanas>
<manas:verzexml>2016.03.29a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/2159405/TRUE</manas:druhtisku>
</manas:qr00>
<manas:qr00>
<manas:verzemanas>26052710</manas:verzemanas>
<manas:verzexml>2016.03.30a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/FALSE</manas:druhtisku>
</manas:qr00>
</manas:usb>
I need to save values of: manas:verzemanas ; manas:verzexml ;
I have this code:
XmlDocument doc = new XmlDocument();
doc.Load("d:\\83116623.XML");
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].ToString();
}
Have you any ideas please?
You're probably better off with XDocument. Also you need to use the namespace prefix. E.g.:
XNamespace ns = "http://www.manas.info/";
var xdoc = XDocument.Load(#"c:\temp\a\a.xml");
var verze = xdoc.Root.Elements(ns + "qr00")
.Elements(ns + "verzemanas")
.Select(e => e.Value);
verze.ToList().ForEach(v => Console.WriteLine(v));
prints
26052708
26052710

c# Xdocument and descendants with the same name not working

Hi have the following XML with the same Transaction name (can't change it because this is how it comes from the origin):
<StoreCenter Operation="update" xmlns="http://something.com/rdc.xsd">
<Transaction>
<Transaction>
<StoreID>30</StoreID>
<TransactionID>2</TransactionID>
<RegisterTransNumber>2</RegisterTransNumber>
....
</Transaction>
<Transaction>
<StoreID>30</StoreID>
<TransactionID>3</TransactionID>
<RegisterTransNumber>2</RegisterTransNumber>
....
<Transaction>
<Transaction>
<StoreCenter>
I have the following code and I'm new in LINQ, I'm trying to retrive the StoreID for each Transaction Child:
XDocument Doc = XDocument.Load(filename);
XNamespace ns = "http://something.com/rdc.xsd";
foreach (var StoreCenter in Doc.Descendants(ns + "StoreCenter"))
{
foreach (var Transaction in StoreCenter.Descendants("Transaction"))
{
foreach (var TransactionCh in Transaction.Descendants("Transaction"))
{
Console.WriteLine(Transaction.Element("StoreID").Value);
}
}
}
But I'm getting nothing, what am I doing wrong?, is this a good approach to retrieve these values?, please your advice will be appreciated
Remove the curly brace from here:
Doc.Descendants("{" + ns + "StoreCenter")
^^^
And you should specify the namespace with child elements as well.Like: StoreCenter.Descendants(ns + "Transaction") and Transaction.Descendants(ns + "Transaction")
if you just want to get Transaction elements you can just to : Doc.Descendants(ns + "Transaction") or Doc.Root.Element(ns + "Transaction").Elements(ns + "Transaction"); (assuming StoreCenter is the root element)
If your XML is correctly closed (i assume that the Transaction and StoreCenter nodes from the example XML are closed), then - yes, your approach using LINQ2XML is correct.
You could enhance the code using the XElement.GetDefaultNamespace() method to retrieve the default namespace easily (easier than typing). A solution could look like this:
var xml = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<StoreCenter Operation=""update"" xmlns=""http://something.com/rdc.xsd"">
<Transaction>
<Transaction>
<StoreID>30</StoreID>
<TransactionID>2</TransactionID>
<RegisterTransNumber>2</RegisterTransNumber>
</Transaction>
<Transaction>
<StoreID>30</StoreID>
<TransactionID>3</TransactionID>
<RegisterTransNumber>2</RegisterTransNumber>
</Transaction>
</Transaction>
</StoreCenter>";
var xmlDocument = XDocument.Parse(xml); // or XDocument.Load(xml);
var ns = xmlDocument.Root.GetDefaultNamespace();
var transactions = xmlDocument
.Root // the StoreCenter root node
.Element(ns + "Transaction") // the enclosing Transaction node
.Elements(ns + "Transaction") // only Transaction subnodes
.ToList();
foreach (var transaction in transactions)
{
var storeId = transaction.Element(ns + "StoreID").Value;
Console.WriteLine(storeId);
}
And the output is:
30
30

Access all nodes in xml using linq

I have xml:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<UpdateMemberHireStatus xmlns="http://tempuri.org/">
<member>
<HireAvailability>
<code>1</code>
<name>פנוי</name>
</HireAvailability>
<HireRejectReason>
<code>2</code>
<name>wow</name>
</HireRejectReason>
<IdNumber>43504349</IdNumber>
<note> </note>
</member>
</UpdateMemberHireStatus>
and I want to use LINQ to access all the nodes in the xml.
Here's what I have tried:
XNamespace ns = "tempuri.org/";
IEnumerable<HireStatus> status = from r in doc.Descendants(ns + "UpdateMemberHireStatus")
.Descendants(ns + "member")
select new HireStatus() { };
return status.ToList();
Use Descendants
var xml = XDocument.Load(XMLStream);
var allEle = xml.Descendants("UpdateMemberHireStatus"); //you can do linq now.
You can use XDocument also in the following way:
string xmlPath = "D://member.xml";
XmlDocument doc = new XmlDocument();
xdoc = XDocument.Load(xmlPath);
doc.LoadXml(xdoc.ToString());
var memberStatus= (from mem in xdoc.Descendants("member")
select mem);
foreach (XElement element in memberStatuses.ToList())
IEnumerable<XNode> nodes = element.Nodes();
var x = XElement.Load(XMLStream);
var all = x.DescendantNodes();

XDocument.Descendants not returning descendants

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SetNationalList xmlns="http://www.lge.com/ddc">
<nationalList>
<portnumber>6000</portnumber>
<slaveaddress>7000</slaveaddress>
<flagzone>2</flagzone>
<flagindivisual>5</flagindivisual>
<flagdimming>3</flagdimming>
<flagpattern>6</flagpattern>
<flaggroup>9</flaggroup>
</nationalList>
</SetNationalList>
</s:Body>
</s:Envelope>
XDocument xdoc = XDocument.Parse(xml);
foreach (XElement element in xdoc.Descendants("nationalList"))
{
MessageBox.Show(element.ToString());
}
I'd like to iterate through every nodes under nationalList but it isn't working for me, it skips the foreach loop entirely. What am I doing wrong here?
You're not including the namespace, which is "http://www.lge.com/ddc", defaulted from the parent element:
XNamespace ns = "http://www.lge.com/ddc";
foreach (XElement element in xdoc.Descendants(ns + "nationalList"))
{
...
}
You have to use the namespace:
// do _not_ use var ns = ... here.
XNameSpace ns = "http://www.lge.com/ddc";
foreach (XElement element in xdoc.Descendants(ns + "nationalList")
{
MessageBox.Show(element.ToString());
}
If you don't want to have to use the ns prefix in all the selectors you can also remove the namespace upfront when parsing the xml. eg:
string ns = "http://www.lge.com/ddc";
XDocument xdoc = XDocument.Parse(xml.Replace(ns, string.Empty));
foreach (XElement element in xdoc.Descendants("nationalList")
...
It is correct that you have to include the namespace, but the samples above do not work unless you put the namespace in curly braces:
XNameSpace ns = "http://www.lge.com/ddc";
foreach (XElement element in xdoc.Descendants("{" + ns + "}nationalList")
{
MessageBox.Show(element.ToString());
}
Greetings
Christian

XDocument and Linq returns null if the element has xmlns attribute

Newbie with XDocuments and Linq, please suggest a solution to retrieve the data from a particular tag in the xml string:
If I have a XML string from webservice response (I formatted xml for ease):
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCashFlowReportResponse xmlns="http://tempuri.org/">
<GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf>
</GetCashFlowReportResponse>
</soap:Body>
</soap:Envelope>
Using the following code, I can get the value only if GetCashFlowReportResponse tag doesn't have "xmlns" attribute. Not sure why? Otherwise, it always return null.
string inputString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetCashFlowReportResponse xmlns=\"http://tempuri.org/\"><GetCashFlowReportPdf>Hello!</GetCashFlowReportPdf></GetCashFlowReportResponse></soap:Body></soap:Envelope>"
XDocument xDoc = XDocument.Parse(inputString);
//XNamespace ns = "http://tempuri.org/";
XNamespace ns = XNamespace.Get("http://tempuri.org/");
var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
select (string)c.Element("GetCashFlowReportPdf");
foreach (string val in data)
{
Console.WriteLine(val);
}
I can't change the web service to remove that attribute. IS there a better way to read the response and get the actual data back to the user (in more readable form)?
Edited:
SOLUTION:
XDocument xDoc = XDocument.Parse(inputString);
XNamespace ns = "http://tempuri.org/";
var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
select (string)c.Element(ns + "GetCashFlowReportPdf");
foreach (string val in data)
{
Console.WriteLine(val);
}
Note: Even if all the child elements doesn't have the namespace attribute, the code will work if you add the "ns" to the element as I guess childs inherit the namespace from parent (see response from SLaks).
You need to include the namespace:
XNamespace ns = "http://tempuri.org/";
xDoc.Descendants(ns + "GetCashFlowReportResponse")
XName qualifiedName = XName.Get("GetCashFlowReportResponse",
"http://tempuri.org/");
var data = from d in xDoc.Descendants(qualifiedName)
Just ask for the elements using the qualified names:
// create a XML namespace object
XNamespace ns = XNamespace.Get("http://tempuri.org/");
var data = from c in xDoc.Descendants(ns + "GetCashFlowReportResponse")
select (string)c.Element(ns + "GetCashFlowReportPdf");
Note the use of the overloaded + operator that creates a QName with a XML namespace and a local name string.

Categories

Resources