Pergunta

É um .vbproj e se parece com isso

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

Tudo que eu quero começar é o ProjectGuid mas ele não funciona quando um namespace está lá ...

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

O que posso fazer para corrigir isso?

Foi útil?

Solução

A melhor maneira de fazer coisas como esta (IMHO) é criar um gerenciador de namespace. Isso pode ser usado chamando SelectNodes para indicar quais URLs de namespace estão conectados a quais prefixos. I normalmente configurar uma propriedade estática que retorna uma instância adequada como este (de C #, você tem que traduzir):

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

I incluem apenas um namespace aqui, mas você pode ter múltiplo. Em seguida, você pode selecionar o documento como este:

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

Note-se que todos os elementos estão no namespace especificado.

Outras dicas

Eu provavelmente estaria inclinado a ir com * A solução da Bartek namespace, mas uma solução geral XPath é:

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

** desde a resposta de Bartek desapareceu, eu recomendo do Teun (que na verdade é mais completa) *

Este problema tem sido aqui href="https://stackoverflow.com/questions/11345/xpaths-and-default-namespaces"> vezes .

Ou você trabalhar com expressões XPath namespace agnóstica (não recomendado para a sua falta de jeito e o potencial para jogos falsos positivos - <msb:ProjectGuid> e <foo:ProjectGuid> são os mesmos para esta expressão):

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

ou você fazer a coisa certa e usar um XmlNamespaceManager para registrar o namespace URI para que possa incluir um prefixo namespace em sua 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)

Você precisa apenas de registar este namespaces XML e associado com um prefixo, para fazer o trabalho de consulta. Criar e passar por um gerente de namespace como segundo parâmetro ao selecionar os nós:

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)

Uma maneira é usar extensões + NamespaceManager.
Código está em VB, mas é realmente fácil de traduzir para 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

E para usá-lo:

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

......

Por que não usar o // para ignorar o namespace:

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

// age como wild card para seguir com tudo entre a raiz eo próximo nome do nó especificado (ou seja ProjectGuid)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top