¿Qué analizador XML debo usar en C++?
xml-parsing c++-faq (6)
Tengo documentos XML que necesito analizar y / o necesito crear documentos XML y escribirlos en texto (archivos o memoria). Dado que la biblioteca estándar de C ++ no tiene una biblioteca para esto, ¿qué debo usar?
Nota: esto pretende ser una pregunta definitiva, de estilo C ++ - Preguntas frecuentes para esto. Así que sí, es un duplicado de los demás. Simplemente no me apropié de esas otras preguntas porque tendían a pedir algo un poco más específico. Esta pregunta es más genérica.
Al igual que con los contenedores de biblioteca estándar, la biblioteca que debe usar depende de sus necesidades. Aquí hay un diagrama de flujo conveniente:
Así que la primera pregunta es esta: ¿Qué necesitas?
Necesito el cumplimiento completo de XML
OK, entonces necesitas procesar XML. No juguete XML, XML real . Debe poder leer y escribir toda la especificación XML, no solo los bits de baja mentira, fáciles de analizar. Necesitas espacios de nombres, documentos, sustitución de entidades, las obras. La especificación XML del W3C, en su totalidad.
La siguiente pregunta es: ¿Su API necesita ajustarse a DOM o SAX?
Necesito la conformidad exacta de DOM y / o SAX
OK, entonces realmente necesitas que la API sea DOM y / o SAX. No puede ser simplemente un analizador push de estilo SAX o un analizador retenido de estilo DOM. Debe ser el DOM real o el SAX real, en la medida en que C ++ lo permita.
Has elegido:
Esa es tu elección. Es prácticamente el único analizador / escritor de C ++ XML que tiene conformidad total (o tan cercana como lo permite C ++) DOM y SAX. También tiene compatibilidad con XInclude, compatibilidad con el esquema XML y una gran cantidad de otras características.
No tiene dependencias reales. Utiliza la licencia de apache.
No me importa el cumplimiento de DOM y / o SAX
Has elegido:
LibXML2 ofrece una interfaz de estilo C (si eso realmente te molesta, usa Xerces), aunque la interfaz está al menos algo basada en objetos y se ajusta fácilmente. Proporciona muchas funciones, como el soporte de XInclude (con devoluciones de llamada para que pueda decir de dónde obtiene el archivo), un reconocedor de XPath 1.0, soporte de RelaxNG y Schematron (aunque los mensajes de error dejan mucho que desear), y así sucesivamente
Tiene una dependencia en iconv, pero se puede configurar sin esa dependencia. Aunque eso significa que tendrá un conjunto más limitado de posibles codificaciones de texto que puede analizar.
Utiliza la licencia MIT.
No necesito el cumplimiento completo de XML
OK, entonces el cumplimiento total de XML no te importa. Sus documentos XML están totalmente bajo su control o están garantizados para usar el "subconjunto básico" de XML: sin espacios de nombres, entidades, etc.
Entonces, ¿qué te importa? La siguiente pregunta es: ¿Qué es lo más importante para usted en su trabajo XML?
Rendimiento de análisis XML máximo
Su aplicación necesita tomar XML y convertirlo en estructuras de datos C ++ tan rápido como sea posible esta conversión.
Has elegido:
Este analizador XML es exactamente lo que dice en el estaño: XML rápido. Ni siquiera se ocupa de llevar el archivo a la memoria; Cómo eso sucede depende de ti. Lo que sí trata es analizar eso en una serie de estructuras de datos C ++ a las que puede acceder. Y lo hace tan rápido como sea necesario para escanear el byte a byte del archivo.
Por supuesto, no hay tal cosa como un almuerzo gratis. Como la mayoría de los analizadores XML que no se preocupan por la especificación XML, Rapid XML no toca espacios de nombres, DocTypes, entidades (con la excepción de las entidades de caracteres y las 6 XML básicas), etc. Así que básicamente nodos, elementos, atributos, y tal.
Además, es un analizador de estilo DOM. Por lo tanto, se requiere que lea todo el texto. Sin embargo, lo que no hace es copiar cualquiera de ese texto (generalmente). La forma en que RapidXML obtiene la mayor parte de su velocidad es al referirse a cadenas en el lugar . Esto requiere una mayor administración de la memoria de su parte (debe mantener esa cadena viva mientras RapidXML lo está viendo).
El DOM de RapidXML es escueto. Puede obtener valores de cadena para las cosas. Puede buscar atributos por nombre. Eso es todo. No hay funciones de conveniencia para convertir los atributos en otros valores (números, fechas, etc.). Sólo tienes cuerdas.
Otro inconveniente con RapidXML es que es doloroso para escribir XML. Requiere que hagas mucha asignación explícita de memoria de nombres de cadenas para construir su DOM. Proporciona un tipo de búfer de cadena, pero aún requiere mucho trabajo explícito en su final. Es ciertamente funcional, pero es un dolor para usar.
Utiliza la licencia MIT. Es una biblioteca de solo encabezado sin dependencias.
- Hay un "parche GitHub" de RapidXML que le permite trabajar también con espacios de nombres.
Me importa el rendimiento, pero no tanto
Sí, el rendimiento te importa. Pero tal vez necesitas algo un poco menos escueto. Tal vez algo que pueda manejar más Unicode, o que no requiera tanta administración de memoria controlada por el usuario. El rendimiento sigue siendo importante, pero quieres algo un poco menos directo.
Has elegido:
Históricamente, esto sirvió de inspiración para RapidXML. Pero los dos proyectos se han desviado, con Pugi ofreciendo más funciones, mientras que RapidXML se centra completamente en la velocidad.
PugiXML ofrece compatibilidad con la conversión de Unicode, por lo que si tiene algunos documentos UTF-16 y desea leerlos como UTF-8, Pugi los proporcionará. Incluso tiene una implementación XPath 1.0, si necesitas ese tipo de cosas.
Pero Pugi sigue siendo bastante rápido. Al igual que RapidXML, no tiene dependencias y se distribuye bajo la Licencia MIT.
Leyendo documentos enormes
Debe leer los documentos que se miden en el tamaño de los gigabytes . Tal vez los estás recibiendo de stdin, siendo alimentado por algún otro proceso. O los estás leyendo desde archivos masivos. O lo que sea. El punto es que lo que necesita es no tener que leer todo el archivo en la memoria de una vez para procesarlo.
Has elegido:
LibXML2
La API de estilo SAX de Xerces funcionará en esta capacidad, pero LibXML2 está aquí porque es un poco más fácil trabajar con él. Una API de estilo SAX es una API de inserción: comienza a analizar una secuencia y simplemente dispara los eventos que tiene que capturar. Estás obligado a gestionar el contexto, el estado, etc. El código que lee una API de estilo SAX está mucho más extendido de lo que se podría esperar.
El objeto xmlReader de xmlReader
es una API de extracción. Usted solicita ir al siguiente nodo o elemento XML; no se te dice Esto le permite almacenar el contexto como mejor le parezca, para manejar diferentes entidades de una manera que sea mucho más legible en código que un montón de devoluciones de llamada.
Alternativas
Expat es un conocido analizador de C ++ que utiliza una API de parpadeo. Fue escrito por James Clark.
Su estado actual es activo. La versión más reciente es la 2.2.5, que fue lanzada el mes pasado (2017-10-31).
Es una implementación de una API de estilo StAX. Es un analizador de extracción, similar al analizador xmlReader de xmlReader
.
Pero no se ha actualizado desde 2005. Así que de nuevo, Caveat Emptor.
Soporte XPath
XPath es un sistema para consultar elementos dentro de un árbol XML. Es una forma práctica de nombrar efectivamente un elemento o una colección de elementos por propiedades comunes, utilizando una sintaxis estandarizada. Muchas bibliotecas XML ofrecen soporte XPath.
Hay efectivamente tres opciones aquí:
- LibXML2 : Proporciona soporte completo de XPath 1.0. Nuevamente, es una API de C, así que si eso te molesta, hay alternativas.
- PugiXML : Viene con soporte XPath 1.0 también. Como se mencionó anteriormente, es más una API de C ++ que LibXML2, por lo que puede sentirse más cómodo con ella.
- TinyXML : no viene con soporte XPath, pero existe la biblioteca TinyXPath que lo proporciona. TinyXML está experimentando una conversión a la versión 2.0, que cambia significativamente la API, por lo que TinyXPath puede no funcionar con la nueva API. Al igual que TinyXML, TinyXPath se distribuye bajo la licencia zLib.
Acaba de hacer el trabajo
Por lo tanto, no te importa la corrección de XML. El rendimiento no es un problema para ti. El streaming es irrelevante. Todo lo que desea es algo que lleve XML a la memoria y le permita volver a pegarlo en el disco. Lo que te importa es API.
Desea un analizador XML que sea pequeño, fácil de instalar, trivial de usar y lo suficientemente pequeño como para que sea irrelevante para el tamaño de su ejecutable.
Has elegido:
Puse TinyXML en esta ranura porque es casi tan fácil de usar como los analizadores XML. Sí, es lento, pero es simple y obvio. Tiene una gran cantidad de funciones de conveniencia para convertir atributos y así sucesivamente.
Escribir XML no es un problema en TinyXML. Solo tienes que std::ostream
algunos objetos, juntarlos, enviar el documento a un std::ostream
y todos están contentos.
También hay algo así como un ecosistema construido alrededor de TinyXML, con una API más amigable con el iterador, e incluso una implementación XPath 1.0 en capas sobre ella.
TinyXML usa la licencia zLib, que es más o menos la licencia MIT con un nombre diferente.
En Secured Globe , Inc. utilizamos RapidXML . Probamos todos los demás, pero rapidxml parece ser la mejor opción para nosotros.
Aquí hay un ejemplo:
rapidxml::xml_document<char> doc;
doc.parse<0>(xmlData);
rapidxml::xml_node<char>* root = doc.first_node();
rapidxml::xml_node<char>* node_account = 0;
if (GetNodeByElementName(root, "Account", &node_account) == true)
{
rapidxml::xml_node<char>* node_default = 0;
if (GetNodeByElementName(node_account, "default", &node_default) == true)
{
swprintf(result, 100, L"%hs", node_default->value());
free(xmlData);
return true;
}
}
free(xmlData);
Hay otro enfoque para el manejo de XML que puede considerar, llamado enlace de datos XML. Especialmente si ya tiene una especificación formal de su vocabulario XML, por ejemplo, en el esquema XML.
El enlace de datos XML le permite utilizar XML sin realizar ningún análisis o serialización XML. Un compilador de enlace de datos genera automáticamente todo el código de bajo nivel y presenta los datos analizados como clases de C ++ que corresponden a su dominio de aplicación. Luego trabaja con estos datos llamando a las funciones y trabajando con tipos de C ++ (int, double, etc.) en lugar de comparar cadenas y analizar texto (que es lo que hace con las API de acceso XML de bajo nivel, como DOM o SAX).
Vea, por ejemplo, una implementación de enlace de datos XML de código abierto que escribí, CodeSynthesis XSD y, para una versión más ligera, sin dependencia, CodeSynthesis XSD / e .
OK entonces. He creado uno nuevo, ya que ninguno de la lista no era suficiente para mis necesidades.
Beneficios:
- Pull-parser Streaming API en el nivel bajo (como Java StAX )
- Excepciones y modos RTTI de soportados.
- Límite para el uso de la memoria, soporte para archivos grandes (probado con un archivo XMark de 100 mib, la velocidad depende del hardware)
- Soporte de UNICODE y detección automática de codificación de fuente de entrada
- API de alto nivel para la lectura en structures/POCO
- API de meta-programación para escribir y generar XSD desde structures/POCO con soporte para estructura xml (atributos y etiquetas de anidamiento) (la generación de XSD necesita RTTI, pero se puede usar solo en la depuración para hacerlo una vez)
- C ++ 11 - GCC y VC ++ 15+
Desventajas:
- La validación DTD y XSD aún no se ha proporcionado
- Obtención de XML / XSD por HTTP / HTTPS en progreso, aún no hecho
- Nueva biblioteca
Otra nota sobre Expat: vale la pena mirar para el trabajo de sistemas embebidos. Sin embargo, la documentación que probablemente encontrará en la web es antigua e incorrecta. El código fuente en realidad tiene comentarios bastante completos a nivel de función, pero tomará algo de sentido para que tengan sentido.
Pon el mío también.
http://www.codeproject.com/Articles/998388/XMLplusplus-version-The-Cplusplus-update-of-my-XML
No hay características de validación XML, pero rápido.