XPath select node with namespace

Its .vbproj and is as follows

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProjectGuid>15a7ee82-9020-4fda-a7fb-85a61664692d</ProjectGuid> 

all I want to get is ProjectGuid, but it doesn't work when the namespace exists ...

  Dim xmlDoc As New XmlDocument() Dim filePath As String = Path.Combine(mDirectory, name + "\" + name + ".vbproj") xmlDoc.Load(filePath) Dim value As Object = xmlDoc.SelectNodes("/Project/PropertyGroup/ProjectGuid") 

what can i do to fix this?

+62
xml xpath xml-namespaces
Feb 11 '09 at 11:49
source share
6 answers

The best way to do such things (IMHO) is to create a namespace manager. This can be used by calling SelectNodes to indicate which namespace URLs are associated with prefixes. I usually set a static property that returns the corresponding instance (this is C #, you will have to translate):

 private static XmlNamespaceManager _nsMgr; public static XmlNamespaceManager NsMgr { get { if (_nsMgr == null) { _nsMgr = new XmlNamespaceManager(new NameTable()); _nsMgr.AddNamespace("msb", "http://schemas.microsoft.com/developer/msbuild/2003"); } return _nsMgr; } } 

Here I include only one namespace, but you can have several. Then you can choose from a document like this:

 Dim value As Object = xmlDoc.SelectNodes("/msb:Project/msb:PropertyGroup/msb:ProjectGuid", NsMgr) 

Note that all elements are in the specified namespace.

+43
Feb 11 '09 at 12:14
source share

I would probably be inclined towards solving the Bartek * namespace, but the general solution is xpath:

//*[local-name()='ProjectGuid']

** since Bartack’s answer has disappeared, I recommend Teun (which is actually more detailed) *

+63
Feb 11 '09 at 12:05
source share

This problem has been here several times already .

Or you work with XPath expressions without an expression (it is not recommended to clumsy it and the potential for false positive matches - <msb:ProjectGuid> and <foo:ProjectGuid> same for this expression):

  // * [local-name () = 'ProjectGuid'] 

or you do the right thing and use the XmlNamespaceManager to register the namespace URI so that you can include the namespace prefix in XPath:

 Dim xmlDoc As New XmlDocument() xmlDoc.Load(Path.Combine(mDirectory, name, name + ".vbproj")) Dim nsmgr As New XmlNamespaceManager(xmlDoc.NameTable) nsmgr.AddNamespace("msb", "http://schemas.microsoft.com/developer/msbuild/2003") Dim xpath As String = "/msb:Project/msb:PropertyGroup/msb:ProjectGuid" Dim value As Object = xmlDoc.SelectNodes(xpath, nsmgr) 
+27
Feb 11 '09 at 12:19
source share

You just need to register these XML namespaces and prefix them to make the request work. Create and pass the namespace manager as the second parameter when selecting the nodes:

 Dim ns As New XmlNamespaceManager ( xmlDoc.NameTable ) ns.AddNamespace ( "msbuild", "http://schemas.microsoft.com/developer/msbuild/2003" ) Dim value As Object = xmlDoc.SelectNodes("/msbuild:Project/msbuild:PropertyGroup/msbuild:ProjectGuid", ns) 
+3
Feb 11 '09 at 12:20
source share

One way is to use the + NameSpaceManager extensions.
The code is in VB, but very easy to translate to C #.

 Imports System.Xml Imports System.Runtime.CompilerServices Public Module Extensions_XmlHelper 'XmlDocument Extension for SelectSingleNode <Extension()> Public Function _SelectSingleNode(ByVal XmlDoc As XmlDocument, xpath As String) As XmlNode If XmlDoc Is Nothing Then Return Nothing Dim nsMgr As XmlNamespaceManager = GetDefaultXmlNamespaceManager(XmlDoc, "x") Return XmlDoc.SelectSingleNode(GetNewXPath(xpath, "x"), nsMgr) End Function 'XmlDocument Extension for SelectNodes <Extension()> Public Function _SelectNodes(ByVal XmlDoc As XmlDocument, xpath As String) As XmlNodeList If XmlDoc Is Nothing Then Return Nothing Dim nsMgr As XmlNamespaceManager = GetDefaultXmlNamespaceManager(XmlDoc, "x") Return XmlDoc.SelectNodes(GetNewXPath(xpath, "x"), nsMgr) End Function Private Function GetDefaultXmlNamespaceManager(ByVal XmlDoc As XmlDocument, DefaultNamespacePrefix As String) As XmlNamespaceManager Dim nsMgr As New XmlNamespaceManager(XmlDoc.NameTable) nsMgr.AddNamespace(DefaultNamespacePrefix, XmlDoc.DocumentElement.NamespaceURI) Return nsMgr End Function Private Function GetNewXPath(xpath As String, DefaultNamespacePrefix As String) As String 'Methode 1: The easy way Return xpath.Replace("/", "/" + DefaultNamespacePrefix + ":") ''Methode 2: Does not change the nodes with existing namespace prefix 'Dim Nodes() As String = xpath.Split("/"c) 'For i As Integer = 0 To Nodes.Length - 1 ' 'If xpath starts with "/", don't add DefaultNamespacePrefix to the first empty node (before "/") ' If String.IsNullOrEmpty(Nodes(i)) Then Continue For ' 'Ignore existing namespaces prefixes ' If Nodes(i).Contains(":"c) Then Continue For ' 'Add DefaultNamespacePrefix ' Nodes(i) = DefaultNamespacePrefix + ":" + Nodes(i) 'Next ''Create and return then new xpath 'Return String.Join("/", Nodes) End Function End Module 

And use it:

 Imports Extensions_XmlHelper ...... Dim FileXMLTextReader As New XmlTextReader(".....") FileXMLTextReader.WhitespaceHandling = WhitespaceHandling.None Dim xmlDoc As XmlDocument = xmlDoc.Load(FileXMLTextReader) FileXMLTextReader.Close() ...... Dim MyNode As XmlNode = xmlDoc._SelectSingleNode("/Document/FirstLevelNode/SecondLevelNode") Dim MyNode As XmlNodeList = xmlDoc._SelectNodes("/Document/FirstLevelNode/SecondLevelNode") ...... 
0
Apr 11 '16 at 13:37
source share

Why not use // to ignore the namespace:

 Dim value As Object = xmlDoc.SelectNodes("//ProjectGuid") 

// acts like a wild card to keep track of everything between the root name and the next node (e.g. ProjectGuid)

-7
Feb 11 '09 at 11:56
source share



All Articles