Prix
Prix

Reputation: 19528

Parsing XML with inner nodes?

I have a XML file like the below:

 <clients>
  <client>
    <id>YYYY</id>
    <name>XXXX</name>
    <desc>ZZZZ</desc>
    <trade_info>
      <tab_list>
       <data>
         <tab>book 123</tab>
       </data>
       <data>
         <tab>cook 321</tab>
       </data>
      </tab_list>
      <buy_price_rate>200</buy_price_rate>
    </trade_info>
  </client>
 </clients>

I need to extract from it id, name, desc and from the inner node trade_info I need data/tab, buy_price_rate.

So initially I was thinking of this:

    var query = from node in doc.Descendants("client")
                select new
                {
                    client = new
                    {
                        Id = node.Element("id").Value,
                        Name = node.Element("name").Value,
                        Desc = node.Element("desc").Value
                    },

                    trade = from n in node.Descendants("trade_info")
                               select new
                               {
                                   Id = n.Element("tab_list").Element("data").Element("tab").Value,
                                   Buy = n.Element("buy_price_rate").Value
                               }
                };

        foreach (var item in query)
        {
            writeXML.WriteStartElement("tradelist_template");
            writeXML.WriteAttributeString("client_id", item.client.Id);
            foreach (var trade in item.trade)
            {
                writeXML.WriteStartElement("tradelist");
                writeXML.WriteAttributeString("item_id", trade.Id);
                writeXML.WriteEndElement();
            }
            writeXML.WriteEndElement();
        }

But it does not seem to work and im not sure on how to debug it.

From the first error I got, Null Expection I belive it may be coming from the node.Descendants("trade_info") as some clients have no trade_info at all.

I also belive there is some comming from:

Id = n.Element("tab_list").Element("data").Element("tab").Value,
Buy = n.Element("buy_price_rate").Value

As sometimes they dont have items on the list or buy_price_rate.

Upvotes: 4

Views: 648

Answers (3)

Tim Jarvis
Tim Jarvis

Reputation: 18815

you could also do this....

  var list = from item in doc.Descendants("client")
             let tradeinfoelement = item.Element("trade_info")
             select new
             {
               Client = new
               {
                 Id = (string)item.Element("id"),
                 Name = (string)item.Element("name"),
                 Desc = (string)item.Element("desc")
               },
               TradeInfo = new
               {
                 BuyPrice = tradeinfoelement.Element("buy_price_rate")  != null ? (int?)tradeinfoelement.Element("buy_price_rate") : null,
                 Tabs = tradeinfoelement.Descendants("tab") != null ? tradeinfoelement.Descendants("tab").Select(t => (string)t).ToList() : null
               }
             };

The main thing is to map out what your wrapping class looks like and work out what your defaults should be in case there is no data for the specific property you will map. (I chose nulls in this example)

Upvotes: 3

Carson63000
Carson63000

Reputation: 4232

Can you change the trade part of your query to:

trade = from n in node.Descendants("trade_info")
  select new
  {
    Id = (n.XPathSelectElement("tab_list/data/tab") == null) ? null : n.XPathSelectElement("tab_list/data/tab").Value,
    Buy = (n.Element("buy_price_rate") == null) ? null : n.Element("buy_price_rate").Value
  }

..?

(you'll need to add using System.Xml.XPath)

Upvotes: 2

DarthVX
DarthVX

Reputation: 25

Your value doc should of type XElement then you can select id like

var query = from el in doc.Descendants(XName.Get("id"))
 select el.Value;

using XName is not necessary you can just use a string, but is useful if your xml has namespaces on some of the elements.

Upvotes: 2

Related Questions