Vereinfachen Sie die XML-Verarbeitung mit VTD-XML

Abbildung 3. Große XML-Dateien. Klicken Sie auf die Miniaturansicht, um das Bild in voller Größe anzuzeigen.

Acht Jahre nach seiner Einführung hat sich XML bereits als offenes, halbstrukturiertes Datenformat zum Speichern von Daten sowie zum Austausch von Daten über das Web etabliert. Aufgrund seiner Einfachheit und menschlichen Lesbarkeit hat XML seine Popularität bei Anwendungsentwicklern in die Höhe geschossen und ist zu einem unverzichtbaren Bestandteil der Unternehmensarchitektur geworden.

Obwohl es schwierig ist, die Anzahl der Verwendungsmöglichkeiten von XML aufzuzählen, kann man sich eines sicher sein: XML muss analysiert werden, bevor etwas anderes getan werden kann. Tatsächlich ist die Auswahl des richtigen Parsers oft eine der ersten Entscheidungen, die Unternehmensentwickler in ihren Projekten treffen müssen. Diese Entscheidung hängt immer wieder von den beiden gängigen XML-Verarbeitungsmodellen ab: dem Document Object Model (DOM) und der Simple API for XML (SAX).

Auf den ersten Blick scheinen sich die jeweiligen Stärken und Schwächen von DOM und SAX zu ergänzen: DOM erstellt speicherinterne Objektgraphen; SAX ist ereignisbasiert und speichert nichts im Speicher. Wenn also die Dokumentgröße klein und das Datenzugriffsmuster komplex ist, ist DOM der richtige Weg. Andernfalls verwenden Sie SAX.

Die Wahrheit ist jedoch noch nie so einfach. In den meisten Fällen sind Entwickler aufgrund ihrer Komplexität nicht bereit, SAX zu verwenden, tun dies jedoch weiterhin, da keine andere praktikable Option verfügbar ist. Wenn die XML-Dateigröße nur geringfügig größer als einige Hundert Kilobyte ist, werden der Speicheraufwand und der Leistungsverlust von DOM für Anwendungsentwickler zu einem schwierigen Hindernis, sodass sie die Mindestleistungsziele ihrer Projekte nicht erreichen können.

Aber ist SAX wirklich so viel besser? Die von SAX angekündigte Parsing-Leistung - normalerweise um ein Vielfaches schneller als die von DOM - täuscht tatsächlich häufig. Es stellt sich heraus, dass die umständliche, nur vorwärts gerichtete Natur des SAX-Parsing nicht nur zusätzlichen Implementierungsaufwand erfordert, sondern auch Leistungseinbußen verursacht, wenn die Dokumentstruktur nur geringfügig komplex wird. Wenn Entwickler das Dokument nicht mehrmals scannen möchten, müssen sie das Dokument puffern oder benutzerdefinierte Objektmodelle erstellen.

In beiden Fällen leidet die Leistung, wie beispielsweise Apache Axis zeigt. Auf seiner FAQ-Seite behauptet Axis, SAX intern zu verwenden, um eine leistungsstärkere Implementierung zu erstellen, erstellt jedoch ein eigenes Objektmodell, das ziemlich DOM-ähnlich ist, was zu vernachlässigbaren Leistungsverbesserungen im Vergleich zu seinem Vorgänger (Apache SOAP) führt. Darüber hinaus funktioniert SAX nicht gut mit XPath und kann im Allgemeinen die XSLT-Verarbeitung (Extensible Stylesheet Language Transformation) nicht steuern. Das SAX-Parsing umgeht also die eigentlichen Probleme der XML-Verarbeitung.

Auf der Suche nach einer benutzerfreundlicheren Alternative zu SAX haben sich immer mehr Entwickler an StAX (Streaming API for XML) gewandt. Im Vergleich zu SAX ziehen StAX-Parser Token aus XML-Dateien, anstatt Rückrufe zu verwenden. Obwohl sie die Benutzerfreundlichkeit spürbar verbessern, bleiben die grundlegenden Probleme bestehen: Der Nur-Forward-Parsing-Stil von StAX erfordert immer noch mühsamen Implementierungsaufwand und damit auch versteckte Leistungskosten.

Fazit: Damit ein XML-Verarbeitungsmodell allgemein nützlich ist, muss es die hierarchische Struktur von XML und nicht weniger darstellen. Der Grund dafür ist, dass XML so konzipiert ist, dass komplexe Daten über das Web übertragen werden und die Übermittlung der Strukturinformationen ein wesentlicher Bestandteil der XML-Funktionen ist.

VTD-XML verändert das Spiel

Angenommen, wir würden die XML-Verarbeitung von Grund auf neu starten, um die oben genannten Probleme mit DOM und SAX zu lösen. Das neue Modell sollte wahrscheinlich die folgenden Eigenschaften haben:

  • Direktzugriff möglich: Das Verarbeitungsmodell sollte es dem Entwickler ermöglichen, manuell oder besser mithilfe von XPath durch eine hierarchische Struktur zu navigieren.
  • Hohe Leistung: Die Leistung sollte wesentlich besser sein als bei DOM und SAX. Und die Leistung sollte "ehrlich" sein, was bedeutet, dass die Messung die Zeit umfassen muss, die für den Aufbau der hierarchischen Struktur aufgewendet wird.
  • Geringe Speichernutzung: Damit das Verarbeitungsmodell auf eine Vielzahl von Szenarien und Dateigrößen anwendbar ist, muss die gesamte XML-Struktur mit einem minimalen Speicherbedarf dargestellt werden.

VTD-XML wurde entwickelt, um diese Ziele zu erreichen. Es ist das Open-Source-XML-Verarbeitungsmodell der nächsten Generation, das grundlegende und umfassende Verbesserungen gegenüber DOM und SAX bietet. Eine Schlüsseloptimierung von VTD-XML ist die nicht-extraktive Tokenisierung. Intern VTD-XML behält im Speicher die intakt und nicht decodierten XML - Nachricht und stellt Token ausschließlich auf der Basis eines binären Codierungsangabe genannt V irtual T Oken D Escriptor. Ein VTD-Datensatz ist eine 64-Bit-Ganzzahl, die die Tokenlänge, den Startversatz, den Typ und die Verschachtelungstiefe eines Tokens in XML codiert.

Hier ein kleiner Teil der Geschichte von VTD-XML, falls Sie interessiert sind: Das Grundkonzept wurde als eine Möglichkeit konzipiert, die XML-Verarbeitung auf dedizierter Hardware in Form von FPGA oder ASIC zu portieren, damit Netzwerk-Switches und -Router XML verarbeiten können Inhalt bei sehr hohen Geschwindigkeiten. Später entschied sich das VTD-XML-Projektteam für Open Source VTD-XML, und die erste Version - Version 0.5 und in Java implementiert - fand im Mai 2004 statt. Seit dieser Version hat VTD-XML mehrere Verbesserungsrunden durchlaufen und ist ausgereift wesentlich. In Version 0.8 wurde die C-Version von VTD-XML zusammen mit der Java-Version veröffentlicht. Die integrierte XPath-Unterstützung wurde in Version 1.0 eingeführt und im Oktober 2005 veröffentlicht. Die neueste Version, Version 1.5, verfügt über eine neu geschriebene Parsing-Engine, die modularer und leistungsfähiger ist.

In dieser Version wurde auch eine Funktion namens Pufferwiederverwendung eingeführt. Die Grundidee besteht darin, dass eine Anwendung, die sich hinter einer Netzwerkverbindung befindet und viele eingehende XML-Dokumente wiederholt verarbeiten muss, die während des ersten Verarbeitungslaufs zugewiesenen Speicherpuffer tatsächlich wiederverwenden kann. Mit anderen Worten, weisen Sie Puffer einmal zu und verwenden Sie sie viele, viele Male. Speziell für VTD-XML ermöglicht diese Funktion die vollständige Eliminierung der Kosten für die Objekterstellung und die Speicherbereinigung (50 bis 80 Prozent des Overheads in DOM und SAX) bei der XML-Verarbeitung. Die Projektwebsite enthält die neuesten Software-Downloads und eine ausführliche technische Beschreibung von VTD-XML.

Ein kurzes Beispiel

Um einen Eindruck vom Programmierstil von VTD-XML zu bekommen, vergleicht dieser Artikel zunächst Code, der sowohl VTD-XML als auch DOM verwendet, um eine einfache XML-Datei mit dem Namen test.xml zu analysieren und zu navigieren, deren Textinhalt unten gezeigt wird:

  Lawnmower 1 148.95  

Die VTD-XML-Version sieht folgendermaßen aus:

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

Die DOM-Version derselben Anwendung wird unten angezeigt:

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

Wie in den obigen Codebeispielen dargestellt, navigiert VTD-XML mithilfe einer Cursor-basierten API durch die XML-Hierarchie. Im Gegensatz dazu navigiert die DOM-API durch die Hierarchie, indem sie Objektreferenzen anfordert. Weitere technische Materialien und Codebeispiele, die VTD-XML ausführlich erläutern, finden Sie auf der Website des VTD-XML-Projekts.

Benchmarking von 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

In diesem Abschnitt wird die XML-Parsing-Leistung in Bezug auf Latenz und Durchsatz dargestellt. Beachten Sie, dass VTD-XML und DOM zwar direkt vergleichbar sind, es jedoch nicht fair ist, VTD-XML mit SAX oder Pull zu vergleichen, da sie keine hierarchische Struktur im Speicher erstellen. Die Leistung für SAX und Pull dient also nur als zusätzlicher Bezugspunkt.

Durchsatz

Latenzvergleiche

Tabelle 1. Kleine Dateien

Dateiname / Größe VTD-XML (ms) Wiederverwendung des VTD-XML-Puffers (ms) SAX (ms) DOM (ms) DOM zurückgestellt (ms) Piccolo (ms) Ziehen (ms)
soap2.xml (1727 Bytes) 0,0446 0,0346 0,0782 0,1122 0,16225 0,092 0,066
nav_48_0.xml (4608 Bytes) 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 Bytes) 0,149 0,135 0,354 0,513 0,557 0,484 0,242
nav_78_0.xml (6920 Bytes) 0,153 0,142 0,3704 0,588 0,52 0,42 0,29

Tabelle 2. Mittlere XML-Dateien