Select an XML node via XPath at an arbitrary depth

2019-06-25 15:51发布

Having an XML document, I want to get the first node with a certain name, no matter in which nesting depth it is contained.

I tried several things without success:

var node1 = doc.SelectSingleNode(@"//Shortcut");
var node2 = doc.SelectSingleNode(@"/*/Shortcut");
var node3 = doc.SelectSingleNode(@"//*/Shortcut");
var node4 = doc.SelectSingleNode(@"*/Shortcut");
...

Each call results in a NULL node.

I think it should be some trivial XPath syntax. Can you help me?

(In case this matters: The XML document is an input file for a WiX project, so there could be some namespace issues involved?!?).

Edit

I also tried the following:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

together with:

var node1 = doc.SelectSingleNode(@"//Shortcut", nsm);
var node2 = doc.SelectSingleNode(@"/*/Shortcut", nsm);
var node3 = doc.SelectSingleNode(@"//*/Shortcut", nsm);
var node4 = doc.SelectSingleNode(@"*/Shortcut", nsm);
...

Leading to the same results.

Edit 2 - Solution

I found the solution:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

and then

var node1 = doc.SelectSingleNode(@"//ns:Shortcut", nsm);

This succeeded.

标签: c# xml xpath wix
3条回答
乱世女痞
2楼-- · 2019-06-25 16:23

The XPath expression that selects exactly the wanted node (and nothing in addition) is:

(//x:Shortcut)[1]

So, using:

doc.SelectNodes("(//x:Shortcut)[1]", someNamespaceManager)

where

the prefix "x" is bound to the namespace "http://schemas.microsoft.com/wix/2006/wi"

in someNamespaceManager

This has an advantage over the proposed solution (to use SelectSingleNode()), because it can easily be adjusted to select the N-th wanted node in the XML document.

For example:

   (//x:Shortcut)[3]

selects the 3rd (in document order) x:Shortcut element, and

   (//x:Shortcut)[last()]

selects the last (in document order) x:Shortcut element in the XML document.

查看更多
叛逆
3楼-- · 2019-06-25 16:34

Why do not use XDocument?

XDocument doc = XDocument.Load("test.xml");
doc.Descendants("Shortcut").First();

IMO XDocument is faster and more readable than XPath.

查看更多
戒情不戒烟
4楼-- · 2019-06-25 16:37

I finally found the solution by myself:

var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace(string.Empty, @"http://schemas.microsoft.com/wix/2006/wi");
nsm.AddNamespace(@"ns", @"http://schemas.microsoft.com/wix/2006/wi");

and then

var node1 = doc.SelectSingleNode(@"//ns:Shortcut", nsm);

This succeeded.

查看更多
登录 后发表回答