我有一个像这样的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()
版本,但在我看来,这是一种常见的情况,我必须遗漏一些东西......
答案 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文件。这将生成有意义的错误消息,如果文件有效,您可以毫无问题地解析它。