Teknik untuk parsing XML

11

Saya selalu menemukan XML agak rumit untuk diproses. Saya tidak berbicara tentang menerapkan parser XML: Saya berbicara tentang menggunakan parser berbasis aliran yang ada, seperti parser SAX, yang memproses XML node demi node.

Ya, sangat mudah untuk mempelajari berbagai API untuk parser ini, tetapi setiap kali saya melihat kode yang memproses XML saya selalu merasa agak berbelit-belit. Masalah mendasar tampaknya adalah bahwa dokumen XML secara logis dipisahkan menjadi node individual, namun tipe data dan atributnya sering dipisahkan dari data aktual, kadang-kadang oleh beberapa tingkat sarang. Oleh karena itu, ketika memproses node tertentu secara individual, banyak kondisi tambahan perlu dipertahankan untuk menentukan di mana kita berada dan apa yang perlu kita lakukan selanjutnya.

Misalnya, diberi potongan dari dokumen XML khas:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... Bagaimana saya menentukan kapan saya menemukan simpul teks yang berisi judul buku? Misalkan kita memiliki parser XML sederhana yang bertindak seperti iterator, memberi kita simpul berikutnya dalam dokumen XML setiap kali kita memanggil XMLParser.getNextNode(). Saya pasti menemukan diri saya menulis kode seperti berikut:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

Pada dasarnya, pemrosesan XML dengan cepat berubah menjadi loop besar yang digerakkan oleh mesin negara, dengan banyak variabel status yang digunakan untuk menunjukkan node induk yang kami temukan sebelumnya. Jika tidak, objek tumpukan harus dipertahankan untuk melacak semua tag yang disarangkan. Ini dengan cepat menjadi rawan kesalahan dan sulit untuk dipertahankan.

Sekali lagi, masalahnya adalah bahwa data yang kami minati tidak terkait langsung dengan satu node. Tentu, bisa jadi, jika kita menulis XML seperti:

<book title="Blah blah" author="blah blah" price="15 USD" />

... tapi ini jarang bagaimana XML digunakan dalam kenyataan. Sebagian besar kita memiliki simpul teks sebagai anak-anak dari simpul induk, dan kita perlu melacak simpul induk untuk menentukan apa yang dimaksud dengan simpul teks.

Jadi ... apakah saya melakukan sesuatu yang salah? Apakah ada cara yang lebih baik? Pada titik apakah menggunakan parser berbasis aliran XML menjadi terlalu rumit, sehingga parser DOM yang lengkap menjadi perlu? Saya ingin mendengar dari programmer lain idiom apa yang mereka gunakan saat memproses XML dengan parser berbasis aliran. Haruskah parsing XML berbasis aliran selalu berubah menjadi mesin negara yang besar?

Channel72
sumber
2
jika Anda menggunakan bahasa .net, Anda harus melihat linq ke xml alias XLinq.
Muad'Dib
Terima kasih, saya pikir hanya saya yang punya masalah ini. Terus terang, saya sering menemukan seluruh format XML lebih menjadi penghalang daripada bantuan. Ya, ini memungkinkan seseorang untuk menyimpan banyak data terstruktur dalam file teks kecil. Tetapi jika Anda membutuhkan 20+ kelas untuk membongkar dan memahami masalahnya - tanpa jaminan bahwa Anda tidak mengabaikan sesuatu yang lebih atau kurang penting. Ini seperti kelinci di Cawan Suci Monty Python.
Elise van Looij

Jawaban:

9

Bagi saya, pertanyaannya adalah sebaliknya. Pada titik apa Dokumen XML menjadi begitu rumit, sehingga Anda harus mulai menggunakan SAX daripada DOM?

Saya hanya akan menggunakan SAX untuk aliran data yang sangat besar dan berukuran tak tentu; atau jika perilaku yang ingin dipanggil oleh XML benar-benar didorong oleh peristiwa, dan karena itu mirip SAX.

Contoh yang Anda berikan terlihat sangat mirip DOM bagi saya.

  1. Muat XML
  2. Ekstrak simpul judul dan "lakukan sesuatu dengannya".

EDIT: Saya juga menggunakan SAX untuk stream yang mungkin cacat, tetapi di mana saya ingin membuat perkiraan terbaik untuk mendapatkan data.

Paul Butcher
sumber
2
Saya pikir ini adalah poin yang bagus. Jika Anda mem-parsing dokumen yang terlalu besar untuk DOM maka Anda perlu mempertimbangkan apakah Anda mem-parsing dokumen yang terlalu besar untuk XML
Dean Harding
1
+1: Diberi opsi, saya akan selalu menggunakan DOM. Sayangnya, sepertinya persyaratan desain kami selalu mencakup "kemampuan untuk menangani dokumen ukuran apa pun" dan "harus berkinerja", yang cukup banyak mengesampingkan solusi berbasis DOM.
TMN
3
@ TMN, di dunia ideal yang persyaratannya akan mengesampingkan XML di tempat pertama.
SK-logic
1
@TMN, itu terdengar seperti salah satu dari persyaratan hantu: "Tentu saja semua dokumen kami hanya sekitar 100KB, dan yang terbesar yang kami lihat adalah 1MB, tetapi Anda tidak pernah tahu apa yang akan terjadi di masa depan, jadi kami harus tetap membuka opsi kami. dan buat dokumen-dokumen besar yang tak terhingga "
Paul Butcher
@Paul Butcher, Anda tidak pernah tahu. Maksudku, tumpukan Wikipedia seperti 30GB XML.
Channel72
7

Saya tidak bekerja dengan XML terlalu banyak, sedikit menurut saya, mungkin salah satu cara terbaik untuk mem-parsing XML dengan perpustakaan menggunakan XPath.

Alih-alih melintasi pohon untuk menemukan beberapa node tertentu, Anda memberikan path ke sana. Dalam hal contoh Anda (dalam pseudocode), itu akan menjadi seperti:

books = parent.xpath ("/ book") // Ini akan memberi Anda semua buku node
untuk-setiap buku dalam buku
    title = book.xpath ("/ title / text ()")
    author = book.xpath ("/ author / text ()")
    price = book.xpath ("/ price / text ()")

    // Lakukan sesuatu dengan data

XPath jauh lebih kuat dari itu, Anda dapat mencari menggunakan kondisi (baik pada nilai dan atribut), pilih node tertentu dalam daftar, pindahkan level melalui pohon. Saya sarankan Anda mencari info tentang cara menggunakannya, ini diterapkan di banyak parsing libraries (saya menggunakannya versi .Net Framework dan lxml untuk Python)

Ioachim
sumber
Tidak apa-apa jika Anda bisa tahu dan percaya sebelumnya bagaimana xml terstruktur. Jika Anda tidak tahu apakah, katakanlah, lebar elemen akan ditentukan sebagai atribut simpul atau sebagai simpul atribut di dalam simpul ukuran elemen, maka XPath tidak akan banyak membantu.
Elise van Looij
5

Haruskah parsing XML berbasis aliran selalu berubah menjadi mesin negara yang besar?

Biasanya begitu, ya.

Bagi saya untuk menunjukkan menggunakan parser DOM yang lengkap adalah ketika saya perlu meniru bagian-bagian dari hirarki file dalam memori, misalnya untuk dapat menyelesaikan referensi silang dalam dokumen.

Alexander Gessler
sumber
+1: Mulai dengan DOM. Hindari SAX.
S.Lott
atau dengan vtd-xml
vtd-xml-author
4

Parsing secara umum hanya mengendarai mesin negara, dan parsing XML tidak berbeda. Parsing berbasis aliran selalu merepotkan, saya selalu berakhir dengan membangun semacam tumpukan untuk melacak node leluhur, dan mendefinisikan banyak acara dan semacam dispatcher acara yang memeriksa tag atau lintasan registri dan menyalakan suatu acara jika ada yang cocok. Kode inti cukup ketat, tetapi saya berakhir dengan sejumlah besar penangan acara yang sebagian besar terdiri dari menetapkan nilai simpul teks berikut ke bidang dalam struktur di suatu tempat. Ini bisa menjadi sangat berbulu jika Anda perlu mencampur logika bisnis di sana juga.

Saya akan selalu menggunakan DOM kecuali masalah ukuran atau kinerja mendikte sebaliknya.

TMN
sumber
1

Tidak sepenuhnya agnostik bahasa, tapi saya biasanya membatalkan XML ke dalam objek daripada memikirkan parsing. Hanya waktu untuk khawatir tentang strategi penguraian per se adalah jika Anda memiliki masalah kecepatan.

Wyatt Barnett
sumber
Itu termasuk dalam penguraian. Kecuali XML yang dimaksud adalah output dari serialisasi objek dan Anda memiliki pustaka deserialisasi yang siap pakai. Tapi kemudian pertanyaan ini tidak muncul.
Banyak bahasa / tumpukan yang memiliki perpustakaan deserialisasi siap pakai.
Wyatt Barnett
Ya, jadi apa? Poin saya masih memegang - tidak semua file XML di alam liar datang dalam format seperti itu, dan jika Anda memiliki satu yang tidak, Anda tidak mengajukan pertanyaan ini karena Anda hanya menggunakan perpustakaan deserialization dan tidak parse apa-apa pada Anda sendiri, dari stream atau sebaliknya.
0

Menjadi jauh lebih rumit jika Anda dapat menggunakan XPath. Dan dalam .Net LINQ ke XML abstrak banyak hal yang kurang glamor juga. ( Edit - ini tentu saja memerlukan pendekatan DOM)

Pada dasarnya, jika Anda mengambil pendekatan berbasis aliran (sehingga Anda tidak dapat menggunakan abstraksi yang lebih baik yang memerlukan DOM) Saya pikir itu akan selalu sangat rumit dan saya tidak yakin ada cara untuk mengatasi ini.

Steve
sumber
Jika Anda menggunakan XPath, Anda menggunakan DOM (kecuali jika Anda menggunakannya dengan evaluator XPath buatan sendiri).
TMN
ya, maka komentar saya tentang abstraksi yang membutuhkan DOM ... tapi saya akan menjelaskan, terima kasih!
Steve
0

Jika Anda dapat menemukan parser yang memberi Anda iterator, pernahkah Anda menganggapnya sebagai lexer, dan menggunakan generator mesin negara?

Demi
sumber