sourcecode

XPath 네임스페이스가 있는 노드 선택

codebag 2023. 7. 7. 19:01
반응형

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

이걸 고치려면 어떻게 해야 하나요?

저는 아마 당신과 함께 가고 싶어할 것입니다. 바텍의 네임스페이스 솔루션이지만 일반적인 xpath 솔루션은 다음과 같습니다.

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

**Bartek의 답변이 사라졌기 때문에 Teun의 답변을 추천합니다(실제로 더 철저한)*

이와 같은 작업을 수행하는 가장 좋은 방법은 네임스페이스 관리자를 만드는 것입니다.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;
  }
}

여기에는 네임스페이스가 하나만 포함되지만 여러 개일 수 있습니다.그런 다음 다음 문서에서 다음과 같이 선택할 수 있습니다.

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

모든 요소가 지정된 네임스페이스에 있습니다.

이 문제는 이미 여러 번 발생했습니다.

네임스페이스에 구애받지 않는 XPath 표현식을 사용할 수 있습니다(어설프고 잘못된 긍정 일치 가능성 때문에 권장되지 않습니다).<msb:ProjectGuid>그리고.<foo:ProjectGuid>이 식에 대해서는 동일합니다):

//*[local-name(로컬 이름) = 'ProjectGuid')]

아니면 당신은 옳은 일을 하고 사용합니다.XmlNamespaceManagerXPath에 네임스페이스 접두사를 포함할 수 있도록 네임스페이스 URI를 등록하려면 다음과 같이 하십시오.

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)

쿼리가 작동하려면 이 XML 네임스페이스를 등록하고 접두사와 연결하기만 하면 됩니다.노드를 선택할 때 네임스페이스 관리자를 만들고 두 번째 매개 변수로 전달합니다.

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)

한 가지 방법은 확장자 + 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")

......

//를 사용하여 네임스페이스를 무시하는 것은 어떻습니까?

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

루트와 지정된 다음 노드 이름(예: ProjectGuid) 사이의 모든 항목을 추적하는 와일드카드 역할을 합니다.

언급URL : https://stackoverflow.com/questions/536441/xpath-select-node-with-namespace

반응형