Разбор XML с внутренними узлами? - PullRequest
4 голосов
/ 24 ноября 2010

У меня есть XML-файл, подобный приведенному ниже:

 <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>

Мне нужно извлечь из него id, name, desc, а из внутреннего узла trade_info мне нужно data/tab, buy_price_rate.

Итак, изначальноЯ думал об этом:

    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();
        }

Но, похоже, он не работает, и я не уверен, как его отладить.

С первой полученной мной ошибки, Null Expection, я верю этомуможет быть из node.Descendants("trade_info"), поскольку некоторые клиенты вообще не имеют trade_info.

Я также верю, что есть некоторые сообщения от:

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

Так как иногда у них нет элементов в спискеили buy_price_rate.

  • Как проверить в своем запросе, является ли он пустым или нет, чтобы обезопасить его
  • В порядке ли мой запрос для того, что я хочу?
  • Чтоя должен измениться?Советы?

Ответы [ 3 ]

3 голосов
/ 24 ноября 2010

Вы также можете сделать это ....

  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
               }
             };

Главное - определить, как выглядит ваш класс обёртывания, и определить, какими должны быть ваши значения по умолчанию, если нет данных дляконкретное свойство вы будете сопоставлять.(Я выбрал нули в этом примере)

2 голосов
/ 24 ноября 2010

Можете ли вы изменить trade часть вашего запроса на:

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
  }

..?

(вам нужно добавить using System.Xml.XPath)

2 голосов
/ 24 ноября 2010

Значение вашего документа должно быть типа XElement, тогда вы можете выбрать id как

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

использование XName не обязательно, вы можете просто использовать строку, но полезно, если ваш xml имеет пространства имен для некоторых элементов.

...