Normalisierung beim Parsen von DOM mit Java - wie funktioniert das?

240

In diesem Tutorial habe ich die folgende Zeile im Code für einen DOM-Parser gesehen .

doc.getDocumentElement().normalize();

Warum machen wir diese Normalisierung?
Ich habe die Dokumente gelesen, aber ich konnte kein Wort verstehen.

Setzt alle Textknoten in der vollen Tiefe des Unterbaums unter diesen Knoten

Okay, kann mir dann jemand (vorzugsweise mit einem Bild) zeigen, wie dieser Baum aussieht?

Kann mir jemand erklären, warum eine Normalisierung erforderlich ist?
Was passiert, wenn wir uns nicht normalisieren?

Apfelschleifer
quelle
Unabhängig von Ihrer Frage lesen Sie bitte den Hinweis zum Beispiel: "DOM Parser ist langsam und verbraucht viel Speicher, wenn ein XML-Dokument geladen wird, das viele Daten enthält. Bitte betrachten Sie SAX Parser als Lösung dafür, SAX ist schneller als DOM und verwenden weniger Speicher. " .
Wulfgarpro
3
@ wulfgar.pro - Ich verstehe, was du gesagt hast. Aber ich möchte das verstehen, was ich in der Frage gestellt habe. Ich werde auch bald SAX-Parsing durchführen.
Apple Grinder
Die Suche in Google nach "XML normalisieren" ergab einige Ergebnisse, die nützlich erscheinen. Es sieht ähnlich aus wie die Normalisierung in Datenbanken.
Apple Grinder
2
@EJP - umm ... es ist immer noch nicht klar, weil ich XML nicht genau kenne und nur ein paar Einführungsseiten darüber lese. Übrigens, verstehen Sie mich nicht falsch, Sie haben genau das getan, was der Autor des Dokuments getan hat - mit komplexen Wörtern anstelle von einfachem Englisch (einfach wie ein Hechtstab = leicht zu verstehen). Einfache Wörter zuerst und Jargon später funktionieren besser für mich.
Apple Grinder
7
Zum jetzigen Zeitpunkt verweist die Website, auf die verwiesen wird, auf diesen SO-Beitrag. Mein Gehirn hat gerade einen Abhängigkeitsfehler geworfen.
Schachofnerd

Antworten:

366

Der Rest des Satzes lautet:

wobei nur die Struktur (z. B. Elemente, Kommentare, Verarbeitungsanweisungen, CDATA-Abschnitte und Entitätsreferenzen) Textknoten trennt, dh es gibt weder benachbarte Textknoten noch leere Textknoten.

Dies bedeutet im Grunde, dass das folgende XML-Element

<foo>hello 
wor
ld</foo>

könnte so in einem denormalisierten Knoten dargestellt werden:

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

Bei Normalisierung sieht der Knoten folgendermaßen aus

Element foo
    Text node: "Hello world"

Gleiches gilt für Attribute : <foo bar="Hello world"/>, Kommentare usw.

JB Nizet
quelle
2
Aha! es ist jetzt viel klarer. Ich weiß nichts über Datenstrukturen (???) und Knoten. Aber ich habe mir die Baumstruktur kurz angesehen und vermute, dass ein Computer "Hallo Welt" so speichern könnte, wie Sie es vorgeschlagen haben. Ist das richtig ?
Apple Grinder
9
Sie müssen die Grundlagen zu DOM lernen. Ja, DOM repräsentiert ein XML-Dokument als Baum. Und in einem Baum haben Sie einen Wurzelknoten mit einem untergeordneten Knoten, jeder untergeordnete Knoten hat auch untergeordnete Knoten usw. Das ist ein Baum. Element ist eine Art Knoten, und TextNode ist eine andere Art von Knoten.
JB Nizet
7
Vielen Dank, JB Nizet. Ich kann dir nicht sagen, wie erleichtert ich bin, nachdem ich eine Anweisung bekommen habe.
Apple Grinder
2
@ user2043553, die Zeilenumbrüche sind eigentlich der Punkt dort. Ohne Zeilenumbrüche würden Sie den Unterschied nicht sehen. Wenn Sie nicht verstanden haben sollten: Die Normalisierung "korrigiert" das XML, sodass ein Tag als ein Element interpretiert wird. Wenn Sie dies nicht getan haben, kann es vorkommen, dass genau diese Zeilenumbrüche als Trennzeichen zwischen mehreren Elementen desselben Typs (bzw. im selben Tag) interpretiert werden.
Stacky
1
@Stacky, im Beispiel gibt es zwei neue Zeilen, die nach dem Normalisieren im Beispiel nicht angezeigt werden, was die Leute glauben lassen könnte, dass es keine mehr gibt. Der resultierende Textknoten mit angezeigten Zeilenumbrüchen sieht folgendermaßen aus: "Hallo \ nwor \ nld" Durch das Normalisieren werden keine Zeilenumbrüche entfernt.
Christian
10

Normalisierung ist einfach eine Reduzierung von Redundanzen.
Beispiele für Redundanzen:
a) Leerzeichen außerhalb der Stamm- / Dokument-Tags ( ... <Dokument> </ Dokument> ... )
b) Leerzeichen innerhalb des Start-Tags (< ... >) und des End-Tags (</ ... >)
c) Leerzeichen zwischen Attributen und ihren Werten (dh Leerzeichen zwischen Schlüsselname und = " )
d) überflüssige Namespace-Deklarationen
e) Zeilenumbrüche / Leerzeichen in Texten von Attributen und Tags
f) Kommentare usw. ...

AVA
quelle
7

Als Erweiterung der Antwort von @ JBNizet für technisch versierte Benutzer erhalten Sie hier eine Vorstellung davon, wie die Implementierung der org.w3c.dom.NodeSchnittstelle in com.sun.org.apache.xerces.internal.dom.ParentNodeaussieht.

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

Es durchläuft alle Knoten rekursiv und ruft kid.normalize()
diesen Mechanismus auforg.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);
 } 

Hoffe das spart dir etwas Zeit.

Matas Vaitkevicius
quelle