Normalización en el análisis DOM con Java: ¿cómo funciona?

240

Vi la siguiente línea en el código para un analizador DOM en este tutorial .

doc.getDocumentElement().normalize();

¿Por qué hacemos esta normalización?
Leí los documentos pero no pude entender una palabra.

Pone todos los nodos de texto en toda la profundidad del subárbol debajo de este nodo

Bien, entonces, ¿alguien puede mostrarme (preferiblemente con una foto) cómo se ve este árbol?

¿Alguien puede explicarme por qué se necesita la normalización?
¿Qué pasa si no nos normalizamos?

Molinillo de manzana
fuente
Independientemente de su pregunta, lea la nota en el ejemplo: "DOM Parser es lento y consumirá mucha memoria cuando carga un documento XML que contiene muchos datos. Considere el analizador SAX como la solución, SAX es más rápido que DOM y usa menos memoria ". .
wulfgarpro
3
@ wulfgar.pro - Entiendo lo que dijiste. Pero, quiero entender las cosas que hice en la pregunta. También haré el análisis SAX pronto.
Apple Grinder
La búsqueda en Google de "normalizar xml" dio algunos resultados que parecen útiles. Parece que es similar a la normalización en las bases de datos.
Apple Grinder
2
@EJP - umm ... todavía no está claro porque no conozco xml en profundidad y solo leo algunas páginas introductorias. Por cierto, no me malinterpretes, hiciste exactamente lo que hizo el autor del documento: usar palabras complejas en lugar de inglés simple (simple como un pike staff = fácil de entender). Las palabras simples primero y la jerga después me funcionan mejor.
Apple Grinder
77
Al momento de escribir esto, el sitio web al que se hace referencia hace referencia a esta publicación SO. Mi cerebro solo arrojó un error de dependencia.
chessofnerd

Respuestas:

366

El resto de la oración es:

donde solo la estructura (p. ej., elementos, comentarios, instrucciones de procesamiento, secciones CDATA y referencias de entidades) separa los nodos de texto, es decir, no hay nodos de texto adyacentes ni nodos de texto vacíos.

Esto básicamente significa que el siguiente elemento XML

<foo>hello 
wor
ld</foo>

podría representarse así en un nodo desnormalizado:

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

Cuando se normaliza, el nodo se verá así

Element foo
    Text node: "Hello world"

Y lo mismo ocurre con los atributos: <foo bar="Hello world"/>comentarios, etc.

JB Nizet
fuente
2
¡Ajá! ahora está mucho más claro. No sé sobre estructuras de datos (???) y nodos. Pero eché un vistazo rápido a la estructura de árbol y supongo que una computadora podría almacenar "hola mundo" de la manera que usted sugirió. Está bien ?
Apple Grinder
99
Debes aprender los conceptos básicos sobre DOM. Sí, DOM representa un documento XML como un árbol. Y en un árbol, tiene un nodo raíz que tiene un nodo hijo, cada nodo hijo también tiene nodos hijos, etc. Eso es un árbol. Element es un tipo de nodo, y TextNode es otro tipo de nodo.
JB Nizet
77
Gracias JB Nizet. No puedo decir lo aliviado que estoy después de obtener alguna dirección.
Apple Grinder
2
@ user2043553, las nuevas líneas son realmente el punto allí. Sin saltos de línea, no verías la diferencia. Si no debería haber entendido: La normalización "corrige" el XML para que una etiqueta se interprete como un elemento. Si no lo hizo, puede suceder que estas líneas nuevas se interpreten como delimitadores entre varios elementos del mismo tipo (respectivamente, en la misma etiqueta).
Stacky
1
@Stacky, en el ejemplo hay dos líneas nuevas, no se muestran después de la normalización en el ejemplo, lo que puede hacer que la gente crea que ya no existen. El nodo de texto resultante con nuevas líneas mostradas se vería así: "Hola \ nwor \ nld" La normalización no elimina las nuevas líneas.
Christian
10

En simple, la normalización es la reducción de redundancias.
Ejemplos de redundancias:
a) espacios en blanco fuera de las etiquetas raíz / documento ( ... <documento> </documento> ... )
b) espacios en blanco dentro de la etiqueta de inicio (< ... >) y la etiqueta de finalización (</ ... >)
c) espacios en blanco entre los atributos y sus valores (es decir, espacios entre el nombre clave y = " )
d) declaraciones de espacio de nombres superfluas
e) saltos de línea / espacios en blanco en textos de atributos y etiquetas
f) comentarios, etc.

AVA
fuente
7

Como extensión de la respuesta de @ JBNizet para usuarios más técnicos , así es como se ve la implementación de la org.w3c.dom.Nodeinterfaz com.sun.org.apache.xerces.internal.dom.ParentNode, le da la idea de cómo funciona realmente.

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

Atraviesa todos los nodos de forma recursiva y llama a kid.normalize()
este mecanismo.org.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);
 } 

Espero que esto te ahorre algo de tiempo.

Matas Vaitkevicius
fuente