Semplifica l'elaborazione XML con VTD-XML

Figura 3. File XML di grandi dimensioni. Fare clic sulla miniatura per visualizzare l'immagine a grandezza naturale.

A otto anni dalla sua nascita, XML è già decollato come formato di dati aperto e semi-strutturato per l'archiviazione e lo scambio di dati sul Web. Grazie alla sua semplicità e leggibilità umana, XML ha visto la sua popolarità salire alle stelle tra gli sviluppatori di applicazioni ed è diventato una parte indispensabile dell'architettura aziendale.

Sebbene sia difficile enumerare il numero di modi in cui XML viene utilizzato, si può essere certi di una cosa: XML deve essere analizzato prima di poter fare qualsiasi altra cosa. In effetti, la scelta del parser giusto è spesso una delle prime decisioni che gli sviluppatori aziendali devono prendere nei loro progetti. E ancora e ancora, questa decisione si riduce ai due popolari modelli di elaborazione XML: Document Object Model (DOM) e Simple API for XML (SAX).

A prima vista, i rispettivi punti di forza e di debolezza di DOM e SAX sembrano complementari: DOM costruisce grafici di oggetti in memoria; SAX è basato sugli eventi e non memorizza nulla. Quindi, se la dimensione del documento è piccola e il modello di accesso ai dati complesso, DOM è la strada da percorrere; altrimenti, usa SAX.

Tuttavia, la verità non è mai così semplicistica. Il più delle volte, gli sviluppatori non sono disposti a utilizzare SAX a causa della sua complessità, ma lo fanno ancora perché non è disponibile altra scelta praticabile. Altrimenti, se la dimensione del file XML è solo leggermente superiore a poche centinaia di kilobyte, l'overhead di memoria di DOM e il trascinamento delle prestazioni diventano un ostacolo difficile per gli sviluppatori di applicazioni, impedendo loro di raggiungere gli obiettivi di prestazioni minimi dei loro progetti.

Ma SAX è davvero molto meglio? Le prestazioni di analisi pubblicizzate da SAX, in genere molte volte più veloci di DOM, in realtà spesso ingannano. Risulta che la natura scomoda e diretta dell'analisi SAX non solo richiede uno sforzo aggiuntivo di implementazione, ma incorre anche in penalizzazioni delle prestazioni quando la struttura del documento diventa solo leggermente complessa. Se gli sviluppatori scelgono di non scansionare il documento più volte, dovranno memorizzare il documento nel buffer o creare modelli di oggetti personalizzati.

In ogni caso, le prestazioni ne risentono, come esemplificato da Apache Axis. Nella sua pagina delle domande frequenti, Axis afferma di utilizzare internamente SAX per creare un'implementazione più performante, ma costruisce ancora il proprio modello a oggetti che è abbastanza simile a DOM, con conseguenti miglioramenti delle prestazioni trascurabili rispetto al suo predecessore (Apache SOAP). Inoltre, SAX non funziona bene con XPath e in generale non può guidare l'elaborazione XSLT (Extensible Stylesheet Language Transformation). Quindi l'analisi SAX aggira i problemi reali dell'elaborazione XML.

Alla ricerca di un'alternativa più facile da usare a SAX, un numero crescente di sviluppatori si è rivolto a StAX (Streaming API for XML). Rispetto a SAX, i parser StAX estraggono i token dai file XML invece di utilizzare i call back. Sebbene migliorino notevolmente l'usabilità, i problemi fondamentali persistono: lo stile di analisi forward-only di StAX richiede ancora noiosi sforzi di implementazione e, insieme ad esso, costi di prestazioni nascosti.

In conclusione: affinché qualsiasi modello di elaborazione XML sia ampiamente utile, deve presentare la struttura gerarchica di XML e niente di meno. Il motivo è perché XML è progettato per spostare dati complessi sul Web e trasmettere le informazioni strutturali è una parte intrinseca di ciò che fa XML.

VTD-XML cambia il gioco

Supponiamo di dover avviare l'elaborazione XML da zero per superare i suddetti problemi con DOM e SAX. Il nuovo modello dovrebbe probabilmente avere le seguenti proprietà:

  • Possibilità di accesso casuale: il modello di elaborazione dovrebbe consentire allo sviluppatore di navigare in una sorta di struttura gerarchica manualmente o, meglio, utilizzando XPath.
  • Prestazioni elevate: le prestazioni dovrebbero essere sostanzialmente migliori di DOM e SAX. E la performance dovrebbe essere "onesta", il che significa che la misurazione deve includere il tempo impiegato per costruire la struttura gerarchica.
  • Utilizzo ridotto della memoria: per rendere il modello di elaborazione applicabile a un'ampia gamma di scenari e dimensioni di file, deve presentare la struttura completa di XML con una quantità minima di utilizzo della memoria.

Progettato per soddisfare questi obiettivi, VTD-XML è il modello di elaborazione XML open source di nuova generazione che apporta miglioramenti fondamentali e globali su DOM e SAX. Una delle principali ottimizzazioni di VTD-XML è la tokenizzazione non estrattiva. Internamente, VTD-XML conserva in memoria messaggio XML intatto e non decodificata, e rappresenta gettoni basati esclusivamente su una specifica codifica binaria chiamato V irtual T oken D escriptor. Un record VTD è un numero intero a 64 bit che codifica la lunghezza del token, l'offset iniziale, il tipo e la profondità di nidificazione di un token in XML.

Ecco un po 'della storia di VTD-XML nel caso foste interessati: Il concetto di base è stato concepito come un modo per portare l'elaborazione XML su hardware dedicato, sotto forma di FPGA o ASIC, per abilitare switch di rete e router per elaborare XML contenuto a velocità molto elevate. Successivamente, il team del progetto VTD-XML ha deciso di rendere open source VTD-XML e il rilascio iniziale, della versione 0.5 e implementato in Java, è avvenuto nel maggio 2004. Da quel rilascio, VTD-XML ha subito diversi round di miglioramenti ed è maturato considerevolmente. Nella versione 0.8, la versione C di VTD-XML è stata rilasciata insieme alla versione Java. Il supporto XPath integrato è stato introdotto nella versione 1.0 e rilasciato nell'ottobre 2005. L'ultima versione, la versione 1.5, presenta un motore di analisi riscritto che è più modulare e con prestazioni più elevate.

In questa versione è stata inoltre introdotta una funzionalità chiamata riutilizzo del buffer. L'idea di base è che quando un'applicazione XML che si trova dietro una connessione di rete deve elaborare ripetutamente molti documenti XML in entrata, l'applicazione può effettivamente riutilizzare i buffer di memoria allocati durante la prima esecuzione di elaborazione. In altre parole, alloca i buffer una volta e usali molte, molte volte. Specifico per VTD-XML, questa caratteristica consente l'eliminazione completa sia della creazione di oggetti che dei costi di garbage collection (50-80% del sovraccarico in DOM e SAX) dall'elaborazione XML. Il sito web del progetto contiene gli ultimi download del software e una descrizione tecnica approfondita di VTD-XML.

Un rapido esempio

Per dare un'idea dello stile di programmazione di VTD-XML, questo articolo confronta innanzitutto il codice utilizzando sia VTD-XML che DOM per analizzare e navigare in un semplice file XML denominato test.xml, il cui contenuto di testo è mostrato di seguito:

  Lawnmower 1 148.95  

La versione VTD-XML ha questo aspetto:

import com.ximpleware.*; import com.ximpleware.parser.*; import java.io.*;

public class use_vtd { public static void main(String[] args){ try{ File f = new File("test.xml"); FileInputStream fis = new FileInputStream(f); byte[] ba = new byte[(int)f.length()]; fis.read(ba); VTDGen vg = new VTDGen(); vg.setDoc(ba); vg.parse(false); VTDNav vn = vg.getNav(); if (vn.matchElement("purchaseOrder")){ System.out.println(" orderDate==>" + vn.toString(vn.getAttrVal("orderDate"))); if (vn.toElement(VTDNav.FIRST_CHILD,"item")){ if (vn.toElement(VTDNav.FIRST_CHILD)){ do { System.out.print( vn.toString(vn.getCurrentIndex())); System.out.print("==>");

System.out.println( vn.toString(vn.getText())); } while(vn.toElement(VTDNav.NEXT_SIBLING)); } } } } catch (Exception e){ System.out.println("exception occurred ==>"+e); } } }

La versione DOM della stessa applicazione è mostrata di seguito:

import java.io.*; import org.w3c.dom.*; import org.w3c.*; import javax.xml.parsers.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.*; import org.xml.sax.SAXException;

public class use_dom { public static void main(String[] args){ try{ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); Document d= parser.parse("test.xml"); Element root = d.getDocumentElement(); if (root.getNodeName().compareTo("purchaseOrder")==0){ System.out.println(" orderDate==> " + root.getAttribute("orderDate"));

Node n = root.getFirstChild(); if (n != null){ do { if (n.getNodeType() == Node.ELEMENT_NODE && n.getNodeName().compareTo("item")==0){ Node n2 = n.getFirstChild(); if (n2!=null){ do { if (n2.getNodeType() == Node.ELEMENT_NODE){ System.out.println( n2.getNodeName() + "==>" + n2.getFirstChild().getNodeValue() ); } }while((n2=n2.getNextSibling())!=null); } } }while ((n=n.getNextSibling()) != null ); } } } catch (Exception e){ System.out.println("exception occurred ==>"+e); } } }

Come illustrato negli esempi di codice precedenti, VTD-XML esplora la gerarchia XML utilizzando un'API basata sul cursore. Al contrario, l'API DOM naviga nella gerarchia richiedendo riferimenti agli oggetti. Visitare il sito Web del progetto VTD-XML per ulteriori materiali tecnici ed esempi di codice che spiegano in modo approfondito VTD-XML.

Analisi comparativa di VTD-XML

Next, let's compare VTD-XML's performance and memory usage with some popular XML parsers. It should be noted that most articles containing benchmark numbers, such as "XML Documents on the Run" by Dennis Sosnoski (JavaWorld, April 2002), are from several years ago. Since then, better and faster hardware are following Moore's Law and becoming cheaper than ever. At the same time, XML parsing and the Java virtual machine have not been standing still—they have seen improvements in many key areas.

Test setup

The test platform is a Sony VAIO laptop equipped with a Pentium M 1.7 GHz processor (2 MB integrated L2 cache) and 512 MB DDR2 RAM. The front bus is clocked at 400 MHz. The OS is Windows XP Professional Edition with services pack 2. The JVM is version 1.5.0_06.

The benchmark tests the latest versions of the following XML parsers:

  • Xerces DOM 2.7.1, with and without deferred node expansion
  • Xerces SAX 2.7.1
  • Piccolo SAX 1.04
  • XPP3 1.1.3.4.O
  • VTD-XML 1.5, with and without buffer reuse

I selected a large collection of XML documents of varying sizes and structural complexities for the test. Depending on the file size, the test documents are grouped into three categories. Small files are less than 10 KB in size. Mid-sized files are between 10 KB and 1 MB. Files larger than 1 MB are considered big.

The server JVM was used for all performance measurements to obtain the peak performance. In those tests, the benchmark programs first looped through the parsing or navigation routines numerous times so that the JVM performed the dynamic, just-in-time optimization of the byte code, before averaging the performance of subsequent iterations as the final results. To reduce timing variation due to disk I/O, the benchmark programs read all XML files into in-memory buffers prior to the test runs.

Note: Interested readers can download the benchmark program from Resources.

Parsing throughput comparisons

Questa sezione presenta le prestazioni di analisi XML sia in termini di latenza che di velocità effettiva. Si noti che mentre VTD-XML e DOM sono direttamente confrontabili, non è corretto confrontare VTD-XML con SAX o Pull perché non creano alcuna struttura gerarchica in memoria. Quindi le prestazioni per SAX e Pull servono solo come punto di riferimento aggiuntivo.

Portata

Confronti di latenza

Tabella 1. File piccoli

Nome / dimensione del file VTD-XML (ms) Riutilizzo del buffer VTD-XML (ms) SAX (ms) DOM (ms) DOM differito (ms) Piccolo (ms) Tirare (ms)
soap2.xml (1727 byte) 0.0446 0.0346 0.0782 0.1122 0.16225 0.092 0.066
nav_48_0.xml (4608 byte) 0.1054 0.0928 0.266 0.37 0.385 0.2784 0.1742
cd_catalog.xml (5035 byte) 0.118 0.108 0.19 0.348 0.4 0.2 0.214
nav_63_0.xml (6848 byte) 0.149 0.135 0.354 0.513 0.557 0.484 0.242
nav_78_0.xml (6920 byte) 0.153 0.142 0.3704 0.588 0,52 0.42 0.29

Tabella 2. File XML medi