2013-04-15 12 views
13

Provo a interrogare gli elementi da un file * .csproj di Visual Studio. Ho creato un breve esempio per illustrare il problema:Query XDocument con attributo xmlns (spazio dei nomi)

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

Il xml1 stringa funziona bene, xml2 non restituisce nulla. L'unica differenza tra queste stringhe è l'attributo xmlns nella root del documento.

Come faccio a interrogare documenti contenenti attributi xmlns? Perché è un problema quando un documento xml contiene un attributo xmlns?

risposta

16

Perché è un problema quando un documento xml contiene un attributo xmlns?

Non è, se si capisce che cosa significa :) In sostanza è stato applicato un predefinita URI del namespace "http://schemas.microsoft.com/developer/msbuild/2003" a tutti gli elementi. Pertanto, quando si esegue una query, è necessario specificare anche tale spazio dei nomi. Fortunatamente, LINQ to XML rende che in realtà semplice:

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

Un'altra sintassi: 'doc.Descendants (" {http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup ")' – ziya

+1

Spiacente, non capisco perché dobbiamo scrivere esplicitamente lo spazio dei nomi se è il DEFAULT per questo documento? Qual è la ragione per cui questo non è stato risolto implicitamente da XElement/XDocument? –

+0

@FelixKeil: Perché quando chiami 'Elemento' o' Discendenti' stai specificando un 'XName', che è pienamente qualificato ... e il nome completo include lo spazio dei nomi. Vedo il tuo punto di vista, ma penso che abbia senso nel modo in cui è stato fatto, e il supporto per lo spazio dei nomi in LINQ to XML è la più bella tra tutte le API XML che ho visto. –

3

Non è necessario conoscere lo spazio dei nomi in anticipo. È possibile scrivere codice, che funziona con entrambi gli XML perché è possibile ottenere lo spazio dei nomi predefinito da XElement.

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

ho anche scritto un metodo di estensione per risolvere il XName da qualsiasi XObject (XElement, XDocument, etc.).

Il vantaggio nell'utilizzo del metodo di estensione anziché GetDefaultNamespace è che non è necessario verificare se è già disponibile un altro spazio dei nomi.

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

Si può usare in questo modo

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

Credo che LINQ to XML è un meraviglioso API. Ma penso sia chiaro, che se non fornisco uno spazio dei nomi, intendo sempre lo spazio dei nomi predefinito. Non vedo alcun motivo per cui LINQ to XML non si comporta in questo modo. Questo è un piccolo inconveniente che mi ha davvero infastidito. E la prima volta come un principiante con LINQ to XML non sapevo cosa ho sbagliato per ore quando ho dimenticato di fornire lo spazio dei nomi predefinito.

+0

Grande, grazie per la condivisione! – Joel

Problemi correlati