Introduzione a LINQ to XML

di , in LINQ,


Questo articolo è tratto dal capitolo 13 (XML e LINQ To XML) del libro ASP.NET 3.5 per tutti di Daniele Bochicchio, Cristian Civera, Riccardo Golia e Stefano Mostarda.

Acquista subito la tua copia ad un prezzo vantaggioso!

LINQ to XML

L'intenzione di LINQ, presente nel .NET Framework 3.5, è quella di fornire un unico modo di interrogare i dati, così da permettere allo sviluppatore di muoversi agilmente con diverse sorgenti tra cui anche documenti XML. A questo scopo è stato aggiungo un nuovo assembly System.Xml.Linq, che contiene nuove classi, racchiuse sotto il nome di LINQ to XML. Queste classi sono in grado di decodificare l'XML, consentendo facilmente di interrogare il documento mediante la query syntax e le estensioni di LINQ to Object.

Architettura delle classi di LINQ to XML

Il documento mostrato nell'esempio successivo è utilizzato all'interno di tutto questo articolo come sorgente.

<?xml version="1.0" encoding="utf-8" ?>
<products xmlns="http://schemas.aspitalia.com/book35/products">
  <!-- Lista prodotti -->
  <product idProduct="1" idCategory="1">
    <description>Prodotto 1</description>
    <details xmlns="http://schemas.aspitalia.com/book35/details">
      <detail name="Size" value="10x20" />
      <detail name="Weight" value="2" />
    </details>
  </product>
  <product idProduct="2" idCategory="3">
    <description>Prodotto 2</description>
    <details xmlns="http://schemas.aspitalia.com/book35/details">
      <detail name="Size" value="40x35" />
      <detail name="Weight" value="8" />
    </details>
  </product>
  <product idProduct="3" idCategory="1">
    <description>Prodotto 31</description>
    <details xmlns="http://schemas.aspitalia.com/book35/details">
      <detail name="Size" value="10x25" />
      <detail name="Weight" value="2" />
    </details>
  </product>
</products>

La classe principale è XDocument, che con i metodi Load, Parse e Save permette di caricare, decodificare una stringa o salvare un documento XML. Da esso tramite la proprietà Root si ha accesso all'XElement radice sul quale è possibile invocare una serie di metodi per ottenere uno specifico elemento figlio o un attributo (classe XAttribute). L'esempio seguente mostra un semplice esempio per la lettura dell'attributo idProduct sul primo tag product. Da notare come gli oggetti XElement e XAttribute dispongano di operatori di conversione espliciti ed è quindi possibile effettuare il cast sul tipo desiderato.

// Caricamento del documento
XDocument doc = XDocument.Load(Request.MapPath("test.xml"));
// Recupera l'elemento product
XElement product = 
  doc.Root.Element("{http://schemas.aspitalia.com/book35/products}product");
// Lettura attributo idProduct
int idProduct = (int)product.Attribute("idProduct");

Nel codice precedente sicuramente colpisce la particolare sintassi "{namespace}localName", utilizzata per qualificare correttamente l'elemento. In realtà il metodo Element accetta un tipo XName, che unisce il namespace al localName, ma grazie ad un operatore di conversione implicito è possibile utilizzare direttamente una stringa con la sintassi speciale vista nell'esempio precedente. In alternativa si possono usare il metodo statico XName.Get o la classe XNamespace, per riutilizzare il namespace concatenandolo con il localName una o più volte.

XNamespace productNs = "http://schemas.aspitalia.com/book35/products";
XElement product = doc.Root.Element(productNs + "product");

Quanto visto finora non basta comunque a giustificare la creazione di nuove API. Infatti da esse se ne trae il massimo con una serie di metodi come Nodes, Elements, Attributes o Descendants, che restituiscono un IEnumerable o tipi da esso derivati.

Questi enumerabili sono una manna per LINQ to Object e per alcuni extension method della classe System.Xml.Linq.Extensions che permettono a loro volta di ottenere nodi, attributi e elementi discendenti oppure ascendenti.

L'esempio successivo mostra all'opera alcuni di questi metodi e come si possono combinare con alcune estensioni della classe Enumerable, applicandoli al documento XML d'esempio, per effettuare la somma o ottenere il primo nodo.

// Tutti gli attributi idProduct degli elementi product 
foreach (XAttribute attribute in
  doc.Root.Elements().Attributes("idProduct"))
    WriteLine("idProduct {0}", (string)attribute);

// Il primo nodo (commento)
WriteLine("Comment: {0}", doc.Root.Nodes().First());

// Il primo elemento product
XElement product = doc.Root.Elements(
  productNs + "product").ElementAt(1);
WriteLine("Description: {0}", 
  (string)product.Element(productNs + "description"));

// Somma dell'attributo value per tutti i
// detail di tipo Weight
int sum = (from d in doc.Root.Descendants(dns + "detail")
          where (string)d.Attribute("name") == "Weight"
          select (int)d.Attribute("value")).Sum();
WriteLine("Total weight: {0}", sum);

Il risultato dell'esempio è visibile nella figura seguente.

Risultato del codice

3 pagine in totale: 1 2 3
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

Introduzione a LINQ to XML 1010 1
| Condividi su: Twitter, Facebook, LinkedIn, Google+

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti