Análisis de documentos XML muy grandes (y un poco más) en Java

(Todo lo siguiente debe escribirse en Java)

Tengo que crear una aplicación que tendrá como entrada documentos XML que son, potencialmente, muy grandes. El documento está encriptado, no con XMLsec, pero con el algoritmo de cifrado preexistente de mi cliente, se procesará en tres fases:

En primer lugar, la secuencia se descifrará de acuerdo con el algoritmo mencionado anteriormente.

En segundo lugar, una clase de extensión (escrita por un tercero en una API que estoy proporcionando) leerá una parte del archivo. La cantidad que se lee no es predecible; en particular, no se garantiza que esté en el encabezado del archivo, pero puede ocurrir en cualquier punto del XML.

Por último, otra clase de extensión (misma oferta) subdividirá el XML de entrada en 1..n documentos subconjuntos. Es posible que en alguna parte se superpongan con la parte del documento tratada por la segunda operación, es decir: creo que tendré que rebobinar cualquier mecanismo que esté utilizando para tratar con este objeto.

Aquí está mi pregunta:

¿Hay alguna manera de hacer esto sin tener que leer toda la información en la memoria al mismo tiempo? Obviamente, puedo implementar el descifrado como un filtro de flujo de entrada, pero no estoy seguro de si es posible analizar XML en la forma en que estoy describiendo; al recorrer la mayor parte del documento para recostackr la información del segundo paso y, a continuación, rebobinar el documento y volver a pasarlo para dividirlo en trabajos, idealmente liberando todas las partes del documento que ya no se utilizan después ellos han sido pasados

Stax es el camino correcto. Yo recomendaría mirar Woodstox

Esto suena como un trabajo para StAX ( JSR 173 ). StAX es un analizador de extracción, lo que significa que funciona más o menos como un analizador sintáctico basado en eventos como SAX, pero que tiene más control sobre cuándo dejar de leer, qué elementos extraer, …

La usabilidad de esta solución dependerá en gran medida de lo que estén haciendo realmente sus clases de extensión, si tiene control sobre su implementación, etc.

El punto principal es que si el documento es muy grande, probablemente desee utilizar un analizador basado en eventos y no un árbol, por lo que no utilizará mucha memoria.

Se pueden encontrar implementaciones de StAX en SUN ( SJSXP ), Codehaus u otros proveedores.

Puede usar un BufferedInputStream con un tamaño de búfer muy grande y usar mark() antes de que la clase de extensión funcione y reset() después.

Si las partes que la clase de extensión necesita están muy lejos en el archivo, entonces esto podría requerir una gran cantidad de memoria.

Una solución más general sería escribir su propio BufferedInputStream -workalike que buffers en el disco si los datos que se almacenan en búfer excede algún umbral preestablecido.

Escribiría una implementación personalizada de InputStream que descifra los bytes en el archivo y luego use SAX para analizar el XML resultante a medida que sale de la transmisión.

 SAXParserFactory.newInstance().newSAXParser().parse( new DecryptingInputStream(), new MyHandler() ); 

Puede que te interese XOM :

XOM es bastante único ya que es una API dual basada en secuencias / árbol. Los nodos individuales en el árbol se pueden procesar mientras el documento se está construyendo. Permite que los progtwigs XOM funcionen casi tan rápido como el analizador subyacente puede suministrar datos. No necesita esperar a que el documento se analice por completo antes de poder comenzar a trabajar con él.

XOM es muy eficiente con la memoria. Si lee un documento completo en la memoria, XOM usa la menor cantidad de memoria posible. Lo que es más importante, XOM le permite filtrar documentos a medida que se construyen para que no tenga que construir las partes del árbol que no le interesan. Por ejemplo, puede omitir la construcción de nodos de texto que solo representan el espacio en blanco del límite, si ese espacio en blanco no es significativo en su aplicación. Incluso puede procesar un documento pieza por pieza y tirar cada pieza cuando haya terminado con ella. XOM se ha utilizado para procesar documentos que tienen un tamaño de gigabytes.

Mire la biblioteca XOM . El ejemplo que está buscando es StreamingExampleExtractor.java en el directorio de ejemplos de la distribución de origen. Esto muestra una técnica para realizar un análisis de transmisión de un documento xml grande que solo crea nodos específicos, los procesa y los descarta. Es muy similar a un enfoque sax, pero tiene una capacidad de análisis mucho más integrada, por lo que se puede lograr un análisis de transmisión con bastante facilidad.

Si quieres trabajar en un nivel superior, mira NUX . Esto proporciona una API de transmisión xpath de alto nivel que solo lee la cantidad de datos en la memoria necesaria para evaluar el xpath.