在XElement和XDocument上使用XPathEvaluate的区别是什么?

3
在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() 是做什么的? - Anirudha
RetrieveXElement() 是我代码中的一个方法,它返回一个有效的 XElement。为了简单起见,假设 RetrieveXElment 是 'XElement.Parse(theTestXml);'。 - BasiK
为什么要在 System.Xml.Linq 中使用 XPath? - Jodrell
为什么不呢?我的程序在内存中使用LINQ构建XML(出于明显的原因)。有没有更好的方法来获取特定属性,而不是使用xpath?我肯定想知道。 但我还对XElement/XDocument之间的区别感兴趣... - BasiK
2
也许在你的第一个案例中,你认为是根元素的那个元素并不是真正的根...你可以尝试这样写: "//exampleRoot/exampleSection[@name='test']/@value"。我把它作为评论发布,而不是答案,因为这只是一个猜测。 - Tom
我注意到你还有一个非常有趣的帖子:".NET GDI+绘图性能"。我给它点了个赞,以便引起应有的关注。 :-) - Tom
1个回答

9
问题在于XPath表达式是以指定节点的子节点开头的。如果你从一个XDocument开始,根元素就是子节点。如果你从表示你的exampleRoot节点的XElement开始,那么子节点就是两个exampleSection节点。
如果你将XPath表达式更改为"/exampleSection[@name='test']/@value",它将从元素中起作用。如果你将其更改为"//exampleSection[@name='test']/@value",它将从XElement和XDocument中都起作用。

真的很有用且出乎意料。非常感谢分享,因为你节省了我相当多(更多)试图弄清楚为什么我的选择器不起作用的时间! - ProNotion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接