2013-04-15 137 views
13

我嘗試從Visual Studio * .csproj文件中查詢元素。我創建了一個簡短的例子來說明問題:使用xmlns屬性查詢XDocument屬性(名稱空間)

// Working 
    string xml1 = @"<Project ToolsVersion='4.0'> 
         <ItemGroup Label='Usings'> 
         <Reference Include='System' /> 
         <Reference Include='System.Xml' /> 
         </ItemGroup> 
        </Project>"; 
    // Not working 
    string xml2 = @"<Project ToolsVersion='4.0' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'> 
         <ItemGroup Label='Usings'> 
         <Reference Include='System' /> 
         <Reference Include='System.Xml' /> 
         </ItemGroup> 
        </Project>"; 

    XDocument doc = XDocument.Parse(xml2); 

    foreach (XElement element in doc.Descendants("ItemGroup")) 
    { 
     Console.WriteLine(element); 
    } 

字符串xml1工作正常,xml2不返回任何內容。這些字符串之間的唯一區別是文檔根目錄中的xmlns屬性。

如何查詢包含xmlns屬性的文檔? 爲什麼xml文檔包含xmlns屬性時會出現問題?

回答

16

爲什麼當xml文檔包含xmlns屬性時會出現問題?

這不,如果你明白是什麼意思:)基本上你已經應用的「http://schemas.microsoft.com/developer/msbuild/2003」一默認命名空間URI所有元素。因此,在查詢時,您還需要指定該名稱空間。幸運的是,LINQ to XML使其非常簡單:

XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003"; 
XDocument doc = XDocument.Parse(xml2); 
foreach (XElement element in doc.Descendants(ns + "ItemGroup")) 
{ 
    Console.WriteLine(element); 
} 
+1

另一種語法:'doc.Descendants(「{http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup」)' – ziya

+1

對不起,我不明白爲什麼我們必須明確寫入命名空間,如果它這個文件的默認值是? XElement/XDocument本身沒有解決這個問題的原因是什麼? –

+0

@FelixKeil:因爲當你調用'Element'或者'Descendants'時,你指定了一個'XName',它是完全限定的......並且完全限定的名字包含了命名空間。我有點看到你的觀點,但我認爲它的完成方式是有道理的,而LINQ to XML中的名稱空間支持是我見過的任何XML API中最好的。 –

3

事先不需要知道名稱空間。 您可以編寫代碼,可以使用兩個Xmls,因爲您可以從XElement獲取默認名稱空間。

XDocument doc = XDocument.Parse(xml2); 
XNamespace ns = doc.Root.GetDefaultNamespace(); 
foreach (XElement element in doc.Descendants(ns + "ItemGroup")) 
{ 
    Console.WriteLine(element); 
} 

我還寫了一個擴展方法來解析來自任何XObject(XElement,XDocument等)的XName。

使用擴展方法而不是GetDefaultNamespace的好處是您不必檢查是否已經提供了另一個名稱空間。

public static XName ResolveName(this XObject xObj, XName name) 
{ 
    //If no namespace has been added, use default namespace anyway 
    if (string.IsNullOrEmpty(name.NamespaceName)) 
    { 
     name = xObj.Document.Root.GetDefaultNamespace() + name.LocalName; 
    } 
    return name; 
} 

您可以使用它像這樣

XDocument doc = XDocument.Parse(xml2); 
foreach (XElement element in doc.Descendants(doc.ResolveName("ItemGroup"))) 
{ 
    Console.WriteLine(element); 
} 

我認爲LINQ到XML是一個美妙的API。但我認爲很明顯,如果我不提供名稱空間,那我總是指默認名稱空間。我看不出任何爲什麼LINQ to XML不這樣做的原因。這是一個讓我非常惱火的小缺點。作爲LINQ to XML的初學者,我第一次在忘記提供默認命名空間的時候不知道自己做錯了幾個小時。

+0

太好了,謝謝分享! – Joel