Simplifiez le traitement XML avec VTD-XML

Figure 3. Gros fichiers XML. Cliquez sur la vignette pour voir l'image en taille réelle.

Huit ans après sa création, XML a déjà pris son envol en tant que format de données ouvert et semi-structuré pour stocker des données ainsi que pour échanger des données sur le Web. En raison de sa simplicité et de sa lisibilité humaine, XML a vu sa popularité monter en flèche parmi les développeurs d'applications et est devenu un élément indispensable de l'architecture d'entreprise.

Bien qu'il soit difficile d'énumérer le nombre de façons dont XML est utilisé, on peut être certain d'une chose: XML doit être analysé avant que quoi que ce soit d'autre puisse être fait. En fait, choisir le bon analyseur est souvent l'une des premières décisions que les développeurs d'entreprise doivent prendre dans leurs projets. Et encore et encore, cette décision revient aux deux modèles de traitement XML populaires: le Document Object Model (DOM) et l'API simple pour XML (SAX).

À première vue, les forces et faiblesses respectives de DOM et SAX semblent complémentaires: DOM construit des graphes d'objets en mémoire; SAX est basé sur les événements et ne stocke rien en mémoire. Donc, si la taille du document est petite et le modèle d'accès aux données, complexe, DOM est la voie à suivre; sinon, utilisez SAX.

Cependant, la vérité n'est jamais aussi simpliste. Le plus souvent, les développeurs ne sont pas disposés à utiliser SAX en raison de sa complexité, mais ils le font toujours car aucun autre choix viable n'est disponible. Sinon, si la taille du fichier XML est légèrement supérieure à quelques centaines de kilo-octets, la surcharge de mémoire et le ralentissement des performances de DOM deviennent un obstacle difficile pour les développeurs d'applications, les empêchant d'atteindre les objectifs de performances minimales de leurs projets.

Mais SAX est-il vraiment bien meilleur? Les performances d'analyse annoncées de SAX - généralement plusieurs fois plus rapides que celles du DOM - sont souvent trompeuses. Il s'avère que la nature maladroite et directe de l'analyse SAX nécessite non seulement un effort d'implémentation supplémentaire, mais entraîne également des pénalités de performance lorsque la structure du document devient légèrement complexe. Si les développeurs choisissent de ne pas numériser le document plusieurs fois, ils devront mettre le document en mémoire tampon ou créer des modèles d'objets personnalisés.

Dans tous les cas, les performances en souffrent, comme le montre Apache Axis. Sur sa page FAQ, Axis prétend utiliser en interne SAX pour créer une implémentation plus performante, mais il construit toujours son propre modèle d'objet qui ressemble assez à DOM, ce qui entraîne des améliorations de performances négligeables par rapport à son prédécesseur (Apache SOAP). De plus, SAX ne fonctionne pas bien avec XPath, et en général ne peut pas piloter le traitement XSLT (Extensible Stylesheet Language Transformation). L'analyse SAX contourne donc les vrais problèmes du traitement XML.

A la recherche d'une alternative plus simple d'utilisation à SAX, un nombre croissant de développeurs se sont tournés vers StAX (Streaming API for XML). Par rapport à SAX, les analyseurs StAX extraient des jetons à partir de fichiers XML au lieu d'utiliser des rappels. Bien qu'ils améliorent sensiblement la convivialité, les problèmes fondamentaux persistent: le style d'analyse avant uniquement de StAX nécessite toujours un effort de mise en œuvre fastidieux et, parallèlement, des coûts de performance cachés.

L'essentiel: pour qu'un modèle de traitement XML soit largement utile, il doit présenter la structure hiérarchique de XML et rien de moins. La raison en est que XML est conçu pour déplacer des données complexes sur le Web et que la transmission des informations structurelles fait partie intégrante de ce que fait XML.

VTD-XML change la donne

Supposons que nous devions commencer le traitement XML à partir de zéro pour surmonter les problèmes mentionnés ci-dessus avec DOM et SAX. Le nouveau modèle devrait probablement avoir les propriétés suivantes:

  • Possibilité d'accès aléatoire: Le modèle de traitement doit permettre au développeur de naviguer dans une sorte de structure hiérarchique soit manuellement, soit, mieux, en utilisant XPath.
  • Hautes performances: les performances devraient être nettement meilleures que celles du DOM et du SAX. Et la performance doit être «honnête», ce qui signifie que la mesure doit inclure le temps consacré à la construction de la structure hiérarchique.
  • Faible utilisation de la mémoire: pour rendre le modèle de traitement applicable à un large éventail de scénarios et de tailles de fichiers, il doit présenter la structure complète de XML avec une quantité minimale d'utilisation de la mémoire.

Conçu pour atteindre ces objectifs, VTD-XML est le modèle de traitement XML open source de nouvelle génération qui apporte des améliorations fondamentales et globales par rapport à DOM et SAX. Une optimisation clé de VTD-XML est la tokenisation non extractive. En interne, VTD-XML conserve en mémoire le message XML intact et non décodé et représente des jetons exclusivement basés sur une spécification de codage binaire appelée V irtual T oken D escriptor. Un enregistrement VTD est un entier 64 bits qui code la longueur du jeton, le décalage de départ, le type et la profondeur d'imbrication d'un jeton dans XML.

Voici un peu d'histoire de VTD-XML au cas où vous seriez intéressé: Le concept de base a été conçu comme un moyen de porter le traitement XML sur du matériel dédié, sous la forme de FPGA ou ASIC, pour permettre aux commutateurs et routeurs réseau de traiter XML contenu à des vitesses très élevées. Plus tard, l'équipe du projet VTD-XML a décidé d'ouvrir le code source VTD-XML, et la version initiale - de la version 0.5 et implémentée en Java - a eu lieu en mai 2004. Depuis cette version, VTD-XML a subi plusieurs séries d'améliorations et a mûri considérablement. Dans la version 0.8, la version C de VTD-XML a été publiée avec la version Java. La prise en charge XPath intégrée a été introduite dans la version 1.0 et publiée en octobre 2005. La dernière version, la version 1.5, comprend un moteur d'analyse réécrit qui est plus modulaire et plus performant.

Une fonctionnalité appelée réutilisation de la mémoire tampon est également introduite dans cette version. L'idée de base est que lorsqu'une application XML située derrière une connexion réseau doit traiter de manière répétitive de nombreux documents XML entrants, l'application peut en fait réutiliser les tampons mémoire alloués lors du premier traitement. En d'autres termes, allouez les tampons une fois et utilisez-les plusieurs fois. Spécifique à VTD-XML, cette fonctionnalité permet d'éliminer complètement les coûts de création d'objets et de garbage collection (50-80 pour cent de la surcharge dans DOM et SAX) du traitement XML. Le site Web du projet contient les derniers téléchargements de logiciels et une description technique approfondie de VTD-XML.

Un exemple rapide

Pour donner une idée du style de programmation de VTD-XML, cet article compare d'abord le code utilisant à la fois VTD-XML et DOM pour analyser et parcourir un simple fichier XML nommé test.xml, dont le contenu textuel est indiqué ci-dessous:

  Lawnmower 1 148.95  

La version VTD-XML ressemble à ceci:

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 version DOM de la même application est illustrée ci-dessous:

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

Comme illustré dans les exemples de code ci-dessus, VTD-XML parcourt la hiérarchie XML à l'aide d'une API basée sur un curseur. En revanche, l'API DOM parcourt la hiérarchie en demandant des références d'objets. Veuillez visiter le site Web du projet VTD-XML pour plus de matériel technique et des exemples de code qui expliquent VTD-XML en profondeur.

Analyse comparative 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

Cette section présente les performances d'analyse XML en temps de latence et en débit. Notez que si VTD-XML et DOM sont directement comparables, il n'est pas juste de comparer VTD-XML avec SAX ou Pull car ils ne construisent aucune structure hiérarchique en mémoire. Les performances pour SAX et Pull ne servent donc que de point de référence supplémentaire.

Débit

Comparaisons de latence

Tableau 1. Petits fichiers

Nom / taille du fichier VTD-XML (ms) Réutilisation du tampon VTD-XML (ms) SAX (ms) DOM (ms) DOM différé (ms) Piccolo (ms) Tirer (ms)
soap2.xml (1727 octets) 0,0446 0,0346 0,0782 0,1122 0,16225 0,092 0,066
nav_48_0.xml (4608 octets) 0,1054 0,0928 0,266 0,37 0,385 0,2784 0,1742
cd_catalog.xml (5035 octets) 0,118 0,108 0,19 0,348 0,4 0,2 0,214
nav_63_0.xml (6848 octets) 0,149 0,135 0,354 0,513 0,557 0,484 0,242
nav_78_0.xml (6920 octets) 0,153 0,142 0,3704 0,588 0,52 0,42 0,29

Tableau 2. Fichiers XML moyens