Siempre he encontrado que XML es algo engorroso de procesar. No estoy hablando de implementar un analizador XML: estoy hablando de usar un analizador basado en flujo existente, como un analizador SAX, que procesa el nodo XML por nodo.
Sí, es realmente fácil aprender las diversas API para estos analizadores, pero cada vez que miro el código que procesa XML siempre encuentro que es algo complicado. El problema esencial parece ser que un documento XML está separado lógicamente en nodos individuales y, sin embargo, los tipos y atributos de datos a menudo están separados de los datos reales, a veces por múltiples niveles de anidamiento. Por lo tanto, cuando se procesa un nodo en particular individualmente, se debe mantener una gran cantidad de estado adicional para determinar dónde estamos y qué debemos hacer a continuación.
Por ejemplo, dado un fragmento de un documento XML típico:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
... ¿Cómo determinaría cuándo me encuentro con un nodo de texto que contiene el título de un libro? Supongamos que tenemos un analizador XML simple que actúa como un iterador, dándonos el siguiente nodo en el documento XML cada vez que llamamos XMLParser.getNextNode()
. Inevitablemente me encuentro escribiendo código como el siguiente:
boolean insideBookNode = false;
boolean insideTitleNode = false;
while (!XMLParser.finished())
{
....
XMLNode n = XMLParser.getNextNode();
if (n.type() == XMLTextNode)
{
if (insideBookNode && insideTitleNode)
{
// We have a book title, so do something with it
}
}
else
{
if (n.type() == XMLStartTag)
{
if (n.name().equals("book")) insideBookNode = true
else if (n.name().equals("title")) insideTitleNode = true;
}
else if (n.type() == XMLEndTag)
{
if (n.name().equals("book")) insideBookNode = false;
else if (n.name().equals("title")) insideTitleNode = false;
}
}
}
Básicamente, el procesamiento XML se convierte rápidamente en un gran bucle controlado por máquinas de estado, con muchas variables de estado utilizadas para indicar nodos principales que hemos encontrado anteriormente. De lo contrario, se debe mantener un objeto de pila para realizar un seguimiento de todas las etiquetas anidadas. Esto rápidamente se vuelve propenso a errores y difícil de mantener.
Nuevamente, el problema parece ser que los datos que nos interesan no están directamente asociados con un nodo individual. Claro, podría ser, si escribiéramos el XML como:
<book title="Blah blah" author="blah blah" price="15 USD" />
... pero así es como se usa XML en la realidad. La mayoría de las veces tenemos nodos de texto como hijos de nodos principales, y necesitamos hacer un seguimiento de los nodos principales para determinar a qué se refiere un nodo de texto.
Entonces ... ¿estoy haciendo algo mal? ¿Hay una mejor manera? ¿En qué punto el uso de un analizador basado en flujo XML se vuelve demasiado engorroso, por lo que se hace necesario un analizador DOM completo? Me gustaría saber de otros programadores qué tipo de modismos usan cuando procesan XML con analizadores basados en secuencias. ¿El análisis XML basado en secuencias debe convertirse siempre en una gran máquina de estados?
fuente
Respuestas:
Para mí, la pregunta es al revés. ¿En qué punto un documento XML se vuelve tan engorroso que tiene que comenzar a usar SAX en lugar de DOM?
Solo usaría SAX para un flujo de datos muy grande y de tamaño indeterminado; o si el comportamiento que pretende invocar el XML está realmente basado en eventos y, por lo tanto, es similar a SAX.
El ejemplo que das me parece muy DOM.
EDITAR: También usaría SAX para transmisiones que pueden estar malformadas, pero donde quiero hacer una mejor suposición para obtener los datos.
fuente
No trabajo demasiado con XML, aunque en mi opinión, probablemente una de las mejores formas de analizar XML con una biblioteca es usando XPath.
En lugar de atravesar el árbol para encontrar algún nodo específico, le da una ruta. En el caso de su ejemplo (en pseudocódigo), sería algo así como:
XPath es mucho más poderoso que eso, puede buscar usando condiciones (tanto en valores como en atributos), seleccionar un nodo específico en una lista, mover niveles a través del árbol. Le recomiendo que busque información sobre cómo usarlo, está implementado en muchas bibliotecas de análisis (lo uso la versión .Net Framework y lxml para Python)
fuente
Por lo general, sí.
Para mí, utilizar un analizador DOM completo es cuando necesito imitar partes de la jerarquía de archivos en memoria, por ejemplo, para poder resolver referencias cruzadas dentro del documento.
fuente
Analizar en general es simplemente manejar una máquina de estado, y el análisis XML no es diferente. El análisis basado en secuencias siempre es una molestia, siempre termino construyendo una pila de algún tipo para realizar un seguimiento de los nodos ancestrales y definiendo muchos eventos y algún tipo de despachador de eventos que verifica un registro de etiqueta o ruta y dispara un evento si uno coincide El código central es bastante estricto, pero termino con una gran cantidad de controladores de eventos que consisten principalmente en asignar el valor del siguiente nodo de texto a un campo en una estructura en algún lugar. Puede ser bastante complicado si necesita mezclar la lógica de negocios allí también.
Siempre usaría DOM a menos que los problemas de tamaño o rendimiento dictaran lo contrario.
fuente
No es completamente independiente del lenguaje, pero normalmente deserializo el XML en objetos en lugar de pensar en el análisis. El único momento para preocuparse por las estrategias de análisis per se es si tiene un problema de velocidad.
fuente
Se vuelve mucho menos engorroso si puede usar XPath. Y en .Net land, LINQ to XML también extrae muchas de las cosas menos glamorosas. ( Editar : estos requieren un enfoque DOM, por supuesto)
Fundamentalmente, si está adoptando un enfoque basado en la transmisión (por lo que no puede utilizar abstracciones más agradables que requieren un DOM), creo que siempre será bastante engorroso y no estoy seguro de que haya alguna forma de evitarlo.
fuente
Si puede encontrar un analizador que le proporcione un iterador, ¿ha pensado en tratarlo como un lexer y utilizar un generador de máquina de estados?
fuente