Normalizzazione nell'analisi DOM con java: come funziona?


240

Ho visto la riga seguente nel codice per un parser DOM in questo tutorial .

doc.getDocumentElement().normalize();

Perché facciamo questa normalizzazione?
Ho letto i documenti ma non sono riuscito a capire una parola.

Mette tutti i nodi di testo in tutta la profondità dell'albero secondario sotto questo nodo

Okay, allora qualcuno può mostrarmi (preferibilmente con una foto) come appare questo albero?

Qualcuno può spiegarmi perché è necessaria la normalizzazione?
Cosa succede se non ci normalizziamo?


Indipendentemente dalla tua domanda, leggi la nota sull'esempio: "Il parser DOM è lento e consuma molta memoria quando carica un documento XML che contiene molti dati. Considera il parser SAX come soluzione, SAX è più veloce di DOM e usa meno memoria. " .
wulfgarpro,

3
@ wulfgar.pro - Capisco quello che hai detto. Ma voglio capire le cose che ho posto nella domanda. Presto eseguirò anche l'analisi SAX.
Apple Grinder

Cercare "normalizzare xml" su Google ha dato alcuni risultati che sembrano utili. Sembra simile alla normalizzazione nei database.
Apple Grinder

2
@EJP - umm ... non è ancora chiaro perché non conosco xml in modo approfondito e ho solo letto alcune pagine introduttive su di esso. A proposito, non fraintendetemi, hai fatto esattamente quello che ha fatto l'autore del documento - usando parole complesse invece di un semplice inglese (semplice come uno staff di luccio = facile da capire). Le parole semplici prima e il gergo poi funzionano meglio per me.
Apple Grinder

7
Al momento della stesura del presente documento, il sito Web di riferimento fa riferimento a questo post SO. Il mio cervello ha appena lanciato un errore di dipendenza.
chessofnerd,

Risposte:


366

Il resto della frase è:

dove solo la struttura (ad es. elementi, commenti, istruzioni di elaborazione, sezioni CDATA e riferimenti di entità) separa i nodi di testo, ovvero non ci sono nodi di testo adiacenti né nodi di testo vuoti.

Ciò significa sostanzialmente che il seguente elemento XML

<foo>hello 
wor
ld</foo>

potrebbe essere rappresentato in questo modo in un nodo denormalizzato:

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

Quando normalizzato, il nodo sarà simile a questo

Element foo
    Text node: "Hello world"

E lo stesso vale per gli attributi: <foo bar="Hello world"/>commenti, ecc.


2
Ah! è molto più chiaro ora. Non conosco strutture dati (???) e nodi. Ma ho dato una rapida occhiata alla struttura ad albero e, immagino che un computer potrebbe memorizzare "ciao mondo" nel modo che hai suggerito. È giusto ?
Apple Grinder

9
Devi imparare le basi del DOM. Sì, DOM rappresenta un documento XML come un albero. E in un albero, hai un nodo radice con nodo figlio, ogni nodo figlio ha anche nodi figlio, ecc. Ecco cos'è un albero. L'elemento è un tipo di nodo e TextNode è un altro tipo di nodo.
JB Nizet,

7
Grazie JB Nizet. Non posso dirti quanto sono sollevato dopo aver ottenuto una direzione.
Apple Grinder

2
@ user2043553, le nuove linee sono in realtà il punto lì. Senza newline, non vedresti la differenza. Se non avresti dovuto capire: la normalizzazione "corregge" l'XML in modo che un tag venga interpretato come un elemento. Se non lo hai fatto, potrebbe accadere che queste nuovissime righe vengano interpretate come delimitatori tra più elementi dello stesso tipo (rispettivamente nello stesso tag).
Stacky

1
@Stacky, nell'esempio ci sono due nuove righe, non vengono visualizzate dopo la normalizzazione nell'esempio che potrebbe far credere alle persone che non ci siano più. Il nodo di testo risultante con le nuove righe visualizzate sarebbe simile a: "Hello \ nwor \ nld" La normalizzazione non rimuove le nuove righe.
Christian,

10

In parole povere, la normalizzazione è la riduzione dei licenziamenti.
Esempi di ridondanze:
a) spazi bianchi all'esterno dei tag radice / documento ( ... <document> </document> ... )
b) spazi bianchi all'interno del tag iniziale (< ... >) e del tag finale (</ ... >)
c) spazi bianchi tra gli attributi e i loro valori (es. spazi tra nome chiave e = " )
d) dichiarazioni di spazio dei nomi superflue
e) interruzioni di riga / spazi bianchi nei testi di attributi e tag
f) commenti ecc ...


7

Come estensione alla risposta di @ JBNizet per più utenti tecnici ecco come appare l' implementazione org.w3c.dom.Nodedell'interfaccia com.sun.org.apache.xerces.internal.dom.ParentNode, ti dà l'idea di come funziona effettivamente.

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);
}

Attraversa tutti i nodi in modo ricorsivo e chiama kid.normalize()
Questo meccanismo viene sostituitoorg.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);
 } 

Spero che questo ti faccia risparmiare un po 'di tempo.

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.