使用linq查询XML的异常

时间:2012-06-14 13:10:59

标签: c# asp.net linq linq-to-xml

我之前提出过这个问题,我得到了非常快速和有帮助的回复:Linq to XML query not picking up any values

我按照标记为正确的答案中给出的建议起作用,并允许我拿起“产品”标签。我现在在'Product'标签内搜索,以便找到要导入我的数据库的值,我又有点卡住了。

以下是我的XML文件的结构:

<?xml version="1.0"?>
<!DOCTYPE ONIXMessage SYSTEM "http://www.editeur.org/onix/2.1/reference/onix-international.dtd">
<ONIXMessage xmlns="http://www.editeur.org/onix/2.1/reference" release="2.1">
  <Header>
    <FromCompany>MyCo</FromCompany>
    <FromPerson>Joe Bloggs</FromPerson>
    <FromEmail>joe@bloggs.com</FromEmail>
    <SentDate>20120522</SentDate>
  </Header>
  <Product>
    <ProductForm>DG</ProductForm>
    <Title>
      <TitleType>01</TitleType>
      <TitleText>Blogg</TitleText>
    </Title>
    <WorkIdentifier>
      <WorkIDType>15</WorkIDType>
      <IDValue>PI3564231</IDValue>
    </WorkIdentifier>
    <Language>
      <LanguageRole>01</LanguageRole>
      <LanguageCode>eng</LanguageCode>
    </Language>
  </Product>
</ONIXMessage>

以下是我的代码中的代码段:

        XElement onix = XElement.Load(fs);

        // Get all the product information.
        //
        var products = onix.Descendants().Where(m => m.Name.LocalName == "Product").ToList();

        foreach (var p in products)
        {
            try
            {
                prod.Title = p.Elements("Title").First(t => (t.Element("TitleType").Value == "01")).Element("TitleText").Value;
                //further processing
            }
            catch (Exception exp)
            {
                throw new FileProcessingException("Unable to process product.", exp);
            }
        }

当我搜索如上所示的标题文本时,会捕获异常。例外情况是“对象引用未设置为对象的实例”。该项目显然在XML文件中,它只是没有正确选择它。

我从来没有见过。在Toda之前的Descendants(),我明白这意味着什么,但从我读到的内容我应该可以使用.Elements()在这里呢?

任何人都可以看到可能出错的地方吗?

2 个答案:

答案 0 :(得分:1)

好吧,当我回答你上一个问题时,我想我可能会帮忙......

您的文档有一个命名空间(xmlns)。 如果您想使用Elements(“tagName”)或Element(“tagName”)等,则必须在命名空间前面添加所有TagName。

所以你的查询会有效(如前一个问题中Habib.OSU所述),如果你这样做了

  XNamespace ns = onix.Attribute("xmlns").Value;
  var products2 = onix.Elements(ns + "Product").ToList();

  foreach (var p in products2)
  {
        var title = p.Elements(ns + "Title")
        .First(t => (t.Element(ns + "TitleType").Value == "01"))
        .Element(ns + "TitleText").Value;
  }

如果您绝对不想使用命名空间,则必须使用Descendants()和Name.LocalName。它会给你相同的,但是...它真的很难读。

 var products = onix.Descendants().Where(m => m.Name.LocalName == "Product").ToList();

 foreach (var p in products)
 {

      var title = p.Descendants().Where(m => m.Name.LocalName == "Title")
         .Descendants()
         .First(m => m.Name.LocalName == "TitleType" && m.Value == "01")
         .Parent
         .Descendants()
         .First(m => m.Name.LocalName == "TitleText")
         .Value;

 }

我没有放任何NULL检查,这当然是可以做的事情。

另请注意,第二个查询的性能较差,因为Descendants()枚举元素的所有子元素,而不考虑层次结构。而Elements()只会检索直接子节点。

答案 1 :(得分:0)

试试这个:

    XDocument doc = XDocument.Load(fs);
 var products= from elements in doc.Elements("ONIXMessage").Elements("Product");
   foreach (var p in products)
            {
                    var title  = (from items in p.Elements("Title")
                                 where items.Element("TitleType").Value == "01"
                                 select items.Element("TitleText").Value).FirstOrDefault();
            }