Normalisasi di DOM parsing dengan java - bagaimana cara kerjanya?

240

Saya melihat baris di bawah ini dalam kode untuk parser DOM di tutorial ini .

doc.getDocumentElement().normalize();

Mengapa kita melakukan normalisasi ini?
aku membaca dokumen tetapi saya tidak bisa mengerti sepatah kata pun.

Letakkan semua node Teks di kedalaman penuh sub-pohon di bawah Node ini

Oke, lalu bisakah seseorang menunjukkan kepada saya (lebih disukai dengan gambar) seperti apa pohon ini?

Adakah yang bisa menjelaskan mengapa diperlukan normalisasi?
Apa yang terjadi jika kita tidak menormalkan kembali?

Penggiling apel
sumber
Terlepas dari pertanyaan Anda, harap baca catatan pada contoh: "DOM Parser lambat dan akan menghabiskan banyak memori saat memuat dokumen XML yang berisi banyak data. Harap pertimbangkan SAX parser sebagai solusi untuk itu, SAX lebih cepat daripada DOM dan menggunakan lebih sedikit memori. " .
wulfgarpro
3
@ wulfgar.pro - Saya mengerti apa yang Anda katakan. Tapi, saya ingin memahami hal-hal yang saya tanyakan dalam pertanyaan. Saya juga akan melakukan SAX parsing segera.
Apple Grinder
Mencari di google untuk "menormalkan xml" memberikan beberapa hasil yang tampaknya bermanfaat. Sepertinya mirip dengan normalisasi dalam database.
Apple Grinder
2
@ EJP - umm ... masih belum jelas karena saya tidak tahu xml secara mendalam dan saya hanya membaca beberapa halaman pengantar di atasnya. BTW, jangan salah paham, Anda melakukan persis seperti yang dilakukan oleh penulis dokumen - menggunakan kata-kata kompleks alih-alih bahasa Inggris biasa (polos sebagai staf tombak = mudah dimengerti). Kata-kata sederhana pertama dan jargon kemudian lebih baik bagi saya.
Apple Grinder
7
Sampai tulisan ini dibuat, situs web yang dirujuk sedang mereferensikan pos SO ini. Otak saya hanya melempar kesalahan ketergantungan.
chessofnerd

Jawaban:

366

Kalimat selanjutnya adalah:

di mana hanya struktur (mis. elemen, komentar, instruksi pemrosesan, bagian CDATA, dan referensi entitas) yang memisahkan simpul teks, yaitu tidak ada simpul teks yang berdekatan atau simpul teks kosong.

Ini pada dasarnya berarti elemen XML berikut

<foo>hello 
wor
ld</foo>

dapat direpresentasikan seperti ini dalam simpul denormalized:

Element foo
    Text node: ""
    Text node: "Hello "
    Text node: "wor"
    Text node: "ld"

Ketika dinormalisasi, simpul akan terlihat seperti ini

Element foo
    Text node: "Hello world"

Dan hal yang sama berlaku untuk atribut:, <foo bar="Hello world"/>komentar, dll.

JB Nizet
sumber
2
Aha! jauh lebih jelas sekarang. Saya tidak tahu tentang struktur data (???) dan node. Tetapi saya melihat sekilas struktur pohon dan, saya kira komputer dapat menyimpan "halo dunia" seperti yang Anda sarankan. Apakah itu benar ?
Apple Grinder
9
Anda perlu mempelajari dasar-dasar tentang DOM. Ya, DOM mewakili dokumen XML sebagai pohon. Dan di pohon, Anda memiliki simpul akar yang memiliki simpul anak, setiap simpul anak juga memiliki simpul anak, dll. Itulah yang dimaksud pohon. Elemen adalah sejenis simpul, dan TextNode adalah jenis simpul lainnya.
JB Nizet
7
Terima kasih JB Nizet. Tidak bisa memberi tahu Anda betapa leganya saya setelah mendapatkan arahan.
Apple Grinder
2
@ user2043553, baris baru sebenarnya adalah titik di sana. Tanpa baris baru, Anda tidak akan melihat perbedaannya. Jika Anda seharusnya tidak mengerti: Normalisasi "mengoreksi" XML sehingga satu tag ditafsirkan sebagai satu elemen. Jika Anda tidak melakukan itu, mungkin saja baris baru ini ditafsirkan sebagai pembatas antara beberapa elemen dari tipe yang sama (resp. Dalam tag yang sama).
Stacky
1
@ Stacky, dalam contoh ada dua baris baru, mereka tidak ditampilkan setelah dinormalisasi dalam contoh yang mungkin membuat orang percaya tidak ada lagi. Node teks yang dihasilkan dengan baris baru ditampilkan akan terlihat seperti: "Hello \ nwor \ nld" Normalisasi tidak menghapus baris baru.
Christian
10

Secara sederhana, Normalisasi adalah Pengurangan Redudansi.
Contoh Redudansi:
a) spasi putih di luar tag root / dokumen ( ... <dokumen> </dokumen> ... )
b) spasi putih dalam tag awal (< ... >) dan tag akhir (</ ... >)
c) spasi putih antara atribut dan nilainya (mis. spasi antara nama kunci dan = " )
d) deklarasi namespace yang berlebihan
e) garis putus / spasi putih dalam teks atribut dan tag
f) komentar dll ...

AVA
sumber
7

Sebagai perpanjangan dari jawaban @ JBNizet untuk pengguna yang lebih teknis inilah penerapan org.w3c.dom.Nodeantarmuka di com.sun.org.apache.xerces.internal.dom.ParentNodedalamnya, memberi Anda ide bagaimana cara kerjanya sebenarnya.

public void normalize() {
    // No need to normalize if already normalized.
    if (isNormalized()) {
        return;
    }
    if (needsSyncChildren()) {
        synchronizeChildren();
    }
    ChildNode kid;
    for (kid = firstChild; kid != null; kid = kid.nextSibling) {
         kid.normalize();
    }
    isNormalized(true);
}

Itu melintasi semua node secara rekursif dan memanggil kid.normalize()
Mekanisme ini ditimpaorg.apache.xerces.dom.ElementImpl

public void normalize() {
     // No need to normalize if already normalized.
     if (isNormalized()) {
         return;
     }
     if (needsSyncChildren()) {
         synchronizeChildren();
     }
     ChildNode kid, next;
     for (kid = firstChild; kid != null; kid = next) {
         next = kid.nextSibling;

         // If kid is a text node, we need to check for one of two
         // conditions:
         //   1) There is an adjacent text node
         //   2) There is no adjacent text node, but kid is
         //      an empty text node.
         if ( kid.getNodeType() == Node.TEXT_NODE )
         {
             // If an adjacent text node, merge it with kid
             if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
             {
                 ((Text)kid).appendData(next.getNodeValue());
                 removeChild( next );
                 next = kid; // Don't advance; there might be another.
             }
             else
             {
                 // If kid is empty, remove it
                 if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) {
                     removeChild( kid );
                 }
             }
         }

         // Otherwise it might be an Element, which is handled recursively
         else if (kid.getNodeType() == Node.ELEMENT_NODE) {
             kid.normalize();
         }
     }

     // We must also normalize all of the attributes
     if ( attributes!=null )
     {
         for( int i=0; i<attributes.getLength(); ++i )
         {
             Node attr = attributes.item(i);
             attr.normalize();
         }
     }

    // changed() will have occurred when the removeChild() was done,
    // so does not have to be reissued.

     isNormalized(true);
 } 

Semoga ini menghemat waktu Anda.

Matas Vaitkevicius
sumber