java - parser - ¿Cuándo debería elegir SAX sobre StAX?
sax parser (6)
@Rinke: supongo que es hora de que prefiera SAX a STAX en caso de que no necesite manejar / procesar el contenido XML; por ejemplo, lo único que quiere hacer es verificar la buena formación del XML entrante y simplemente quiere manejar los errores si lo tiene ... en este caso, simplemente puede llamar al método parse () en el analizador SAX y especificar el manejador de errores para manejar cualquier problema de análisis ... básicamente, STAX es definitivamente una opción preferible en los escenarios en los que se desea manejar contenido porque el controlador de contenido SAX es demasiado difícil de codificar ...
Un ejemplo práctico de este caso puede ser que si tiene una serie de nodos SOAP en su sistema empresarial y un nodo SOAP de nivel de entrada solo permite que esos XML SOAP pasen a la etapa siguiente, que sean bien formados, entonces no veo ninguna razón por la cual usaría STAX. Yo solo usaría SAX.
Los analizadores xml de transmisión por secuencias como SAX y StAX son más rápidos y más eficientes en cuanto a la memoria que los analizadores que crean una estructura de árbol como los analizadores DOM. SAX es un analizador de impulsos, lo que significa que es una instancia del patrón del observador (también llamado patrón de escucha). SAX estaba allí primero, pero luego vino StAX, un analizador de extracción, lo que significa que básicamente funciona como un iterador.
Puede encontrar razones por las que prefiere StAX sobre SAX en todas partes, pero generalmente se reduce a: "es más fácil de usar".
En el tutorial de Java sobre JAXP StAX se presenta vagamente como el medio entre DOM y SAX: "es más fácil que SAX y más eficiente que DOM". Sin embargo, nunca encontré ninguna pista de que StAX sea más lento o menos eficiente que SAX.
Todo esto me hizo preguntarme: ¿hay alguna razón para elegir SAX en lugar de StAX?
Es todo un equilibrio.
Puede convertir un analizador de SAX en un analizador de extracción utilizando una cola de bloqueo y algunos trucos de hilos, por lo que, para mí, hay mucha menos diferencia de lo que parece en un principio.
Creo que actualmente StAX necesita ser empacado a través de un contenedor de terceros mientras que SAX viene gratis en javax.
Hace poco elegí SAX y construí un analizador de extracción para que no tuviera que depender de un contenedor de terceros.
Las versiones futuras de Java seguramente contendrán una implementación StAX para que el problema desaparezca.
La mayoría de la información provista por esas respuestas está un poco desactualizada ... se ha realizado un estudio exhaustivo de todas las librerías de análisis XML en este documento de investigación 2013 ... léalo y verá fácilmente al ganador claro (pista: solo hay una) verdadero ganador) ...
http://recipp.ipp.pt/bitstream/10400.22/1847/1/ART_BrunoOliveira_2013.pdf
StAX le permite crear analizadores XML bidireccionales que son rápidos. Es una mejor alternativa a otros métodos, como DOM y SAX, tanto en términos de rendimiento como de usabilidad.
Puede leer más sobre StAX en los tutoriales de Java StAX
Visión de conjunto
Los documentos XML son documentos jerárquicos, donde los mismos nombres de elementos y espacios de nombres pueden aparecer en varios lugares, tener diferentes significados y en profundidad infinitiva (recursiva). Como es normal, la solución a los grandes problemas es dividirlos en pequeños problemas. En el contexto del análisis XML, esto significa analizar partes específicas de XML en métodos específicos para ese XML. Por ejemplo, una pieza de lógica analizaría una dirección:
<Address>
<Street>Odins vei</Street>
<Building>4</Building>
<Door>b</Door>
</Address>
es decir, tendrías un método
AddressType parseAddress(...); // A
o
void parseAddress(...); // B
en algún lugar de tu lógica, tomando XML ingresa argumentos y devuelve un objeto (el resultado de B puede ser extraído de un campo más adelante).
SAXÓFONO
SAX ''empuja'' los events XML , dejando que usted determine dónde pertenecen los eventos XML en su programa / datos.
// method in stock SAX handler
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
// .. your logic here for start element
}
En el caso de un elemento de inicio ''Edificio'', necesitaría determinar que en realidad está analizando una Dirección y luego enrutar el evento XML al método cuyo trabajo es interpretar la Dirección.
StAX
StAX ''extrae'' events XML , dejando que usted determine dónde en su programa / datos recibir los eventos XML.
// method in standard StAX reader
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
// .. your logic here for start element
}
Por supuesto, siempre desearía recibir un evento ''Building'' en el método cuyo trabajo es interpretar Address.
Discusión
La diferencia entre SAX y StAX es la de empujar y tirar. En ambos casos, el estado de análisis debe manejarse de alguna manera.
Esto se traduce en el método B como típico para SAX, y el método A para StAX. Además, SAX debe dar B eventos XML individuales, mientras que StAX puede dar A eventos múltiples (pasando una instancia de XMLStreamReader).
Por lo tanto, B primero verifica el estado anterior del análisis sintáctico y luego maneja cada evento XML individual y luego almacena el estado (en un campo). El Método A solo puede manejar los eventos XML a la vez accediendo al XMLStreamReader varias veces hasta que esté satisfecho.
Conclusión
StAX le permite estructurar su código de análisis (enlace de datos) de acuerdo con la estructura XML ; Entonces, en relación con SAX, el ''estado'' está implícito en el flujo del programa para StAX, mientras que en SAX, siempre necesita conservar algún tipo de variable de estado + enrutar el flujo según ese estado, para la mayoría de las llamadas a eventos.
Recomiendo StAX para todos menos para los documentos más simples. Más bien, muévase a SAX como una optimización más tarde (pero es probable que desee ir binario para entonces).
Siga este patrón al analizar con StAX:
public MyDataBindingObject parse(..) { // provide input stream, reader, etc
// set up parser
// read the root tag to get to level 1
XMLStreamReader reader = ....;
do {
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
// check if correct root tag
break;
}
// add check for document end if you want to
} while(reader.hasNext());
MyDataBindingObject object = new MyDataBindingObject();
// read root attributes if any
int level = 1; // we are at level 1, since we have read the document header
do {
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
level++;
// do stateful stuff here
// for child logic:
if(reader.getLocalName().equals("Whatever1")) {
WhateverObject child = parseSubTreeForWhatever(reader);
level --; // read from level 1 to 0 in submethod.
// do something with the result of subtree
object.setWhatever(child);
}
// alternatively, faster
if(level == 2) {
parseSubTreeForWhateverAtRelativeLevel2(reader);
level --; // read from level 1 to 0 in submethod.
// do something with the result of subtree
object.setWhatever(child);
}
} else if(event == XMLStreamConstants.END_ELEMENT) {
level--;
// do stateful stuff here, too
}
} while(level > 0);
return object;
}
Entonces, el submétodo usa aproximadamente el mismo enfoque, es decir, el nivel de conteo:
private MySubTreeObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {
MySubTreeObject object = new MySubTreeObject();
// read element attributes if any
int level = 1;
do {
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
level++;
// do stateful stuff here
// for child logic:
if(reader.getLocalName().equals("Whatever2")) {
MyWhateverObject child = parseMySubelementTree(reader);
level --; // read from level 1 to 0 in submethod.
// use subtree object somehow
object.setWhatever(child);
}
// alternatively, faster, but less strict
if(level == 2) {
MyWhateverObject child = parseMySubelementTree(reader);
level --; // read from level 1 to 0 in submethod.
// use subtree object somehow
object.setWhatever(child);
}
} else if(event == XMLStreamConstants.END_ELEMENT) {
level--;
// do stateful stuff here, too
}
} while(level > 0);
return object;
}
Y luego, eventualmente alcanzas un nivel en el que leerás los tipos básicos.
private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {
MySetterGetterObject myObject = new MySetterGetterObject();
// read element attributes if any
int level = 1;
do {
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
level++;
// assume <FirstName>Thomas</FirstName>:
if(reader.getLocalName().equals("FirstName")) {
// read tag contents
String text = reader.getElementText()
if(text.length() > 0) {
myObject.setName(text)
}
level--;
} else if(reader.getLocalName().equals("LastName")) {
// etc ..
}
} else if(event == XMLStreamConstants.END_ELEMENT) {
level--;
// do stateful stuff here, too
}
} while(level > 0);
// verify that all required fields in myObject are present
return myObject;
}
Esto es bastante sencillo y no hay lugar para malentendidos. Solo recuerda disminuir el nivel correctamente:
A. después de que esperaba los caracteres pero obtuvo un END_ELEMENT en alguna etiqueta que debería contener caracteres (en el patrón anterior):
<Name>Thomas</Name>
fue en cambio
<Name></Name>
Lo mismo es cierto para un subárbol perdido también, entiendes la idea.
B. después de llamar a los métodos de subpaso, que son llamados en los elementos de inicio, y regresa DESPUÉS del elemento final correspondiente, es decir, el analizador está en un nivel más bajo que antes de la llamada al método (el patrón anterior).
Tenga en cuenta cómo este enfoque ignora por completo el espacio en blanco "ignorable" también, para una implementación más robusta.
Parsers
Vaya con Woodstox para la mayoría de las funciones o con Aaalto-xml para obtener mayor velocidad.
Para generalizar un poco, creo que StAX
puede ser tan eficiente como SAX
. Con el diseño mejorado de StAX
, no puedo encontrar ninguna situación en la que se prefiera el análisis SAX
, a menos que trabaje con código heredado.
EDITAR : Según este blog, Java SAX vs. StAX StAX
no ofrecen validación de esquema.