Normalisation dans l'analyse DOM avec java - comment ça marche?

240

J'ai vu la ligne ci-dessous dans le code d'un analyseur DOM lors de ce tutoriel .

doc.getDocumentElement().normalize();

Pourquoi faisons-nous cette normalisation?
J'ai lu les documents mais je n'ai pas pu comprendre un mot.

Place tous les nœuds de texte dans toute la profondeur de la sous-arborescence sous ce nœud

D'accord, alors quelqu'un peut-il me montrer (de préférence avec une photo) à quoi ressemble cet arbre?

Quelqu'un peut-il m'expliquer pourquoi une normalisation est nécessaire?
Que se passe-t-il si nous ne normalisons pas?

Apple Grinder
la source
Quelle que soit votre question, veuillez lire la note sur l'exemple: "DOM Parser est lent et consommera beaucoup de mémoire lorsqu'il charge un document XML qui contient beaucoup de données. Veuillez considérer l'analyseur SAX comme solution, SAX est plus rapide que DOM et utiliser moins de mémoire. " .
wulfgarpro
3
@ wulfgar.pro - Je comprends ce que vous avez dit. Mais, je veux comprendre les choses que j'ai posées dans la question. Je ferai aussi bientôt l'analyse SAX.
Apple Grinder
La recherche sur google pour "normaliser xml" a donné des résultats qui semblent utiles. Il ressemble à sa normalisation dans les bases de données.
Apple Grinder
2
@EJP - umm ... ce n'est toujours pas clair parce que je ne connais pas le xml en profondeur et je n'ai lu que quelques pages d'introduction dessus. BTW, ne vous méprenez pas, vous avez fait exactement ce que l'auteur du document a fait - en utilisant des mots complexes au lieu de l'anglais simple (simple comme un personnel de brochet = facile à comprendre). Les mots simples d'abord et le jargon plus tard fonctionnent mieux pour moi.
Apple Grinder
7
Au moment d'écrire ces lignes, le site Web référencé fait référence à ce message SO. Mon cerveau vient de lancer une erreur de dépendance.
chessofnerd

Réponses:

366

Le reste de la phrase est:

où seule la structure (par exemple, éléments, commentaires, instructions de traitement, sections CDATA et références d'entité) sépare les nœuds de texte, c'est-à-dire qu'il n'y a ni nœuds de texte adjacents ni nœuds de texte vides.

Cela signifie essentiellement que l'élément XML suivant

<foo>hello 
wor
ld</foo>

pourrait être représenté comme ceci dans un nœud dénormalisé:

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

Une fois normalisé, le nœud ressemblera à ceci

Element foo
    Text node: "Hello world"

Et il en va de même pour les attributs <foo bar="Hello world"/>:, commentaires, etc.

JB Nizet
la source
2
Ah! c'est beaucoup plus clair maintenant. Je ne connais pas les structures de données (???) et les nœuds. Mais j'ai jeté un coup d'œil à la structure arborescente et je suppose qu'un ordinateur peut stocker "bonjour le monde" comme vous l'avez suggéré. Est-ce correct ?
Apple Grinder
9
Vous devez apprendre les bases du DOM. Oui, DOM représente un document XML sous forme d'arbre. Et dans un arbre, vous avez un nœud racine ayant un nœud enfant, chaque nœud enfant ayant également des nœuds enfants, etc. C'est ce qu'est un arbre. Element est une sorte de nœud et TextNode est une autre sorte de nœud.
JB Nizet
7
Merci JB Nizet. Je ne peux pas vous dire à quel point je suis soulagé après avoir reçu une direction.
Apple Grinder
2
@ user2043553, les nouvelles lignes sont en fait le point. Sans nouvelles lignes, vous ne verriez pas la différence. Si vous n'auriez pas dû comprendre: la normalisation "corrige" le XML afin qu'une balise soit interprétée comme un élément. Si vous ne le faites pas, il peut arriver que ces toutes nouvelles lignes soient interprétées comme des délimiteurs entre plusieurs éléments du même type (resp. Dans la même balise).
Stacky
1
@Stacky, dans l'exemple, il y a deux nouvelles lignes, elles ne sont pas affichées après la normalisation dans l'exemple, ce qui pourrait faire croire aux gens qu'il n'y en a plus. Le nœud de texte résultant avec des sauts de ligne affichés ressemblerait à: "Hello \ nwor \ nld" La normalisation ne supprime pas les sauts de ligne.
Christian
10

En termes simples, la normalisation est la réduction des redondances.
Exemples de redondances:
a) espaces blancs en dehors des balises racine / document ( ... <document> </document> ... )
b) espaces blancs dans la balise de début (< ... >) et la balise de fin (</ ... >)
c) les espaces blancs entre les attributs et leurs valeurs (c'est-à-dire les espaces entre le nom de la clé et = " )
d) les déclarations d'espace de noms superflues
e) les sauts de ligne / les espaces blancs dans les textes des attributs et des balises
f) les commentaires etc ...

AVA
la source
7

En tant qu'extension de la réponse de @ JBNizet pour les utilisateurs plus techniques, voici à quoi ressemble la mise en œuvre de l' org.w3c.dom.Nodeinterface com.sun.org.apache.xerces.internal.dom.ParentNode, vous donne une idée de son fonctionnement réel .

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

Il parcourt tous les nœuds récursivement et appelle kid.normalize()
Ce mécanisme est surchargé dansorg.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);
 } 

J'espère que cela vous fera gagner du temps.

Matas Vaitkevicius
la source