Simplifique el procesamiento de XML con VTD-XML

Figura 3. Grandes archivos XML. Haga clic en la miniatura para ver la imagen a tamaño completo.

Ocho años desde su creación, XML ya ha despegado como un formato de datos abierto y semiestructurado para almacenar datos e intercambiar datos a través de la Web. Debido a su simplicidad y legibilidad humana, XML ha visto dispararse su popularidad entre los desarrolladores de aplicaciones y se ha convertido en una parte indispensable de la arquitectura empresarial.

Aunque es difícil enumerar el número de formas en que se utiliza XML, uno puede estar seguro de una cosa: XML debe analizarse antes de que se pueda hacer cualquier otra cosa. De hecho, elegir el analizador adecuado suele ser una de las primeras decisiones que los desarrolladores empresariales deben abordar en sus proyectos. Y una y otra vez, esa decisión se reduce a los dos modelos populares de procesamiento de XML: el Modelo de objetos de documento (DOM) y la API simple para XML (SAX).

A primera vista, las respectivas fortalezas y debilidades de DOM y SAX parecen complementarias: DOM crea gráficos de objetos en memoria; SAX se basa en eventos y no almacena nada en la memoria. Entonces, si el tamaño del documento es pequeño y el patrón de acceso a los datos, complejo, DOM es el camino a seguir; de lo contrario, utilice SAX.

Sin embargo, la verdad nunca es tan simplista. La mayoría de las veces, los desarrolladores no están dispuestos a usar SAX debido a su complejidad, pero aún lo hacen porque no hay otra opción viable disponible. De lo contrario, si el tamaño del archivo XML es solo un poco mayor que unos pocos cientos de kilobytes, la sobrecarga de memoria de DOM y la resistencia al rendimiento se convierten en un obstáculo difícil para los desarrolladores de aplicaciones, lo que les impide cumplir con los objetivos mínimos de rendimiento de sus proyectos.

Pero, ¿es SAX realmente mucho mejor? El rendimiento de análisis publicitado de SAX, por lo general varias veces más rápido que DOM, es en realidad a menudo engañoso. Resulta que la naturaleza incómoda y de solo avance del análisis SAX no solo requiere un esfuerzo de implementación adicional, sino que también incurre en penalizaciones de rendimiento cuando la estructura del documento se vuelve solo ligeramente compleja. Si los desarrolladores optan por no escanear el documento varias veces, deberán almacenar el documento en búfer o crear modelos de objetos personalizados.

De cualquier manera, el rendimiento se ve afectado, como lo ejemplifica Apache Axis. En su página de preguntas frecuentes, Axis afirma utilizar SAX internamente para crear una implementación de mayor rendimiento, pero aún así construye su propio modelo de objetos que es bastante similar a DOM, lo que resulta en mejoras de rendimiento insignificantes en comparación con su predecesor (Apache SOAP). Además, SAX no funciona bien con XPath y, en general, no puede controlar el procesamiento XSLT (Transformación del lenguaje de hoja de estilo extensible). Por tanto, el análisis de SAX evita los problemas reales del procesamiento XML.

Buscando una alternativa más fácil de usar a SAX, un número creciente de desarrolladores ha recurrido a StAX (Streaming API para XML). En comparación con SAX, los analizadores StAX extraen tokens de archivos XML en lugar de utilizar devoluciones de llamada. Si bien mejoran notablemente la usabilidad, los problemas fundamentales persisten: el estilo de análisis de solo avance de StAX aún requiere un tedioso esfuerzo de implementación y, junto con él, costos de rendimiento ocultos.

El resultado final: para que cualquier modelo de procesamiento XML sea ampliamente útil, debe presentar la estructura jerárquica de XML y nada menos. La razón es que XML está diseñado para mover datos complejos a través de la Web y transmitir la información estructural es una parte inherente de lo que hace XML.

VTD-XML cambia el juego

Supongamos que comenzamos el procesamiento XML desde cero para superar los problemas mencionados anteriormente con DOM y SAX. El nuevo modelo probablemente debería tener las siguientes propiedades:

  • Capacidad de acceso aleatorio: el modelo de procesamiento debe permitir al desarrollador navegar por algún tipo de estructura jerárquica, ya sea manualmente o, mejor, utilizando XPath.
  • Alto rendimiento: el rendimiento debería ser sustancialmente mejor que DOM y SAX. Y el desempeño debe ser "honesto", lo que significa que la medición debe incluir el tiempo dedicado a construir la estructura jerárquica.
  • Bajo uso de memoria: para que el modelo de procesamiento sea aplicable a una amplia gama de escenarios y tamaños de archivo, debe presentar la estructura completa de XML con una cantidad mínima de uso de memoria.

Diseñado para cumplir con esos objetivos, VTD-XML es el modelo de procesamiento XML de código abierto de próxima generación que aporta mejoras fundamentales y completas sobre DOM y SAX. Una optimización clave de VTD-XML es la tokenización no extractiva. Internamente, VTD-XML retiene en la memoria el mensaje XML intacto y sin codificar, y representa tokens basados ​​exclusivamente en una especificación de codificación binaria llamada V irtual T oken D escriptor. Un registro VTD es un entero de 64 bits que codifica la longitud del token, el desplazamiento inicial, el tipo y la profundidad de anidamiento de un token en XML.

Aquí hay un poco de la historia de VTD-XML en caso de que esté interesado: El concepto básico fue concebido como una forma de portar el procesamiento XML en hardware dedicado, en forma de FPGA o ASIC, para permitir que los conmutadores y enrutadores de red procesen XML contenido a velocidades muy altas. Más tarde, el equipo del proyecto VTD-XML decidió abrir VTD-XML de código abierto, y el lanzamiento inicial, de la versión 0.5 e implementado en Java, tuvo lugar en mayo de 2004. Desde ese lanzamiento, VTD-XML ha experimentado varias rondas de mejoras y ha madurado importantemente. En la versión 0.8, se lanzó la versión C de VTD-XML junto con la versión Java. La compatibilidad con XPath incorporada se introdujo en la versión 1.0 y se lanzó en octubre de 2005. La última versión, la versión 1.5, presenta un motor de análisis reescrito que es más modular y de mayor rendimiento.

También se presenta en esta versión una función llamada reutilización de búfer. La idea básica es que cuando una aplicación XML que se encuentra detrás de una conexión de red necesita procesar repetidamente muchos documentos XML entrantes, la aplicación puede reutilizar los búferes de memoria asignados durante la primera ejecución de procesamiento. En otras palabras, asigne búferes una vez y utilícelos muchas, muchas veces. Específica para VTD-XML, esta característica permite la eliminación completa tanto del costo de creación de objetos como de recolección de basura (50-80 por ciento de la sobrecarga en DOM y SAX) del procesamiento XML. El sitio web del proyecto contiene las últimas descargas de software y una descripción técnica detallada de VTD-XML.

Un ejemplo rapido

Para dar una idea del estilo de programación de VTD-XML, este artículo primero compara el código usando tanto VTD-XML como DOM para analizar y navegar por un archivo XML simple llamado test.xml, cuyo contenido de texto se muestra a continuación:

  Lawnmower 1 148.95  

La versión VTD-XML se ve así:

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 versión DOM de la misma aplicación se muestra a continuación:

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

Como se ilustra en los ejemplos de código anteriores, VTD-XML navega por la jerarquía XML utilizando una API basada en cursor. Por el contrario, la API DOM navega por la jerarquía solicitando referencias de objetos. Visite el sitio web del proyecto VTD-XML para obtener más materiales técnicos y ejemplos de código que explican VTD-XML en mayor profundidad.

Benchmarking 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

Esta sección presenta el rendimiento del análisis de XML tanto en latencia como en rendimiento. Tenga en cuenta que si bien VTD-XML y DOM son directamente comparables, no es justo comparar VTD-XML con SAX o Pull porque no construyen ninguna estructura jerárquica en la memoria. Así que el rendimiento para SAX y Pull solo sirve como un punto de referencia adicional.

Rendimiento

Comparaciones de latencia

Tabla 1. Archivos pequeños

Nombre / tamaño de archivo VTD-XML (ms) Reutilización de búfer VTD-XML (ms) SAXO (ms) DOM (ms) DOM diferido (ms) Piccolo (ms) Tirar (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 bytes) 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

Tabla 2. Archivos XML medianos