【问题标题】:Difference between XPathEvaluate on XElement or XDocument?XElement 或 XDocument 上的 XPathEvaluate 之间的区别?
【发布时间】:2012-11-26 11:38:04
【问题描述】:

在 C# 程序的某个地方,我需要从 xml 结构中获取属性值。我可以直接作为 XElement 访问这个 xml 结构,并有一个简单的 xpath 字符串来获取属性。但是,使用 XPathEvaluate 时,我大部分时间都会得到一个空数组。 (是的,有时会返回该属性,但大多数情况下它不是...对于完全相同的 XElement 和 xpath 字符串...) 但是,如果我首先将 xml 转换为字符串并将其重新解析为 XDocument,我总是会取回该属性。有人可以解释这种行为吗? (我正在使用 .NET 3.5)

大部分返回空 IEnumerable 的代码:

string xpath = "/exampleRoot/exampleSection[@name='test']/@value";
XElement myXelement = RetrieveXElement();
((IEnumerable)myXElement.XPathEvaluate(xpath)).Cast<XAttribute>().FirstOrDefault().Value;

始终有效的代码(我得到我的属性值):

string xpath = "/exampleRoot/exampleSection[@name='test']/@value";
string myXml = RetrieveXElement().ToString();
XDocument xdoc = XDocument.Parse(myXml);
((IEnumerable)xdoc.XPathEvaluate(xpath)).Cast<XAttribute>().FirstOrDefault().Value;

带有测试xml:

<exampleRoot>
    <exampleSection name="test" value="2" />
    <exampleSection name="test2" value="2" />
</exampleRoot>

根据与周围根相关的建议,我在测试程序中做了一些“干测试”,使用相同的 xml 结构(txtbxXml 和 txtbxXpath 代表上述 xml 和 xpath 表达式):

// 1. XDocument Trial:
((IEnumerable)XDocument.Parse(txtbxXml.Text).XPathEvaluate(txtbxXPath.Text)).Cast<XAttribute>().FirstOrDefault().Value.ToString();
// 2. XElement trial:
((IEnumerable)XElement.Parse(txtbxXml.Text).XPathEvaluate(txtbxXPath.Text)).Cast<XAttribute>().FirstOrDefault().Value.ToString();
// 3. XElement originating from other root:
((IEnumerable)(new XElement("otherRoot", XElement.Parse(txtbxXml.Text)).Element("exampleRoot")).XPathEvaluate(txtbxXPath.Text)).Cast<XAttribute>().FirstOrDefault().Value.ToString();

结果:案例 1 和 3 产生正确的结果,而案例 2 抛出 nullref 异常。 如果案例 3 失败而案例 2 成功,那对我来说会有些道理,但现在我不明白......

【问题讨论】:

  • RetrieveXElement() 做了什么。
  • RetrieveXElement() 是我的代码中返回有效 XElement 的一些方法。为了简单起见,假设 RetrieveXElment 是 'XElement.Parse(theTestXml);'
  • 为什么将 XPath 与 System.Xml.Linq 一起使用?
  • 为什么不呢?我的程序使用 LINQ(出于显而易见的原因)在内存中构建 xml。有没有更好的方法来获取特定属性而不是使用 xpath?我肯定很想知道。但仍然对导致 XElement/XDocument 差异的原因感兴趣......
  • 也许在您的第一种情况下,您认为是根的元素不是根...您可以这样尝试:“//exampleRoot/exampleSection[@name='test' ]/@价值”。我将其发布为评论,而不是答案,因为这只是一个猜测。

标签: c# linq-to-xml xelement


【解决方案1】:

问题在于 XPath 表达式从指定节点的子节点开始。如果以XDocument 开头,则根元素是子节点。如果您以代表 exampleRoot 节点的 XElement 开头,则子节点是两个 exampleSection 节点。

如果您将 XPath 表达式更改为 "/exampleSection[@name='test']/@value",它将在元素中起作用。如果您将其更改为"//exampleSection[@name='test']/@value",它将同时适用于XElementXDocument

【讨论】:

  • 知道真的很有用,但并不像预期的那样。感谢您的分享,因为您节省了我很多(更多)浪费的时间,试图找出我的选择器无法正常工作的原因!
猜你喜欢
  • 1970-01-01
  • 2011-04-22
  • 2012-11-07
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 2016-11-07
  • 1970-01-01
相关资源
最近更新 更多