Modifica dell'albero XML in memoria e costruzione funzionale (LINQ to XML)

La modifica di un albero XML sul posto è un approccio tradizionale per cambiare la forma di un documento XML. Una tipica applicazione carica un documento in un archivio dati quale DOM o LINQ to XML, usa un'interfaccia di programmazione per inserire o eliminare nodi o modificarne il contenuto e quindi salva il codice XML in un file o lo trasmette tramite una rete.

LINQ to XML consente di adottare un altro approccio che risulta utile in molti scenari: la costruzione funzionale. Nella costruzione funzionale la modifica di dati viene considerata come un problema di trasformazione, anziché come una modifica dettagliata di un archivio dati. Se è possibile trasformare in modo efficiente una rappresentazione di dati da un formato a un altro, il risultato è identico a quello ottenuto modificando un archivio dati in modo da cambiarne la forma. Un aspetto importante dell'approccio della costruzione funzionale riguarda il passaggio dei risultati delle query ai costruttori XDocument e XElement.

In molti casi, è possibile scrivere il codice di trasformazione in tempi ridotti rispetto a quelli richiesti per la modifica dell'archivio dati. Il codice risultante è inoltre più affidabile e facile da gestire. In questi casi, anche se l'approccio della trasformazione può richiedere una maggiore potenza di elaborazione, si tratta di una soluzione più efficace per la modifica dei dati. Se uno sviluppatore ha familiarità con l'approccio funzionale, il codice risultante è in molti casi più facile da comprendere ed è facile trovare il codice che modifica ogni parte dell'albero.

Molti programmatori DOM hanno una maggiore dimestichezza con l'approccio in cui un albero XML viene modificato sul posto, mentre il codice scritto con l'approccio funzionale potrebbe sembrare insolito agli sviluppatori che non hanno ancora compreso tale approccio. Se è necessario apportare solo una piccola modifica a un albero XML di grandi dimensioni, l'approccio in cui un albero viene modificato sul posto richiederà in molti casi meno tempo CPU.

Questo articolo fornisce esempi di entrambi gli approcci. Si supponga di voler modificare il semplice documento XML seguente in modo che gli attributi diventino elementi:

<?xml version="1.0" encoding="utf-8" ?>
<Root Data1="123" Data2="456">
  <Child1>Content</Child1>
</Root>

Il primo degli esempi seguenti usa l'approccio tradizionale di modifica sul posto e il secondo usa l'approccio di costruzione funzionale.

Esempio: Trasformare gli attributi in elementi con l'approccio sul posto tradizionale

È possibile scrivere codice procedurale per creare elementi dagli attributi e quindi eliminare gli attributi, come segue:

XElement root = XElement.Load("Data.xml");
foreach (XAttribute att in root.Attributes()) {
    root.Add(new XElement(att.Name, (string)att));
}
root.Attributes().Remove();
Console.WriteLine(root);
Dim root As XElement = XElement.Load("Data.xml")
For Each att As XAttribute In root.Attributes()
    root.Add(New XElement(att.Name, att.Value))
Next
root.Attributes().Remove()
Console.WriteLine(root)

Nell'esempio viene prodotto l'output seguente:

<Root>
  <Child1>Content</Child1>
  <Data1>123</Data1>
  <Data2>456</Data2>
</Root>

Esempio: Trasformare gli attributi in elementi con l'approccio di costruzione funzionale

Al contrario, un approccio funzionale è costituito da codice per creare un nuovo albero, selezionando gli elementi e gli attributi dall'albero di origine e trasformandoli nel modo appropriato prima di aggiungerli nel nuovo albero.

XElement root = XElement.Load("Data.xml");
XElement newTree = new XElement("Root",
    root.Element("Child1"),
    from att in root.Attributes()
    select new XElement(att.Name, (string)att)
);
Console.WriteLine(newTree);
Dim root As XElement = XElement.Load("Data.xml")
Dim newTree As XElement = _
    <Root>
        <%= root.<Child1> %>
        <%= From att In root.Attributes() _
            Select New XElement(att.Name, att.Value) %>
    </Root>
Console.WriteLine(newTree)

In questo esempio viene restituito stesso lo stesso output XML del primo esempio. Si noti, tuttavia, che è possibile visualizzare la struttura risultante del nuovo codice XML nell'approccio funzionale. È quindi possibile vedere la creazione dell'elemento Root, il codice che effettua il pull dell'elemento Child1 dall'albero di origine e il codice che trasforma gli attributi dell'albero di origine in elementi nel nuovo albero.

L'esempio funzionale in questo caso non è né più breve né più semplice del primo esempio. Se tuttavia è necessario apportare molte modifiche a un albero XML, l'approccio procedurale diventerà alquanto complesso e poco flessibile. Al contrario, quando si usa l'approccio funzionale, viene comunque creato l'XML desiderato, incorporando query ed espressioni nel modo appropriato, per inserire il contenuto desiderato. L'approccio funzionale restituisce codice più facile gestire.

Si noti che in questo caso le prestazioni dell'approccio funzionale potrebbero non essere uguali a quelle dell'approccio della modifica dell'albero. Il problema principale è che l'approccio funzionale crea più oggetti temporanei. Tuttavia, il problema è controbilanciato dalla maggiore produttività dei programmatori resa possibile da tale approccio.

Questo esempio è molto semplice, ma serve a illustrare le differenze concettuali tra i due approcci. L'approccio funzionale offre un aumento della produttività per la trasformazione di documenti XML di grandi dimensioni.