2013-04-15 13 views
13

Ich versuche, Elemente aus einem Visual Studio *. Csproj-Datei abzufragen. Ich habe ein kurzes Beispiel, das Problem zu veranschaulichen:Abfrage XDocument mit Xmlns Attribut (Namespace)

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

Der String xml1 funktioniert gut, xml2 nichts zurückliefert. Der einzige Unterschied zwischen diesen Zeichenfolgen ist das xmlns-Attribut im Dokumentstammverzeichnis.

Wie kann ich Dokumente abfragen, die xmlns-Attribute enthalten? Warum ist es ein Problem, wenn ein XML-Dokument ein Xmlns-Attribut enthält?

Antwort

16

Warum ist es ein Problem, wenn ein XML-Dokument ein Xmlns-Attribut enthält?

Es ist nicht, wenn Sie verstehen, was es bedeutet :) Grundsätzlich Sie eine Standard NamespaceURI von „http://schemas.microsoft.com/developer/msbuild/2003“ auf alle Elemente angewendet haben. Bei der Abfrage müssen Sie also auch diesen Namespace angeben. Glücklicherweise macht LINQ to XML das wirklich einfach:

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

Eine andere Syntax: 'doc.Descendants (" {http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup ")' – ziya

+1

Sorry ich verstehe nicht, warum wir den Namespace explizit schreiben müssen, wenn es ist die DEFAULT für dieses Dokument? Was ist der Grund, dass dies nicht durch XElement/XDocument selbst implizit gelöst wird? –

+0

@FelixKeil: Wenn Sie 'Element' oder' Descendants' aufrufen, geben Sie einen 'XName' an, der vollständig qualifiziert ist ... und der vollständig qualifizierte Name enthält den Namespace. Ich verstehe Ihren Standpunkt, aber ich denke, es macht Sinn, wie es gemacht wird, und die Namespace-Unterstützung in LINQ to XML ist die beste XML-API, die ich je gesehen habe. –

3

Es ist nicht notwendig, den Namespace vorher zu kennen. Sie können Code schreiben, der mit beiden Xmls funktioniert, weil Sie den Standard-Namespace von XElement beziehen können.

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

Ich schrieb auch eine Erweiterungsmethode die XName von jedem XObject (XElement, XDocument, etc.) zu lösen.

Der Vorteil bei der Verwendung der Erweiterungsmethode anstelle von GetDefaultNamespace besteht darin, dass Sie nicht überprüfen müssen, ob bereits ein anderer Namespace verfügbar ist.

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

Sie können es verwenden, wie diese

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

ich LINQ to XML denken, ist eine wunderbare API. Aber ich denke, es ist klar, dass ich, wenn ich keinen Namespace anbiete, immer den Standard-Namespace bedeute. Ich sehe keinen Grund, warum sich LINQ to XML nicht so verhält. Das ist ein kleiner Nachteil, der mich wirklich genervt hat. Und das erste Mal als Anfänger mit LINQ to XML wusste ich nicht, was ich stundenlang falsch gemacht habe, als ich vergessen habe, den Standard-Namespace bereitzustellen.

+0

Großartig, danke fürs Teilen! – Joel

Verwandte Themen