Jakiego parsera XML powinienem używać w C ++? [Zamknięte]


344

Mam dokumenty XML, które muszę przeanalizować i / lub muszę zbudować dokumenty XML i zapisać je w tekście (pliki lub pamięć). Ponieważ standardowa biblioteka C ++ nie ma biblioteki do tego, czego powinienem użyć?

Uwaga: To ma być ostateczne pytanie w stylu C ++ - FAQ. Tak, to duplikat innych. Nie odpowiedziałem po prostu na te inne pytania, ponieważ zwykle prosiły o coś nieco bardziej szczegółowego. To pytanie jest bardziej ogólne.


Lubię tiCpp code.google.com/p/ticpp , dokumenty nie są jeszcze świetne (jeszcze?), Ale uwielbiam bibliotekę, ładny, czysty kod.

Napisałem własny github.com/igagis/mikroxml
igagis

Odpowiedzi:


679

Podobnie jak w przypadku standardowych kontenerów bibliotecznych, biblioteka, której należy użyć, zależy od potrzeb. Oto wygodny schemat blokowy:

wprowadź opis zdjęcia tutaj

Pierwsze pytanie brzmi: czego potrzebujesz?

Potrzebuję pełnej zgodności z XML

OK, więc musisz przetworzyć XML. Nie zabawki XML, prawdziwy XML. Musisz być w stanie odczytać i zapisać całą specyfikację XML, a nie tylko nisko położone, łatwe do przeanalizowania bity. Potrzebujesz przestrzeni nazw, typów dokumentów, podstawiania encji, prac. Specyfikacja W3C XML w całości.

Następne pytanie brzmi: czy Twój interfejs API musi być zgodny z DOM lub SAX?

Potrzebuję dokładnej zgodności z DOM i / lub SAX

OK, więc naprawdę potrzebujesz interfejsu API, aby był DOM i / lub SAX. Nie może to być po prostu parser wypychający w stylu SAX lub zachowany parser w stylu DOM. To musi być rzeczywisty DOM lub rzeczywisty SAX, do tego stopnia, że C ++ pozwala.

Wybrałeś:

Xerces

To Twój wybór. Jest to właściwie jedyny parser / moduł zapisujący XML C ++, który ma pełną (lub tak bliską, jak pozwala C ++) zgodność DOM i SAX. Ma także obsługę XInclude, obsługę schematu XML i mnóstwo innych funkcji.

Nie ma żadnych rzeczywistych zależności. Korzysta z licencji Apache.

Nie dbam o zgodność z DOM i / lub SAX

Wybrałeś:

LibXML2

LibXML2 oferuje interfejs w stylu C (jeśli naprawdę Ci to przeszkadza, skorzystaj z Xerces), chociaż interfejs jest co najmniej w pewnym stopniu oparty na obiektach i łatwo go zapakować. Zapewnia wiele funkcji, takich jak obsługa XInclude (z oddzwanianiem, dzięki czemu można powiedzieć, skąd pobiera plik), rozpoznawanie XPath 1.0, obsługa RelaxNG i Schematron (choć komunikaty o błędach pozostawiają wiele do życzenia) i itd.

Ma zależność od iconv, ale można ją skonfigurować bez tej zależności. Chociaż oznacza to, że będziesz mieć bardziej ograniczony zestaw możliwych kodowań tekstowych, które może analizować.

Korzysta z licencji MIT.

Nie potrzebuję pełnej zgodności z XML

OK, więc pełna zgodność XML nie ma dla ciebie znaczenia. Twoje dokumenty XML są w pełni pod twoją kontrolą lub masz gwarancję, że użyjesz „podstawowego podzbioru” XML: bez przestrzeni nazw, encji itp.

Co jest dla ciebie ważne? Następne pytanie brzmi: co jest dla Ciebie najważniejsze w pracy nad XML?

Maksymalna wydajność analizowania XML

Twoja aplikacja musi pobrać XML i przekształcić go w struktury danych C ++ tak szybko, jak to możliwe.

Wybrałeś:

RapidXML

Ten parser XML jest dokładnie tym, co jest napisane na puszce: rapid XML. Nawet nie zajmuje się wciąganiem pliku do pamięci; jak to się stanie, zależy od ciebie. Zajmuje się analizowaniem tego w szeregu struktur danych C ++, do których można uzyskać dostęp. I robi to tak szybko, jak potrzeba do skanowania pliku bajt po bajcie.

Oczywiście nie ma czegoś takiego jak darmowy lunch. Jak większość parserów XML, które nie dbają o specyfikację XML, Rapid XML nie dotyka przestrzeni nazw, typów dokumentów, encji (z wyjątkiem encji znakowych i 6 podstawowych XML) i tak dalej. Więc w zasadzie węzły, elementy, atrybuty i tym podobne.

Ponadto jest to parser w stylu DOM. Wymaga to więc przeczytania całego tekstu. Jednak to, czego nie robi, to skopiowanie dowolnego tekstu (zwykle). Sposób, w jaki RapidXML osiąga największą prędkość, polega na odwoływaniu się do ciągów w miejscu . Wymaga to większego zarządzania pamięcią z twojej strony (musisz utrzymywać ten ciąg przy życiu, gdy RapidXML na niego patrzy).

DOM RapidXML jest zupełnie pusty. Możesz uzyskać wartości ciągu dla rzeczy. Możesz wyszukiwać atrybuty według nazwy. O to chodzi. Nie ma żadnych funkcji ułatwiających przekształcenie atrybutów w inne wartości (liczby, daty itp.). Po prostu dostajesz sznurki.

Innym minusem RapidXML jest to, że pisanie XML jest bolesne . Wymaga dużo jawnej alokacji pamięci nazw ciągów w celu zbudowania DOM. Zapewnia rodzaj bufora ciągów, ale wciąż wymaga dużo wyraźnej pracy po twojej stronie. Jest to z pewnością funkcjonalne, ale korzystanie z niego jest uciążliwe.

Korzysta z licencji MIT. Jest to biblioteka tylko nagłówka bez zależności.

Dbam o wydajność, ale nie aż tak bardzo

Tak, wydajność ma dla Ciebie znaczenie. Ale może potrzebujesz czegoś mniej nagiego. Może coś, co może obsłużyć więcej Unicode lub nie wymaga tak dużo zarządzania pamięcią kontrolowanego przez użytkownika. Wydajność jest nadal ważna, ale chcesz czegoś mniej bezpośredniego.

Wybrałeś:

PugiXML

Historycznie było to inspiracją dla RapidXML. Ale oba projekty się rozeszły, Pugi oferuje więcej funkcji, podczas gdy RapidXML koncentruje się całkowicie na szybkości.

PugiXML oferuje obsługę konwersji Unicode, więc jeśli masz jakieś dokumenty UTF-16 i chcesz je przeczytać jako UTF-8, Pugi zapewni. Ma nawet implementację XPath 1.0, jeśli potrzebujesz czegoś takiego.

Ale Pugi jest wciąż dość szybki. Podobnie jak RapidXML, nie ma żadnych zależności i jest rozpowszechniany na licencji MIT.

Czytanie ogromnych dokumentów

Musisz przeczytać dokumenty mierzone w gigabajtach . Może otrzymujesz je ze standardowego źródła, będąc zasilanym przez inny proces. Lub czytasz je z ogromnych plików. Lub cokolwiek. Chodzi o to, że nie musisz od razu czytać całego pliku do pamięci, aby go przetworzyć.

Wybrałeś:

LibXML2

Interfejs API Xerces w stylu SAX będzie działał w tej roli, ale LibXML2 jest tutaj, ponieważ jest nieco łatwiej z nim pracować. Interfejs API w stylu SAX jest interfejsem API typu push: rozpoczyna analizowanie strumienia i po prostu odpala zdarzenia, które należy przechwycić. Jesteś zmuszony zarządzać kontekstem, stanem i tak dalej. Kod odczytujący interfejs API w stylu SAX jest znacznie bardziej rozpowszechniony, niż można by się spodziewać.

xmlReaderObiekt LibXML2 to pull-API. Państwo poprosić , aby przejść do następnego węzła XML lub elementu; nie powiedziano ci. Umożliwia to przechowywanie kontekstu według własnego uznania i obsługę różnych elementów w sposób znacznie bardziej czytelny w kodzie niż kilka wywołań zwrotnych.

Alternatywy

Expat

Expat jest dobrze znanym parserem C ++, który wykorzystuje API parsera pull-parser. Zostało napisane przez Jamesa Clarka.

Jego obecny status jest aktywny. Najnowsza wersja to 2.2.9, która została wydana (2019-09-25).

LlamaXML

Jest to implementacja interfejsu API w stylu StAX. Jest to parser typu pull-parser, podobny do xmlReaderparsera LibXML2 .

Ale nie był aktualizowany od 2005 roku. Więc ponownie, Caveat Emptor.

Obsługa XPath

XPath to system do zapytań o elementy w drzewie XML. Jest to przydatny sposób skutecznego nazywania elementu lub kolekcji elementu według wspólnych właściwości przy użyciu standardowej składni. Wiele bibliotek XML oferuje obsługę XPath.

Istnieją tutaj skutecznie trzy opcje:

  • LibXML2 : Zapewnia pełną obsługę XPath 1.0. Ponownie, jest to C API, więc jeśli ci to przeszkadza, istnieją alternatywy.
  • PugiXML : Posiada również obsługę XPath 1.0. Jak wyżej, jest to bardziej interfejs API C ++ niż LibXML2, więc możesz być z nim wygodniejszy.
  • TinyXML : Nie jest obsługiwany przez XPath, ale istnieje biblioteka TinyXPath, która to zapewnia. TinyXML przechodzi konwersję do wersji 2.0, co znacznie zmienia API, więc TinyXPath może nie działać z nowym API. Podobnie jak sam TinyXML, TinyXPath jest rozpowszechniany na licencji zLib.

Po prostu zrób pracę

Tak więc nie obchodzi Cię poprawność XML. Wydajność nie stanowi dla ciebie problemu. Streaming nie ma znaczenia. Wszystko, czego potrzebujesz, to coś , co przenosi XML do pamięci i pozwala ponownie przykleić go z powrotem na dysk. To , na czym Ci zależy, to API.

Potrzebujesz parsera XML, który będzie mały, łatwy w instalacji, trywialny w użyciu i wystarczająco mały, aby nie miał znaczenia dla ostatecznego rozmiaru pliku wykonywalnego.

Wybrałeś:

TinyXML

Umieściłem TinyXML w tym gnieździe, ponieważ jest on tak prosty w obsłudze jak Braindead, jak parsery XML. Tak, jest wolny, ale prosty i oczywisty. Ma wiele funkcji ułatwiających konwersję atrybutów i tak dalej.

Pisanie XML nie jest problemem w TinyXML. Po prostu newzbierasz niektóre obiekty, łączysz je ze sobą, wysyłasz dokument do std::ostreami wszyscy są zadowoleni.

Jest też coś w rodzaju ekosystemu zbudowanego wokół TinyXML, z API bardziej przyjaznym dla iteratorów, a nawet warstwą implementacji XPath 1.0.

TinyXML korzysta z licencji zLib, która jest mniej więcej licencją MIT o innej nazwie.


6
To wygląda trochę jak kopiuj-wklej. Czy możesz połączyć dokument źródłowy?
Joel

28
@Joel: dość często, gdy ktoś odpowiada na swoje pytanie dobrym, długim postem, dzieje się tak dlatego, że postępuje zgodnie z radą Jeffa - szczególnie dlatego, że coś, co wygląda na takie sobie, może być często zamknięte, zanim dobra odpowiedź będzie w stanie zostać opublikowanym, jeśli dana osoba pisze odpowiedź właśnie wtedy i tam. Poświęcając trochę czasu na przygotowanie odpowiedzi, zanim zadał pytanie :) Nicol zapewnia nam wszystkim doskonałego kandydata na pytania Close-> Duplicate w przyszłości.
sarnold

28
@Jel: Obawiam się, że nie mogę. Był to tylko tymczasowy dokument, z którego skopiowałem w Notepad ++. Nigdy go nie uratowałem, więc nie mogę cię do tego połączyć;)
Nicol Bolas,

6
Warto wspomnieć o nowszej wersji TinyXML: TinyXML-2 używa interfejsu API podobnego do TinyXML-1 i tych samych bogatych przypadków testowych. Ale implementacja parsera została całkowicie przepisana, aby była bardziej odpowiednia do użycia w grze. Zużywa mniej pamięci, jest szybszy i zużywa niewiele alokacji pamięci.
johnbakers

6
Podoba mi się to pytanie i odpowiedź, ale uważam, że jest to również stronnicze. Brak wzmianki o MSXML i XmlLite? Jeśli powodem przenoszenia tych danych jest przenośność na wielu palcach, należy to wyraźnie zaznaczyć w pytaniu i odpowiedzi. (W przeciwnym razie niektóre osoby mogą ostatecznie wybrać np. Libxml2 dla projektu tylko dla systemu Windows, który prosi o bóle głowy, których można łatwo uniknąć.)
Scrontch

17

Istnieje inne podejście do obsługi XML, które warto rozważyć, nazywane wiązaniem danych XML. Zwłaszcza jeśli masz już formalną specyfikację swojego słownictwa XML, na przykład w schemacie XML.

Powiązanie danych XML umożliwia korzystanie z XML bez faktycznego analizowania lub serializacji XML. Kompilator powiązania danych automatycznie generuje cały kod niskiego poziomu i prezentuje przeanalizowane dane jako klasy C ++, które odpowiadają Twojej domenie aplikacji. Następnie pracujesz z tymi danymi, wywołując funkcje i pracując z typami C ++ (int, double, itp.) Zamiast porównywania ciągów i parsowania tekstu (co robisz z interfejsami API niskiego poziomu, takimi jak DOM lub SAX).

Zobacz na przykład napisaną przeze mnie implementację wiązania danych XML o otwartym kodzie źródłowym, CodeSynthesis XSD oraz, w przypadku lżejszej, niezależnej wersji, CodeSynthesis XSD / e .


13
Nie mam nic przeciwko temu postowi, ale zasady SO mówią, że jeśli sugerujesz coś, co napisałeś, powinieneś wspomnieć, że to napisałeś, w celu pełnego ujawnienia.
Nicol Bolas,

@Nicol Zredagowałem to w odpowiedzi.
JBentley,

Być może pomocna jest ta lista, ale nie mogłem dowiedzieć się, kim są autorzy tej listy (bez publicznego ujawnienia nie widzę, czy opisy i oceny są znaczące). Być może można spojrzeć na grupę roboczą do wiązania danych W3C, która wymienia kilka narzędzi do wiązania danych, które są własnością publiczną i zostały wykorzystane do testowania i raportowania (pełne ujawnienie: nie jestem związany z CodeSynthesis, pomogłem gsoap wymienionemu z W3C przybory).
Dr Alex RE

1

Jeszcze jedna uwaga na temat programu Expat: warto przyjrzeć się pracy systemów wbudowanych. Jednak dokumentacja, którą najprawdopodobniej znajdziesz w Internecie, jest starożytna i błędna. Kod źródłowy faktycznie ma dość dokładne komentarze na poziomie funkcji, ale ich zrozumienie zajmie trochę czasu.



0

Okej więc. Stworzyłem nową, ponieważ żadna z list nie zaspokoiła moich potrzeb.

Korzyści:

  1. Pull-parser Streaming API na niskim poziomie ( podobny do Java StAX )
  2. Obsługiwane wyjątki i tryby RTTI
  3. Limit wykorzystania pamięci, obsługa dużych plików (testowane z plikiem XMark 100 mib od, szybkość zależy od sprzętu)
  4. Obsługa UNICODE i automatyczne wykrywanie kodowania źródła wejściowego
  5. Interfejs API wysokiego poziomu do wczytywania struktur / POCO
  6. Metaprogramujący interfejs API do pisania i generowania XSD ze struktur / POCO z obsługą struktury xml (atrybuty i tagi zagnieżdżania) (generowanie XSD wymaga RTTI, ale można go użyć tylko przy debugowaniu, aby zrobić to raz)
  7. C ++ 11 - GCC i VC ++ 15+

Niedogodności:

  1. Sprawdzanie poprawności DTD i XSD nie zostało jeszcze dostarczone
  2. Uzyskiwanie XML / XSD przez HTTP / HTTPS w toku, jeszcze nie zrobione
  3. Nowa biblioteka

Projekt domu


1
Czy możesz dodać testy porównawcze?
Vadim Peretokin

-1

W Secured Globe , Inc. używamy rapidxml . Próbowaliśmy wszystkich innych, ale rapidxml wydaje się być dla nas najlepszym wyborem.

Oto przykład:

 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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.