¿Qué analizador XML debo usar en C ++? [cerrado]

344

Tengo documentos XML que necesito analizar y / o necesito construir documentos XML y escribirlos en texto (ya sea 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, C ++ - Preguntas frecuentes para esto. Entonces sí, es un duplicado de otros. No simplemente 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.

Nicol Bolas
fuente
Me gusta tiCpp code.google.com/p/ticpp , los documentos no son geniales (¿todavía?), Pero me encanta la biblioteca, un código limpio y agradable.
Escribí mi propio github.com/igagis/mikroxml
igagis

Respuestas:

679

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:

ingrese la descripción de la imagen aquí

Entonces la primera pregunta es esta: ¿Qué necesitas?

Necesito cumplimiento completo de XML

OK, entonces necesitas procesar XML. No juguete XML, XML real . Debe poder leer y escribir todas las especificaciones XML, no solo los bits bajos y fáciles de analizar. Necesita espacios de nombres, DocTypes, sustitución de entidades, los trabajos. La especificación XML W3C, en su totalidad.

La siguiente pregunta es: ¿Su API debe ajustarse a DOM o SAX?

Necesito 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. Se debe ser el DOM real o el SAX real, en la medida en que C ++ permite.

Has elegido:

Xerces

Esa es tu elección. Es prácticamente el único analizador / escritor XML C ++ que tiene conformidad DOM (y SAX) completa (o tan cerca como lo permite C ++). También tiene soporte XInclude, soporte de 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

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 características, como soporte XInclude (con devoluciones de llamada para que pueda decirle de dónde obtiene el archivo), un reconocedor XPath 1.0, soporte RelaxNG y Schematron (aunque los mensajes de error dejan mucho que desear), y etc.

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 completamente bajo su control o tienen garantizado el uso del "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?

Máximo rendimiento de análisis XML

Su aplicación necesita tomar XML y convertirlo en estructuras de datos C ++ tan rápido como pueda ocurrir esta conversión.

Has elegido:

RapidXML

Este analizador XML es exactamente lo que dice en la lata: XML rápido. Ni siquiera se trata de tirar el archivo a la memoria; cómo eso sucede depende de usted. Lo que sí trata es analizar eso en una serie de estructuras de datos de C ++ a las que puede acceder. Y lo hace tan rápido como se necesita para escanear el archivo byte a byte.

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 los 6 XML básicos), y así sucesivamente. Básicamente, nodos, elementos, atributos y demás.

Además, es un analizador de estilo DOM. Por lo tanto, requiere que lea todo el texto. Sin embargo, lo que no hace es copiar nada de ese texto (generalmente). La forma en que RapidXML obtiene la mayor parte de su velocidad es haciendo referencia a las cadenas en el lugar . Esto requiere más administración de memoria por su parte (debe mantener esa cadena viva mientras RapidXML lo está mirando).

El DOM de RapidXML es básico. Puede obtener valores de cadena para cosas. Puede buscar atributos por nombre. Eso es todo. No hay funciones convenientes para convertir los atributos en otros valores (números, fechas, etc.). Solo tienes cuerdas.

Otra desventaja de RapidXML es que es doloroso escribir XML. Requiere que haga mucha asignación explícita de memoria de nombres de cadena para construir su DOM. Proporciona un tipo de búfer de cadena, pero eso aún requiere mucho trabajo explícito por su parte. Ciertamente es funcional, pero es difícil de usar.

Utiliza la licencia MIT. Es una biblioteca de solo encabezado sin dependencias.

Me importa el rendimiento, pero no tanto

Sí, el rendimiento es importante para ti. Pero tal vez necesites algo un poco menos básico. Quizás 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:

PugiXML

Históricamente, esto sirvió de inspiración para RapidXML. Pero los dos proyectos han divergido, con Pugi ofreciendo más funciones, mientras que RapidXML se centra completamente en la velocidad.

PugiXML ofrece soporte de conversión 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 necesita 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.

Leer documentos enormes

Debe leer documentos que se miden en gigabytes de tamaño. Tal vez los está obteniendo de stdin, siendo alimentado por algún otro proceso. O los estás leyendo de 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 sola vez para poder 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 atrapar. 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 cabría esperar.

El xmlReaderobjeto de LibXML2 es una API de extracción. Usted pide ir al siguiente nodo XML o elemento; no te lo dicen Esto le permite almacenar el contexto como mejor le parezca, para manejar diferentes entidades de una manera mucho más legible en código que un montón de devoluciones de llamada.

Alternativas

Expatriado

Expat es un conocido analizador de C ++ que utiliza una API pull-parser. Fue escrito por James Clark.

Su estado actual es activo. La versión más reciente es 2.2.9, que se lanzó el (2019-09-25).

LlamaXML

Es una implementación de una API de estilo StAX. Es un analizador de extracción, similar al xmlReaderanalizador LibXML2 .

Pero no se ha actualizado desde 2005. Una vez más, 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 colección de elementos mediante propiedades comunes, utilizando una sintaxis estandarizada. Muchas bibliotecas XML ofrecen soporte para XPath.

Hay efectivamente tres opciones aquí:

  • LibXML2 : Proporciona soporte completo para XPath 1.0. Nuevamente, es una API C, por lo que si eso te molesta, hay alternativas.
  • PugiXML : también viene con soporte para XPath 1.0. Como se indicó 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.

Solo haz el trabajo

Entonces, no te importa la corrección de XML. El rendimiento no es un problema para ti. La transmisión es irrelevante. Todo lo que quiere es algo que tenga XML en la memoria y le permita volver a pegarlo en el disco. Lo que te importa es la API.

Desea un analizador XML que sea pequeño, fácil de instalar, trivial de usar y lo suficientemente pequeño como para ser irrelevante para el tamaño de su ejecutable final.

Has elegido:

TinyXML

Puse TinyXML en esta ranura porque es tan fácil de usar como los analizadores XML. Sí, es lento, pero es simple y obvio. Tiene muchas funciones convenientes para convertir atributos, etc.

Escribir XML no es un problema en TinyXML. Simplemente newlevante algunos objetos, adjúntelos, envíe el documento a un std::ostream, y todos estarán felices.

También hay algo de un ecosistema construido alrededor de TinyXML, con una API más amigable para los iteradores, e incluso una implementación de XPath 1.0 en capas.

TinyXML usa la licencia zLib, que es más o menos la licencia MIT con un nombre diferente.

Nicol Bolas
fuente
66
Esto se parece un poco a copiar y pegar. ¿Puedes vincular el documento fuente?
Joel
28
@Joel: con bastante frecuencia cuando alguien responde a su propia pregunta con una buena publicación larga, es porque está siguiendo el espíritu del consejo de Jeff, especialmente porque lo que parece una pregunta regular a menudo se puede cerrar antes de que una buena respuesta pueda ser publicado, si la persona está escribiendo la respuesta en ese mismo momento. Al tomarse un tiempo para preparar una respuesta antes de hacer la pregunta :) Nicol nos está brindando a todos un excelente candidato para Cerrar-> Duplicar preguntas en el futuro.
sarnold
28
@ Joel: Me temo que no puedo. Era solo un documento temporal que copié en Notepad ++. Nunca lo guardé, así que no puedo vincularlo a él;)
Nicol Bolas
66
Vale la pena mencionar la versión más nueva de TinyXML: TinyXML-2 usa una API similar a TinyXML-1 y los mismos casos de prueba enriquecidos. Pero la implementación del analizador se reescribe por completo para que sea más apropiado para su uso en un juego. Utiliza menos memoria, es más rápido y utiliza muy pocas asignaciones de memoria.
johnbakers
66
Me gusta esta pregunta y respuesta, pero me parece demasiado sesgada. ¿No se menciona MSXML y XmlLite? Si la portabilidad de múltiples plataformas es su razón para excluirlas, entonces esto debe mencionarse claramente en la pregunta y respuesta. (De lo contrario, algunas personas podrían terminar eligiendo, por ejemplo, Libxml2 para un proyecto solo de Windows, que
requiere
17

Hay otro enfoque para manejar XML que puede considerar, llamado enlace de datos XML. Especialmente si ya tiene una especificación formal de su vocabulario XML, por ejemplo, en XML Schema.

El enlace de datos XML le permite usar 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 al dominio de su aplicación. Luego trabaja con estos datos llamando a funciones y trabajando con tipos C ++ (int, double, etc.) en lugar de comparar cadenas y analizar texto (que es lo que hace con 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 liviana y libre de dependencia, CodeSynthesis XSD / e .

Boris Kolpackov
fuente
13
No me importa la publicación, pero la política de SO establece que si sugiere algo que escribió, debe mencionar que lo escribió, en aras de una divulgación completa.
Nicol Bolas
@Nicol lo edité en la respuesta.
JBentley
Quizás sea útil esta lista, pero no pude averiguar quiénes son los autores de esa lista (sin divulgación pública, no puedo ver si las descripciones y calificaciones son significativas). Tal vez se pueda ver el grupo de trabajo de enlace de datos del W3C que enumera varias herramientas de enlace de datos que son de dominio público y se usaron para pruebas e informes (divulgación completa: no estoy afiliado a CodeSynthesis, he ayudado a gsoap incluido en el W3C herramientas).
Dr. Alex RE
1

Otra nota sobre Expat: vale la pena mirar para el trabajo de sistemas integrados. Sin embargo, la documentación que es probable que encuentre en la web es antigua e incorrecta. El código fuente en realidad tiene comentarios de nivel de función bastante completos, pero tomará un poco de lectura para que tengan sentido.

punto de ruptura
fuente
0

OK entonces. He creado uno nuevo, ya que ninguno de la lista no era suficiente para mis necesidades.

Beneficios:

  1. Pull-parser Streaming API en el nivel bajo ( Java StAX como )
  2. Excepciones y modos RTTI de soportados
  3. Límite para uso de memoria, soporte para archivos grandes (probado con archivo XMark de 100 mib , la velocidad depende del hardware)
  4. Soporte UNICODE y autodetección para codificación de fuente de entrada
  5. API de alto nivel para leer en estructuras / POCO
  6. API de metaprogramación para escribir y generar XSD a partir de estructuras / POCO con soporte para estructura xml (atributos y etiquetas de anidación) (la generación XSD necesita RTTI, pero solo se puede usar en depuración para hacerlo una vez)
  7. C ++ 11 - GCC y VC ++ 15+

Desventajas

  1. La validación DTD y XSD aún no se ha proporcionado.
  2. Obteniendo XML / XSD por HTTP / HTTPS en progreso, aún no hecho
  3. Nueva biblioteca

Proyecto en casa

Victor Gubin
fuente
1
¿Podría agregar puntos de referencia?
Vadim Peretokin el
-1

En Secured Globe , Inc. usamos 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);
Michael Haephrati
fuente