XPathSelectElement总是返回null
本文关键字:null 返回 XPathSelectElement | 更新日期: 2023-09-27 17:53:23
为什么使用XDocument.XPathSelectElement不能工作?
Xpath://Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]
XML <Plugin xmlns="http://www.MyNamespace.ca/MyPath">
<UI>
<PluginPageCategory>
<Page>
<Group>
<CommandRef>
<Images>
</Images>
</CommandRef>
<CommandRef>
<Images>
</Images>
</CommandRef>
</Group>
</Page>
</PluginPageCategory>
</UI>
</Plugin>
c#代码:myXDocument.XPathSelectElement("//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]", myXDocument.Root.CreateNavigator());
使用名称空间时,也必须在XPath查询中使用这些名称空间。XPath查询只适用于没有名称空间的元素(可以通过从XML中删除名称空间来验证)。
下面的示例展示了如何创建和传递名称空间管理器:
var xml = ... XML from your post ...;
var xmlReader = XmlReader.Create( new StringReader(xml) ); // Or whatever your source is, of course.
var myXDocument = XDocument.Load( xmlReader );
var namespaceManager = new XmlNamespaceManager( xmlReader.NameTable ); // We now have a namespace manager that knows of the namespaces used in your document.
namespaceManager.AddNamespace( "prefix", "http://www.MyNamespace.ca/MyPath" ); // We add an explicit prefix mapping for our query.
var result = myXDocument.XPathSelectElement(
"//prefix:Plugin/prefix:UI[1]/prefix:PluginPageCategory[1]/prefix:Page[1]/prefix:Group[1]/prefix:CommandRef[2]",
namespaceManager
); // We use that prefix against the elements in the query.
Console.WriteLine(result); // <CommandRef ...> element is printed.
这应该是对@Cumbayah的帖子的评论,但我似乎不能对任何事情发表评论。
您可能最好使用这样的东西,而不是使用XmlReader来获取命名表。
var xml = ... XML from your post ...;
var myXDocument = XDocument.Parse(xml);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("prefix", "http://www.MyNamespace.ca/MyPath");
var result = ...;
在这种情况下,最简单的方法是使用XPath 轴和节点测试作为节点名称和位置来选择元素。您的XPath选择:
myXDocument.XPathSelectElement("//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]", myXDocument.Root.CreateNavigator());
可以很容易地翻译成:
myXDocument.XPathSelectElement("/child::node()[local-name()='Plugin']/child::node()[local-name()='UI'][position()=1]/child::node()[local-name()='PluginPageCategory'][position()=1]/child::node()[local-name()='Page'][position()=1]/child::node()[local-name()='Group'][position()=1]/child::node()[local-name()='CommandRef'][position()=2]");
不需要创建并传递XmlNamespaceManager作为参数
有一种方法可以在不更改xpath的情况下做到这一点。我发现的解决方案是在将XML解析为XDocument时删除名称空间。
下面是一个例子:
var regex = @"(xmlns:?[^=]*=[""][^""]*[""])";
var myXDocument = XDocument.Parse(Regex.Replace("MyXmlContent", regex, "", RegexOptions.IgnoreCase | RegexOptions.Multiline))
既然名称空间没有了,操作起来就容易多了。