wake-up-neo.com

XPath-Auswahlknoten mit Namespace

Es ist ein .vbproj und sieht so aus

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

ich möchte nur das ProjectGuid erhalten, aber es funktioniert nicht, wenn ein Namespace vorhanden ist ...

 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")

was kann ich dagegen tun?

64
Peter

Der beste Weg, dies zu tun (IMHO), ist das Erstellen eines Namespace-Managers. Dies kann verwendet werden, um SelectNodes aufzurufen, um anzugeben, welche Namespace-URLs mit welchen Präfixen verbunden sind. Normalerweise habe ich eine statische Eigenschaft eingerichtet, die eine angemessene Instanz wie diese zurückgibt (es ist C #, Sie müssen übersetzen):

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;
  }
}

Ich füge hier nur einen Namespace ein, aber Sie könnten mehrere haben. Dann können Sie aus dem Dokument wie folgt auswählen:

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

Beachten Sie, dass sich alle Elemente im angegebenen Namespace befinden. 

44
Teun D

Ich würde wahrscheinlich dazu neigen Barteks* Namespace-Lösung, aber eine allgemeine xpath-Lösung ist:

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

** Da Barteks Antwort verschwunden ist, empfehle ich Teuns (was eigentlich gründlicher ist) *

63
annakata

Dieses Problem hat sich hier mehreremalbereits .

Entweder arbeiten Sie mit XPath-Ausdrücken mit Namensraum-Agnostik (nicht empfohlen für Ungeschicklichkeit und das Potenzial für falsch positive Übereinstimmungen - <msb:ProjectGuid> und <foo:ProjectGuid> sind für diesen Ausdruck gleich):

XmlNamespaceManager, um den Namespace-URI zu registrieren, sodass Sie ein Namespace-Präfix in Ihren XPath einfügen können:

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
Tomalak

Sie müssen nur diese XML-Namespaces registrieren und mit einem Präfix verknüpfen, damit die Abfrage funktioniert. _ Erstellen Sie einen Namespace-Manager und übergeben Sie diesen als zweiten Parameter, wenn Sie die Knoten auswählen:

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
baretta

Eine Möglichkeit ist die Verwendung von Erweiterungen + NameSpaceManager.
Code ist in VB, aber es ist wirklich leicht in C # zu übersetzen.

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

Und um es zu benutzen:

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