Quale parser XML dovrei usare in C ++? [chiuso]


344

Ho documenti XML che devo analizzare e / o ho bisogno di creare documenti XML e scriverli in testo (file o memoria). Poiché la libreria standard C ++ non ha una libreria per questo, cosa dovrei usare?

Nota: questa è una domanda definitiva in stile C ++ - FAQ per questo. Quindi sì, è un duplicato di altri. Non mi sono semplicemente appropriato quelle altre domande perché tendevano a chiedere qualcosa di leggermente più specifico. Questa domanda è più generica.


Mi piace tiCpp code.google.com/p/ticpp , i documenti non sono fantastici (ancora?), Ma adoro la libreria, un bel codice pulito.

Risposte:


679

Proprio come con i contenitori di librerie standard, quale libreria si dovrebbe usare dipende dalle proprie esigenze. Ecco un diagramma di flusso conveniente:

inserisci qui la descrizione dell'immagine

Quindi la prima domanda è questa: di cosa hai bisogno?

Ho bisogno della piena conformità XML

OK, quindi è necessario elaborare XML. Non un giocattolo XML, un vero XML. Devi essere in grado di leggere e scrivere tutte le specifiche XML, non solo i bit bassi e facili da analizzare. Hai bisogno di spazi dei nomi, DocTypes, sostituzione delle entità, opere. La specifica XML del W3C, nella sua interezza.

La domanda successiva è: l'API deve essere conforme a DOM o SAX?

Ho bisogno di conformità esatta DOM e / o SAX

OK, quindi hai davvero bisogno che l'API sia DOM e / o SAX. Non può essere solo un parser push in stile SAX o un parser mantenuto in stile DOM. Essa deve essere DOM reale o il SAX reale, nella misura in cui C ++ consente.

Tu hai scelto:

Xerces

Questa e 'la tua scelta. È praticamente l'unico parser / writer XML C ++ che ha piena (o quasi quanto C ++ consente) conformità DOM e SAX. Ha anche il supporto XInclude, il supporto XML Schema e una pletora di altre funzionalità.

Non ha dipendenze reali. Utilizza la licenza Apache.

Non mi interessa la conformità DOM e / o SAX

Tu hai scelto:

libxml2

LibXML2 offre un'interfaccia in stile C (se questo ti disturba davvero, usa Xerces), sebbene l'interfaccia sia almeno un po 'basata sugli oggetti e facilmente racchiusa. Fornisce molte funzionalità, come il supporto XInclude (con callback in modo da poterlo dire da dove ottiene il file), un riconoscitore XPath 1.0, supporto RelaxNG e Schematron (anche se i messaggi di errore lasciano molto a desiderare), e così via.

Ha una dipendenza da iconv, ma può essere configurato senza quella dipendenza. Ciò significa che avrai un set più limitato di possibili codifiche di testo che può analizzare.

Utilizza la licenza MIT.

Non ho bisogno della piena conformità XML

OK, quindi la piena conformità XML non conta per te. I tuoi documenti XML sono completamente sotto il tuo controllo o sono garantiti per utilizzare il "sottoinsieme di base" di XML: nessuno spazio dei nomi, entità, ecc.

Quindi cosa ti importa? La domanda successiva è: qual è la cosa più importante per te nel tuo lavoro XML?

Prestazioni massime di analisi XML

La tua applicazione deve prendere XML e trasformarlo in strutture di dati C ++ il più rapidamente possibile.

Tu hai scelto:

RapidXML

Questo parser XML è esattamente ciò che dice sulla confezione: XML rapido. Non si occupa nemmeno di estrarre il file in memoria; come succede dipende da te. Ciò di cui si occupa è analizzarlo in una serie di strutture di dati C ++ a cui è possibile accedere. E lo fa con la stessa velocità necessaria per scansionare il file byte per byte.

Certo, non esiste un pranzo gratis. Come la maggior parte dei parser XML che non si preoccupano delle specifiche XML, Rapid XML non tocca spazi dei nomi, DocTypes, entità (ad eccezione delle entità carattere e delle 6 XML di base) e così via. Quindi fondamentalmente nodi, elementi, attributi e simili.

Inoltre, è un parser in stile DOM. Quindi richiede di leggere tutto il testo. Tuttavia, ciò che non fa è copiare qualsiasi di quel testo (di solito). Il modo in cui RapidXML ottiene la massima velocità è facendo riferimento alle stringhe sul posto . Ciò richiede una maggiore gestione della memoria da parte dell'utente (è necessario mantenere viva quella stringa mentre RapidXML la sta guardando).

Il DOM di RapidXML è bare-bones. Puoi ottenere valori stringa per cose. Puoi cercare gli attributi per nome. Questo è tutto. Non ci sono funzioni utili per trasformare gli attributi in altri valori (numeri, date, ecc.). Ottieni solo stringhe.

Un altro aspetto negativo di RapidXML è che è doloroso scrivere XML. Richiede molta allocazione di memoria esplicita dei nomi delle stringhe per costruire il suo DOM. Fornisce una sorta di buffer di stringhe, ma ciò richiede ancora molto lavoro esplicito da parte tua. È certamente funzionale, ma è un dolore da usare.

Utilizza la licenza MIT. È una libreria di sola intestazione senza dipendenze.

Mi preoccupo delle prestazioni ma non abbastanza

Sì, le prestazioni contano per te. Ma forse hai bisogno di qualcosa di meno ossa nude. Forse qualcosa che può gestire più Unicode o che non richiede così tanta gestione della memoria controllata dall'utente. Le prestazioni sono ancora importanti, ma vuoi qualcosa di un po 'meno diretto.

Tu hai scelto:

PugiXML

Storicamente, ciò ha ispirato RapidXML. Ma i due progetti sono divergenti, con Pugi che offre più funzionalità, mentre RapidXML si concentra interamente sulla velocità.

PugiXML offre il supporto per la conversione Unicode, quindi se hai in giro alcuni documenti UTF-16 e vuoi leggerli come UTF-8, Pugi fornirà. Ha anche un'implementazione di XPath 1.0, se hai bisogno di quel genere di cose.

Ma Pugi è ancora abbastanza veloce. Come RapidXML, non ha dipendenze ed è distribuito sotto la licenza MIT.

Leggere documenti enormi

Devi leggere documenti misurati in gigabyte . Forse le stai ottenendo dallo stdin, alimentato da qualche altro processo. Oppure li stai leggendo da file di grandi dimensioni. O qualunque cosa. Il punto è che ciò di cui hai bisogno è non farlo dover leggere l'intero file in memoria tutto in una volta per poterlo elaborare.

Tu hai scelto:

libxml2

L'API in stile SAX di Xerces funzionerà con questa capacità, ma LibXML2 è qui perché è un po 'più facile da lavorare. Un'API in stile SAX è un'API push: inizia l'analisi di uno stream e genera eventi che devi catturare. Sei costretto a gestire il contesto, lo stato e così via. Il codice che legge un'API in stile SAX è molto più diffuso di quanto si possa sperare.

L' xmlReaderoggetto di LibXML2 è un'API pull. Si chiede di passare al nodo o all'elemento XML successivo; non ti è stato detto. Ciò ti consente di archiviare il contesto come ritieni opportuno, di gestire entità diverse in un modo molto più leggibile nel codice rispetto a una serie di callback.

alternative

Expat

Expat è un noto parser C ++ che utilizza un'API pull-parser. È stato scritto da James Clark.

Lo stato corrente è attivo. La versione più recente è la 2.2.9, rilasciata il (25-09-2019).

LlamaXML

È un'implementazione di un'API in stile StAX. È un pull-parser, simile a quello di LibXML2xmlReader parser .

Ma non è stato aggiornato dal 2005. Quindi, ancora, Caveat Emptor.

Supporto XPath

XPath è un sistema per interrogare elementi all'interno di un albero XML. È un modo pratico per nominare in modo efficace un elemento o una raccolta di elementi con proprietà comuni, usando una sintassi standardizzata. Molte librerie XML offrono supporto XPath.

Ci sono effettivamente tre scelte qui:

  • LibXML2 : fornisce il supporto completo per XPath 1.0. Ancora una volta, si tratta di un'API C, quindi se questo ti disturba, ci sono alternative.
  • PugiXML : viene fornito anche con il supporto XPath 1.0. Come sopra, è più un'API C ++ che LibXML2, quindi potresti sentirti più a tuo agio.
  • TinyXML : non viene fornito con il supporto XPath, ma è disponibile la libreria TinyXPath . TinyXML sta subendo una conversione alla versione 2.0, che modifica significativamente l'API, quindi TinyXPath potrebbe non funzionare con la nuova API. Come TinyXML stesso, TinyXPath è distribuito sotto la licenza zLib.

Basta avere il lavoro fatto

Quindi, non ti interessa la correttezza XML. Le prestazioni non sono un problema per te. Lo streaming è irrilevante. Tutto quello che vuoi è qualcosa che metta in memoria l'XML e ti permetta di incollarlo di nuovo sul disco. Quello che ti interessa è l'API.

Vuoi un parser XML che sia piccolo, facile da installare, banale da usare e abbastanza piccolo da essere irrilevante per le dimensioni del tuo eseguibile finale.

Tu hai scelto:

TinyXML

Ho inserito TinyXML in questo slot perché è semplice da usare quanto i parser XML. Sì, è lento, ma è semplice ed evidente. Ha molte funzioni utili per convertire gli attributi e così via.

Scrivere XML non è un problema in TinyXML. Basta solo newalcuni oggetti, attaccarli insieme, inviare il documento a un std::ostreame tutti sono felici.

C'è anche qualcosa di un ecosistema costruito attorno a TinyXML, con un'API più intuitiva e persino un'implementazione XPath 1.0 sovrapposta.

TinyXML utilizza la licenza zLib, che è più o meno la licenza MIT con un nome diverso.


6
Sembra un po 'un copia-incolla. Puoi collegare il documento di origine?
Gioele il

28
@Joel: abbastanza spesso quando qualcuno risponde alla propria domanda con un buon post lungo, è perché stanno seguendo lo spirito del consiglio di Jeff - specialmente perché quella che sembra una domanda così spesso può essere chiusa prima che una buona risposta possa essere pubblicato, se la persona sta scrivendo la risposta in quel momento. Prendendo un po 'di tempo per preparare una risposta prima di porre la domanda :) Nicol ci fornisce a tutti un eccellente candidato per domande chiuse in futuro.
sarnold,

28
@Joel: temo di non poterlo fare. Era solo un documento temporaneo da cui ho copiato in Notepad ++. Non l'ho mai salvato, quindi non posso collegarti ad esso;)
Nicol Bolas,

6
Vale la pena menzionare la versione più recente di TinyXML: TinyXML-2 utilizza un'API simile a TinyXML-1 e gli stessi ricchi casi di test. Ma l'implementazione del parser è completamente riscritta per renderlo più appropriato per l'uso in un gioco. Utilizza meno memoria, è più veloce e utilizza pochissime allocazioni di memoria.
johnbakers,

6
Mi piace questa domanda e risposta, ma la trovo troppo distorta da Unix. Nessuna menzione di MSXML e XmlLite? Se la portabilità multi-paltform è la ragione per escluderli, questo dovrebbe essere chiaramente menzionato nella domanda e risposta. (Altrimenti alcune persone potrebbero finire per scegliere, ad esempio, Libxml2 per un progetto solo per Windows, che richiede mal di testa che avrebbe potuto essere facilmente evitato.)
Scrontch

17

Esiste un altro approccio alla gestione di XML che potresti prendere in considerazione, chiamato associazione dati XML. Soprattutto se hai già una specifica formale del tuo vocabolario XML, ad esempio, in XML Schema.

L'associazione di dati XML consente di utilizzare XML senza eseguire alcuna analisi o serializzazione XML. Un compilatore di associazione dati genera automaticamente tutto il codice di basso livello e presenta i dati analizzati come classi C ++ che corrispondono al dominio dell'applicazione. Quindi si lavora con questi dati chiamando le funzioni e lavorando con i tipi C ++ (int, double, ecc.) Invece di confrontare stringhe e analizzare il testo (che è ciò che si fa con API di accesso XML di basso livello come DOM o SAX).

Vedi, ad esempio, un'implementazione di associazione di dati XML open source che ho scritto, CodeSynthesis XSD e, per una versione più leggera e senza dipendenze, CodeSynthesis XSD / e .


13
Non mi dispiace il post, ma la politica SO afferma che se suggerisci qualcosa che hai scritto, dovresti menzionare che l'hai scritto, nell'interesse della piena divulgazione.
Nicol Bolas,

@Nicol L'ho modificato nella risposta.
JBentley,

Forse questo elenco è utile ma non sono riuscito a scoprire chi sono gli autori di tale elenco (senza divulgazione pubblica non riesco a vedere se le descrizioni e le valutazioni sono significative). Forse si può guardare al gruppo di lavoro di associazione dei dati del W3C che elenca diversi strumenti di associazione dei dati che sono di dominio pubblico e sono stati usati per test e report (divulgazione completa: non sono affiliato con CodeSynthesis, ho aiutato gsoap elencato con il W3C utensili).
Dr. Alex RE,

1

Un'altra nota su Expat: vale la pena cercare il lavoro dei sistemi integrati. Tuttavia, la documentazione che probabilmente troverai sul web è antica e sbagliata. Il codice sorgente in realtà ha commenti a livello di funzione abbastanza approfonditi, ma ci vorrà un po 'di lettura per avere un senso.



0

Va bene allora. Ne ho creato uno nuovo, dal momento che nessuno dell'elenco non statisfy i miei bisogni.

Benefici:

  1. API di streaming pull-parser a basso livello ( come Java StAX )
  2. Eccezioni e modalità RTTI supportate
  3. Limite per l'utilizzo della memoria, supporto per file di grandi dimensioni (testato con file XMark da 100 mib , la velocità dipende dall'hardware)
  4. Supporto UNICODE e rilevamento automatico per la codifica della sorgente di input
  5. API di alto livello per la lettura in strutture / POCO
  6. API di meta-programmazione per scrivere e generare XSD da strutture / POCO con supporto per la struttura xml (attributi e tag di annidamento) (la generazione XSD necessita di RTTI, ma può essere utilizzata solo sul debug per eseguirla una volta)
  7. C ++ 11 - GCC e VC ++ 15+

svantaggi:

  1. Convalida DTD e XSD non ancora fornita
  2. Ottenere XML / XSD da HTTP / HTTPS in corso, non ancora fatto
  3. Nuova biblioteca

Casa del progetto


1
Potresti aggiungere benchmark?
Vadim Peretokin,

-1

Nel Secured Globe , Inc. utilizziamo rapidxml . Abbiamo provato tutti gli altri, ma rapidxml sembra essere la scelta migliore per noi.

Ecco un esempio:

 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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.