比element.Elements(“Whatever”)更好的解决方案。第一个()?

时间:2010-04-18 11:18:03

标签: linq linq-to-xml

我有一个像这样的XML文件:

<SiteConfig>
  <Sites>
    <Site Identifier="a" />
    <Site Identifier="b" />
    <Site Identifier="c" />
  </Sites>
</SiteConfig>

该文件是用户可编辑的,因此我想提供合理的错误消息,以防我无法正确解析它。我可能会为它写一个.xsd,但这对于一个简单的文件来说似乎有些过分。

所以无论如何,在查询<Site>节点列表时,有几种方法可以做到:

var doc = XDocument.Load(...);

var siteNodes = from siteNode in 
                  doc.Element("SiteConfig").Element("Sites").Elements("Site")
                select siteNode;

但问题是,如果用户没有包含<SiteUrls>节点(比方说),那么它只会抛出一个NullReferenceException,这对用户并没有真正说明实际内容出了问题。

另一种可能性就是在任何地方使用Elements()而不是Element(),但在与Attribute()的调用相结合时,这并不总是有效,例如,在以下情况中:

var siteNodes = from siteNode in 
                  doc.Elements("SiteConfig")
                     .Elements("Sites")
                     .Elements("Site")
                where siteNode.Attribute("Identifier").Value == "a"
                select siteNode;

(也就是说,没有等同于Attributes("xxx").Value

框架内置了一些内容来处理这种情况好一点吗?我更喜欢的是Element()(以及Attribute()的版本),它会抛出一个描述性异常(例如“在&lt; abc&gt;下寻找元素&lt; xyz&gt;但是没有找到了这样的元素“)而不是返回null

我可以编写自己的Element()Attribute()版本,但在我看来,这是一种常见的情况,我必须遗漏一些东西......

2 个答案:

答案 0 :(得分:2)

您可以将所需的功能实现为扩展方法:

public static class XElementExtension
{
    public static XElement ElementOrThrow(this XElement container, XName name)
    {
        XElement result = container.Element(name);
        if (result == null)
        {
            throw new InvalidDataException(string.Format(
                "{0} does not contain an element {1}",
                container.Name,
                name));
        }
        return result;
    }
}

XDocument你需要类似的东西。然后像这样使用它:

var siteNodes = from siteNode in 
    doc.ElementOrThrow("SiteConfig")
       .ElementOrThrow("SiteUrls")
       .Elements("Sites")
    select siteNode;

然后你会得到一个这样的例外:

SiteConfig does not contain an element SiteUrls

答案 1 :(得分:0)

您可以使用XPathSelectElements

using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;

class Program
{
    static void Main()
    {
        var ids = from site in XDocument.Load("test.xml")
                  .XPathSelectElements("//SiteConfig/Sites/Site")
                  let id = site.Attribute("Identifier")
                  where id != null
                  select id;
        foreach (var item in ids)
        {
            Console.WriteLine(item.Value);
        }
    }
}

我想到的另一件事是定义XSD架构并根据此架构验证XML文件。这将生成有意义的错误消息,如果文件有效,您可以毫无问题地解析它。