Jens Körte
Jens Körte

Reputation: 63

XML parsing a subtree in C#

I have many xml-files which I need to parse. The xml-files are loaded from elsewhere. I can examine these files to get the paths I need to extract my desired data. The paths aren't the same. So I added the paths in an ini-file for each xml-file. This works fine for 5 of 6 files.

WebClient client = new WebClient();
data = client.DownloadData("ftp://some.site/my.xml");
MemoryStream stream = new MemoryStream(data);
XmlDocument xml_doc = new XmlDocument();
xml_doc.Load(stream);
var prod_ids = xml_doc.DocumentElement.SelectNodes("/Catalog/Products/Product/Product_Id/text()");
foreach (XmlNode node in prod_ids) {
  [...]
}

In the last file I need to get 2 information from one subtree at once, because I have to combine them in one string, therefore reading all nodes seperatly doesn't work. See Example-XML:

<Catalog>
  <Created><![CDATA[2020-11-16T00:22:11+01:00]]></Created>
  <Products>
    <Product>
        <Product_Id><![CDATA[ABC]]></Product_Id>
        <Color_Code><![CDATA[123]]></Color_Code>
        <Size><![CDATA[]]></Size>
        <Length>210</Length>
        <Width>0</Width>
    </Product>
    <Product>
        <Product_Id><![CDATA[ABC]]></Product_Id>
        <Color_Code><![CDATA[456]]></Color_Code>
        <Size><![CDATA[]]></Size>
        <Length>44</Length>
        <Width>55</Width>
    </Product>
    <Product>
        <Product_Id><![CDATA[XYZ]]></Product_Id>
        <Color_Code><![CDATA[123]]></Color_Code>
        <Size><![CDATA[]]></Size>
        <Length>150</Length>
        <Width>11</Width>
    </Product>
  </Products>
</Catalog>
        

I'm lookig for some code which parses each subtree (/Catalog/Products/Product) in which I can read the innerText from Product_Id and Color_Code to combine them to one string. Any ideas?

Upvotes: 1

Views: 366

Answers (2)

Alexander Petrov
Alexander Petrov

Reputation: 14231

Use a more modern linq to xml.

var doc = XDocument.Load(stream);

var values = doc.Root
    .Element("Products")
    .Elements("Product")
    .Select(p => p.Element("Product_Id").Value + p.Element("Color_Code").Value);

foreach (var value in values)
    Console.WriteLine(value);

I can offer the following solution.

Get the values of different nodes using the OR operation |.

Then we go through the collection with an increment of two and combine the values.

var prod_ids = xml_doc.DocumentElement.SelectNodes(
    "/Catalog/Products/Product/Product_Id | /Catalog/Products/Product/Color_Code");

for (int i = 0; i < prod_ids.Count; i += 2)
    Console.WriteLine(prod_ids[i].InnerText + prod_ids[i + 1].InnerText);

Upvotes: 0

William Walseth
William Walseth

Reputation: 2923

You're really close, but you're going too low in the DOM tree. Instead of looping through each Product/ProductID, start your loop at each Product, then in the loop get each ProductID / ColorCode.

foreach( XmlElement ndProduct in xml.SelectNodes( "//Product") ) {
    XmlElement ndProductID = (XmlElement)ndProduct.SelectSingleNode("Product_Id");
    string strProductID = ndProductID.InnerText;

    XmlElement ndColorCode = (XmlElement)ndProduct.SelectSingleNode("Color_Code");
    string strColorCode = ndColorCode.InnerText;

    string strReturn = strProductID + " - " + strColorCode;
}

Upvotes: 2

Related Questions