它是一个 .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")
我能做些什么来解决这个问题?
我可能倾向于使用 Bartek 的 * 命名空间解决方案,但一般的 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)
请注意,所有元素都在指定的命名空间中。
此问题已出现在这里 several times already。
您可以使用与命名空间无关的 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)
您只需注册此 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)
不定期副业成功案例分享