Parser XML apa yang harus saya gunakan di C ++? [Tutup]


344

Saya memiliki dokumen XML yang harus saya uraikan dan / atau saya perlu membuat dokumen XML dan menulisnya ke teks (baik file atau memori). Karena pustaka standar C ++ tidak memiliki pustaka untuk ini, apa yang harus saya gunakan?

Catatan: Ini dimaksudkan sebagai pertanyaan definitif, C ++ - FAQ-style untuk ini. Jadi ya, itu adalah duplikat dari orang lain. Saya tidak sekadar menyesuaikan pertanyaan-pertanyaan lain itu karena mereka cenderung meminta sesuatu yang sedikit lebih spesifik. Pertanyaan ini lebih umum.


Saya suka tiCpp code.google.com/p/ticpp , docs tidak bagus (belum?), Tapi saya suka perpustakaan, kode bersih yang bagus.

Jawaban:


679

Sama seperti dengan wadah perpustakaan standar, perpustakaan apa yang harus Anda gunakan tergantung pada kebutuhan Anda. Inilah diagram alur yang nyaman:

masukkan deskripsi gambar di sini

Jadi pertanyaan pertama adalah ini: Apa yang Anda butuhkan?

Saya Membutuhkan Kepatuhan XML Penuh

OK, jadi Anda perlu memproses XML. Bukan mainan XML, XML nyata . Anda harus dapat membaca dan menulis semua spesifikasi XML, bukan hanya bit yang rendah dan mudah diurai. Anda memerlukan Namespace, DocTypes, subtitusi entitas, karya. Spesifikasi W3C XML, secara keseluruhan.

Pertanyaan selanjutnya adalah: Apakah API Anda harus sesuai dengan DOM atau SAX?

Saya Membutuhkan Penampilan DOM dan / atau SAX yang Tepat

OK, jadi Anda benar-benar membutuhkan API untuk menjadi DOM dan / atau SAX. Itu tidak bisa hanya menjadi pengurai gaya SAX, atau pengurai gaya DOM. Itu harus menjadi DOM aktual atau SAX yang sebenarnya, sejauh C ++ memungkinkan.

Kamu telah memilih:

Xerces

Itu pilihanmu. Ini cukup banyak parser / penulis C ++ XML yang memiliki penuh (atau sedekat C ++ memungkinkan) kesesuaian DOM dan SAX. Ini juga memiliki dukungan XInclude, dukungan XML Schema, dan sejumlah fitur lainnya.

Tidak memiliki dependensi nyata. Ini menggunakan lisensi Apache.

Saya Tidak Peduli Tentang DOM dan / atau SAX Conformance

Kamu telah memilih:

LibXML2

LibXML2 menawarkan antarmuka gaya-C (jika itu benar-benar mengganggu Anda, gunakan Xerces), meskipun antarmuka tersebut setidaknya berbasis objek dan mudah dibungkus. Ini menyediakan banyak fitur, seperti dukungan XInclude (dengan panggilan balik sehingga Anda dapat mengetahui dari mana file itu berasal), dukungan XPath 1.0, dukungan RelaxNG dan Schematron (meskipun pesan kesalahan meninggalkan banyak yang diinginkan), dan sebagainya.

Itu memang memiliki ketergantungan pada iconv, tetapi dapat dikonfigurasi tanpa ketergantungan itu. Meskipun itu berarti bahwa Anda akan memiliki seperangkat penyandian teks yang lebih terbatas, ia dapat diuraikan.

Ini menggunakan lisensi MIT.

Saya Tidak Membutuhkan Kepatuhan XML Penuh

OK, kepatuhan XML yang begitu lengkap tidak masalah bagi Anda. Dokumen XML Anda sepenuhnya berada di bawah kendali Anda atau dijamin untuk menggunakan "subset dasar" dari XML: tidak ada ruang nama, entitas, dll.

Jadi apa yang penting bagimu? Pertanyaan selanjutnya adalah: Apa hal terpenting bagi Anda dalam pekerjaan XML Anda?

Kinerja Parsing XML Maksimum

Aplikasi Anda perlu mengambil XML dan mengubahnya menjadi struktur data C ++ secepat konversi ini mungkin terjadi.

Kamu telah memilih:

RapidXML

Parser XML ini persis seperti yang tertulis di kaleng: XML cepat. Bahkan tidak berurusan dengan menarik file ke memori; bagaimana itu terjadi terserah Anda. Apa yang dikerjakannya adalah menguraikannya menjadi serangkaian struktur data C ++ yang dapat Anda akses. Dan ia melakukan ini secepat yang diperlukan untuk memindai file byte demi byte.

Tentu saja, tidak ada yang namanya makan siang gratis. Seperti kebanyakan parser XML yang tidak peduli dengan spesifikasi XML, XML cepat tidak menyentuh ruang nama, DocTypes, entitas (dengan pengecualian entitas karakter dan 6 yang XML dasar), dan sebagainya. Jadi pada dasarnya node, elemen, atribut, dan semacamnya.

Juga, ini adalah parser gaya DOM. Jadi itu mengharuskan Anda membaca semua teks. Namun, apa yang tidak dilakukannya adalah menyalin teks itu (biasanya). Cara RapidXML mendapatkan sebagian besar kecepatannya adalah dengan merujuk pada string di tempat . Ini membutuhkan lebih banyak manajemen memori di pihak Anda (Anda harus menjaga agar string tetap hidup saat RapidXML melihatnya).

RapidXML's DOM kosong. Anda bisa mendapatkan nilai string untuk berbagai hal. Anda dapat mencari atribut berdasarkan nama. Itu saja. Tidak ada fungsi kenyamanan untuk mengubah atribut menjadi nilai lain (angka, tanggal, dll). Anda hanya mendapatkan string.

Satu kelemahan lain dengan RapidXML adalah menyakitkan untuk menulis XML. Ini mengharuskan Anda untuk melakukan banyak alokasi memori eksplisit dari nama string untuk membangun DOM-nya. Itu memang menyediakan semacam buffer string, tapi itu masih membutuhkan banyak kerja eksplisit di pihak Anda. Ini memang fungsional, tetapi sulit digunakan.

Ini menggunakan lisensi MIT. Ini adalah perpustakaan hanya header yang tidak memiliki dependensi.

Saya Peduli Tentang Kinerja Tapi Tidak Cukup Banyak

Ya, kinerja penting bagi Anda. Tapi mungkin Anda perlu sesuatu yang sedikit lebih sederhana. Mungkin sesuatu yang dapat menangani lebih banyak Unicode, atau tidak memerlukan begitu banyak manajemen memori yang dikontrol pengguna. Kinerja masih penting, tetapi Anda menginginkan sesuatu yang sedikit kurang langsung.

Kamu telah memilih:

PugiXML

Secara historis, ini berfungsi sebagai inspirasi untuk RapidXML. Tetapi kedua proyek telah menyimpang, dengan Pugi menawarkan lebih banyak fitur, sementara RapidXML berfokus sepenuhnya pada kecepatan.

PugiXML menawarkan dukungan konversi Unicode, jadi jika Anda memiliki beberapa dokumen UTF-16 dan ingin membacanya sebagai UTF-8, Pugi akan menyediakannya. Bahkan memiliki implementasi XPath 1.0, jika Anda memerlukan hal semacam itu.

Namun Pugi masih cukup cepat. Seperti RapidXML, ia tidak memiliki dependensi dan didistribusikan di bawah Lisensi MIT.

Membaca Dokumen Besar

Anda perlu membaca dokumen yang diukur dalam ukuran gigabyte . Mungkin Anda mendapatkannya dari stdin, diberi makan oleh beberapa proses lain. Atau Anda membacanya dari file besar. Atau terserah. Intinya, yang Anda butuhkan adalah tidak harus membaca seluruh file ke dalam memori sekaligus untuk memprosesnya.

Kamu telah memilih:

LibXML2

API SAX-style Xerces akan bekerja dalam kapasitas ini, tetapi LibXML2 ada di sini karena itu sedikit lebih mudah untuk dikerjakan. API SAX-style adalah push-API: API mulai mengurai aliran dan hanya memadamkan peristiwa yang harus Anda tangkap. Anda dipaksa untuk mengelola konteks, keadaan, dan sebagainya. Kode yang bertuliskan API gaya SAX jauh lebih tersebar daripada yang diharapkan.

Objek LibXML2 xmlReaderadalah pull-API. Anda bertanya untuk pergi ke simpul atau elemen XML berikutnya; kamu tidak diberitahu. Ini memungkinkan Anda untuk menyimpan konteks sesuai keinginan Anda, untuk menangani entitas yang berbeda dengan cara yang jauh lebih mudah dibaca dalam kode daripada sekelompok panggilan balik.

Alternatif

Expat

Expat adalah parser C ++ yang terkenal yang menggunakan API pull-parser. Itu ditulis oleh James Clark.

Statusnya saat ini aktif. Versi terbaru adalah 2.2.9, yang dirilis pada (2019-09-25).

LlamaXML

Ini adalah implementasi API gaya StAX. Ini adalah parser tarik, mirip dengan xmlReaderparser LibXML2 .

Tapi itu belum diperbarui sejak 2005. Jadi sekali lagi, Caveat Emptor.

Dukungan XPath

XPath adalah sistem untuk elemen permintaan dalam pohon XML. Ini adalah cara praktis untuk secara efektif menamai elemen atau kumpulan elemen dengan properti umum, menggunakan sintaksis terstandarisasi. Banyak perpustakaan XML menawarkan dukungan XPath.

Ada tiga pilihan di sini:

  • LibXML2 : Ini menyediakan dukungan penuh XPath 1.0. Sekali lagi, ini adalah API C, jadi jika itu mengganggu Anda, ada alternatifnya.
  • PugiXML : Muncul dengan dukungan XPath 1.0 juga. Seperti di atas, ini lebih merupakan C ++ API daripada LibXML2, jadi Anda mungkin lebih nyaman dengannya.
  • TinyXML : Ini tidak datang dengan dukungan XPath, tetapi ada perpustakaan TinyXPath yang menyediakannya. TinyXML sedang mengalami konversi ke versi 2.0, yang secara signifikan mengubah API, sehingga TinyXPath mungkin tidak berfungsi dengan API baru. Seperti TinyXML sendiri, TinyXPath didistribusikan di bawah lisensi zLib.

Selesaikan Pekerjaan

Jadi, Anda tidak peduli tentang kebenaran XML. Kinerja bukan masalah bagi Anda. Streaming tidak relevan. Yang Anda inginkan adalah sesuatu yang memasukkan XML ke dalam memori dan memungkinkan Anda untuk memasangnya kembali ke disk. Yang Anda pedulikan adalah API.

Anda menginginkan parser XML yang berukuran kecil, mudah dipasang, sepele untuk digunakan, dan cukup kecil agar tidak relevan dengan ukuran akhirnya yang dapat dieksekusi.

Kamu telah memilih:

TinyXML

Saya menempatkan TinyXML di slot ini karena ini adalah tentang braindead yang mudah digunakan seperti parser XML. Ya, lambat, tetapi sederhana dan jelas. Ini memiliki banyak fungsi kenyamanan untuk mengkonversi atribut dan sebagainya.

Menulis XML tidak ada masalah di TinyXML. Anda hanya newmembuat beberapa objek, melampirkannya bersama-sama, mengirim dokumen ke std::ostream, dan semua orang senang.

Ada juga sesuatu dari ekosistem yang dibangun di sekitar TinyXML, dengan API yang lebih ramah-iterator, dan bahkan implementasi XPath 1.0 berlapis di atasnya.

TinyXML menggunakan lisensi zLib, yang kurang lebih merupakan Lisensi MIT dengan nama yang berbeda.


6
Ini terlihat seperti copy-paste. Bisakah Anda menautkan dokumen sumber?
Joel

28
@ Joel: cukup sering ketika seseorang menjawab pertanyaan mereka sendiri dengan posting panjang yang baik, itu karena mereka mengikuti semangat saran Jeff - terutama karena apa yang tampak seperti pertanyaan biasa-biasa saja dapat ditutup sebelum jawaban yang baik dapat diposting, jika orang itu menulis jawaban saat itu juga. Dengan meluangkan waktu untuk menyiapkan jawaban sebelum dia mengajukan pertanyaan :) Nicol memberi kita semua kandidat yang bagus untuk Close-> Duplikat pertanyaan di masa depan.
sarnold

28
@ Joel: Saya khawatir saya tidak bisa. Itu hanya dokumen sementara yang saya salin dari di Notepad ++. Saya tidak pernah menyimpannya, jadi saya tidak dapat menautkan Anda ke sana;)
Nicol Bolas

6
Mungkin patut disebutkan versi TinyXML yang lebih baru: TinyXML-2 menggunakan API yang mirip dengan TinyXML-1 dan kotak uji kaya yang sama. Tetapi implementasi parser sepenuhnya ditulis ulang untuk membuatnya lebih tepat untuk digunakan dalam permainan. Menggunakan lebih sedikit memori, lebih cepat, dan menggunakan alokasi memori jauh lebih sedikit.
johnbakers

6
Saya suka pertanyaan dan jawaban ini, tetapi merasa terlalu bias-Unix. Tidak disebutkan tentang MSXML dan XmlLite? Jika portabilitas multi-paltform adalah alasan Anda untuk mengecualikan itu, maka ini harus secara jelas disebutkan dalam pertanyaan dan jawaban. (Kalau tidak, beberapa orang mungkin akhirnya memilih mis. Libxml2 untuk proyek khusus Windows, yang meminta sakit kepala yang bisa dengan mudah dihindari.)
Scrontch

17

Ada pendekatan lain untuk menangani XML yang mungkin ingin Anda pertimbangkan, disebut XML data binding. Terutama jika Anda sudah memiliki spesifikasi formal kosa kata XML Anda, misalnya, dalam XML Schema.

Pengikatan data XML memungkinkan Anda untuk menggunakan XML tanpa benar-benar melakukan parsing atau serialisasi XML. Compiler pengikatan data otomatis membuat semua kode tingkat rendah dan menyajikan data yang diurai sebagai kelas C ++ yang sesuai dengan domain aplikasi Anda. Anda kemudian bekerja dengan data ini dengan memanggil fungsi, dan bekerja dengan tipe C ++ (int, double, dll) alih-alih membandingkan string dan teks parsing (yang Anda lakukan dengan API akses XML tingkat rendah seperti DOM atau SAX).

Lihat, misalnya, implementasi pengikatan data XML sumber terbuka yang saya tulis, CodeSynthesis XSD dan, untuk versi yang lebih ringan, bebas ketergantungan, CodeSynthesis XSD / e .


13
Saya tidak keberatan dengan pos tersebut, tetapi kebijakan SO menyatakan bahwa jika Anda menyarankan sesuatu yang Anda tulis, Anda harus menyebutkan bahwa Anda menulisnya, untuk kepentingan pengungkapan penuh.
Nicol Bolas

@Nicol saya mengeditnya menjadi jawabannya.
JBentley

Mungkin membantu daftar ini tetapi saya tidak dapat menemukan siapa penulis daftar itu (tanpa pengungkapan publik saya tidak dapat melihat apakah deskripsi dan peringkatnya bermakna). Mungkin orang dapat melihat kelompok kerja pengikatan data W3C yang mencantumkan beberapa alat pengikatan data yang berada dalam domain publik dan digunakan untuk pengujian dan pelaporan (pengungkapan penuh: Saya tidak berafiliasi dengan CodeSynthesis, saya telah membantu melihat daftar dengan W3C alat).
Dr. Alex RE

1

Satu catatan lain tentang Expat: ada baiknya mencari pekerjaan sistem tertanam. Namun, dokumentasi yang mungkin Anda temukan di web adalah kuno dan salah. Kode sumber sebenarnya memiliki komentar tingkat fungsi yang cukup menyeluruh, tetapi perlu beberapa pertimbangan bagi mereka untuk masuk akal.



0

Baiklah kalau begitu. Saya telah membuat yang baru, karena tidak ada daftar yang tidak memenuhi kebutuhan saya.

Manfaat:

  1. Pull-parser Streaming API pada level rendah ( seperti Java StAX )
  2. Pengecualian dan mode RTTI yang didukung
  3. Batas penggunaan memori, dukungan untuk file besar (diuji dengan file 100Mib XMark dari, kecepatan tergantung pada perangkat keras)
  4. Dukungan UNICODE, dan deteksi otomatis untuk pengkodean sumber input
  5. API tingkat tinggi untuk membaca struktur / POCO
  6. Meta-programming API untuk menulis dan menghasilkan XSD dari structure / POCO dengan dukungan untuk struktur xml (atribut dan tag bersarang) (generasi XSD membutuhkan RTTI, tetapi dapat digunakan hanya pada debug untuk membuatnya sekali)
  7. C ++ 11 - GCC dan VC ++ 15+

Kekurangan:

  1. Validasi DTD dan XSD belum tersedia
  2. Memperoleh XML / XSD melalui HTTP / HTTPS sedang berlangsung, belum selesai
  3. Perpustakaan baru

Proyek rumah


1
Bisakah Anda menambahkan tolok ukur?
Vadim Peretokin

-1

Di Secured Globe , Inc. kami menggunakan quickxml . Kami sudah mencoba yang lain tetapi rapidxml tampaknya menjadi pilihan terbaik bagi kami.

Berikut ini sebuah contoh:

 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);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.