LINQ: da xml a classi C#

Proseguo la mia serie di articoli dedicati alla programmazione con C# e LINQ.

Nel mio precedente mio post ho presentato un semplice metodo per serializzare una classe C# con LINQ.

Oggi voglio descrivere l’altra faccia della medaglia: partendo da un file XML vedremo come sia possibile popolare le corrispondenti classi C#.

Partiamo dunque con il nostro esempio.

Supponiamo di avere un file xml che contiene l’elenco dei comuni italiani con il loro prefisso telefonico.

Vogliamo caricare questo file in una lista di oggetti C# con i quali sia più comodo lavorare all’interno della nostra applicazione.

Definiamo quindi il file Comuni.xml nel seguente modo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<comuni>
  <comune>
    <prefisso>045</prefisso>
    <descrizione>Verona</descrizione>
  </comune>
  <comune>
    <prefisso>02</prefisso>
    <descrizione>Milano</descrizione>
  </comune>
  <comune>
    <prefisso>06</prefisso>
    <descrizione>Roma</descrizione>
  </comune>
  <comune>
    <prefisso>011</prefisso>
    <descrizione>Torino</descrizione>
  </comune>
  <comune>
    <prefisso>055</prefisso>
    <descrizione>Firenze</descrizione>
  </comune>
...
</comuni>

Partendo da questo xml definiamo nel nostro progetto una classe Comune che andremo poi a popolare con i dati del singolo comune.

In caso di strutture XML più complesse si possono utilizzare dei tool di generazione di classi per ottenere le classi direttamente dall’xml, ma nel nostro caso definiamo la classe a mano vista la sua semplicità.

1
2
3
4
5
public class Comune
{
  public String prefisso { get; set; }
  public String descrizione { get; set; }
}

A questo punto siamo pronti: possiamo sfruttare la potenza di LINQ e popolare una lista di comuni con un’unica query.

Di seguito il metodo popolaComuni che serve al nostro scopo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static List popolaComuni(string xmlFilePath)
{
  List lstComuni = new List();

  var com = from p in  XElement.Load(xmlFilePath).Elements("comuni")
                                 .Elements("comune")
                       orderby (string)p.Element("descrizione") ascending
                       select new Comune
                       {
                          prefisso = (string)p.Element("prefisso"),
                          descrizione = (string)p.Element("descrizione")
                       };

  foreach (var c in com)
    lstComuni.Add(c);

  return lstComuni;
}

Il punto chiave della query è l’accesso in cascata ai nodi del file xml tramite l’istruzione:

1
2
3
4
5
6
7
8
9
XElement.Load(nomeFileXml).Elements("comuni").Elements("comune")
</pre>
E' poi interessante notare come LINQ ci permetta di popolare una classe direttamente con i risultati della query.
<code lang="CSharp">..
 select new Comune
  {
    prefisso = (string)p.Element("prefisso"),
    descrizione = (string)p.Element("descrizione")
  };

Questo è forse l’aspetto più interessante in quanto, definendo una sola volta la new del nostro oggetto all’interno della query, otteniamo direttamente una lista di oggetti all’interno della nostra variabile com.

Potremmo utilizzare direttamente questa variabile nel nostro codice, ma per comodità carichiamo il tutto in una List con il ciclo for finale.

Oltre alla semplicità, c’è da dire che questo approccio con LINQ è anche molto più veloce in fase di esecuzione rispetto alla lettura di un file xml scorrendo i nodi come oggetti XmlNode. Un vantaggio notevole quando si trattano file di grandi dimensioni.