2009-02-11 184 views
62

它是一種.vbproj和XPath選擇節點看起來像這樣命名空間

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

我能做些什麼來解決這個問題?

+1

兩個問題:

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 

,並使用它1.它是醜陋的,在這種情況下,它可以使用,但如果是「ProjectGuid」元素將提供錯誤的結果屬於多個命名空間,我們只需要來自單個命名空間的元素。使用NamespaceManager的解決方案更好 – 2009-02-11 14:36:58

+0

必須爲XPath引擎提供正確的靜態上下文,該靜態上下文包含前綴和NS URI之間的綁定,以便在計算表達式時使用,否則將無法引用名稱空間內的內容。這就是@Teun所做的。 – lkuty 2013-10-17 15:35:51

回答

43

做這樣的事情(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; 
    } 
} 

我只包括一個命名空間在這裏,但你可以有多個。然後你可以選擇這樣的文件:

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

請注意,所有的元素都在指定的命名空間。

-7

爲什麼不使用//忽略命名空間:

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

//作爲外卡通過指定(即ProjectGuid)的根和下一個節點名稱

+7

實際上並沒有工作 - 是的,這表示尋找任何ProjectGuids任何地方,但它仍然希望他們在默認命名空間 – annakata 2009-02-11 12:11:54

63

我之間的一切都遵循倒是可能會傾向於去 鮑爾泰克的 *命名空間的解決方案,但一般的XPath的解決方案是:

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

**由於Bartek的答案已經消失,我推薦Teun's(實際上更徹底)*

+0

同意,雖然這成爲一個真正的PITA,當你不得不深入幾個級別。不過,它*可以工作。 :) – ZombieSheep 2009-02-11 12:08:36

27

這個問題一直在這裏severaltimesalready

要麼你與命名空間無關的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) 
3

你只需要註冊這個XML命名空間和associ吃了一個前綴,使查詢工作。選擇節點時 創建並傳遞一個命名空間管理器作爲第二個參數:

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

的一種方法是使用擴展+ NameSpaceManager。
代碼在VB中,但很容易轉換爲C#。與annakata的解決方案

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

......