web-dev-qa-db-ja.com

名前空間を持つXPath選択ノード

その.vbprojとこのように見えます

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

取得したいのはProjectGuidだけですが、名前空間がある場合は機能しません...

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

これを修正するにはどうすればよいですか?

64
Peter

このようなこと(IMHO)を行う最良の方法は、名前空間マネージャーを作成することです。これは、SelectNodesを呼び出して、どのネームスペースURLがどのプレフィックスに接続されているかを示すために使用できます。通常、次のような適切なインスタンスを返す静的プロパティを設定します(C#です。翻訳する必要があります)。

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

ここには名前空間を1つだけ含めていますが、複数の名前空間を含めることもできます。次に、次のようなドキュメントから選択できます。

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

すべての要素が指定された名前空間にあることに注意してください。

44
Teun D

私はおそらく一緒に行きたいと思うでしょう バーテック*名前空間ソリューション。ただし、一般的なxpathソリューションは次のとおりです。

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

** Bartekの答えが消えたので、Teunの方をお勧めします(実際にはより徹底的です)

63
annakata

この問題はここにありました 既に

名前空間に依存しないXPath式を使用するか(その不器用さと誤検知の可能性があるためお勧めしません-<msb:ProjectGuid>および<foo:ProjectGuid>はこの式でも同じです):

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

または、正しいことをしてXmlNamespaceManagerを使用して名前空間URIを登録し、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
Tomalak

クエリを機能させるには、このXML名前空間を登録し、プレフィックスに関連付けるだけです。ノードを選択するときに、2番目のパラメーターとして名前空間マネージャーを作成して渡します。

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

1つの方法は、拡張機能+ NameSpaceManagerを使用することです。
コードはVBにありますが、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

そしてそれを使用するには:

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