Нормализация в DOM разборе с java-как это работает?


Я видел строку ниже в коде для парсера DOM в в этом уроке.

doc.getDocumentElement().normalize();

почему мы делаем эту нормализацию ?
Я прочитал docs но я не мог понять ни слова.

помещает все текстовые узлы в полную глубину поддерева под этим узлом

Хорошо, тогда может кто-нибудь показать мне (желательно с картинкой), как выглядит это дерево ?

может кто-нибудь объяснить мне, почему нормализация нужна?
Что произойдет, если мы не нормализовать ?

3 203

3 ответа:

остальная часть предложения:

где только структура (например, элементы, комментарии, инструкции по обработке, разделы CDATA и ссылки на сущности) разделяет текстовые узлы, т. е. нет ни соседних текстовых узлов, ни пустых текстовых узлов.

это в основном означает, что следующий элемент XML

<foo>hello 
wor
ld</foo>

может быть представлен следующим образом в денормализованном узле:

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

при нормализации узел будет выглядеть так это

Element foo
    Text node: "Hello world"

и то же самое касается атрибутов: <foo bar="Hello world"/>, замечания и т. д.

проще говоря, нормализация-это сокращение избыточности.
примеры избыточности:
a) пробелы вне тегов корня / документа (...документ>...)
b) пробелы в теге start (...>) и закрывающего тега (...>)
c) пробелы между атрибутами и их значениями (т. е. пробелы между введите имя и =")
d) избыточное пространство имен декларации
e) разрывы строк/пробелы в текстах атрибутов и тегов
е) замечания и т. д...

в качестве расширения к ответу @JBNizet для более технических пользователей вот какая реализация org.w3c.dom.Node интерфейс com.sun.org.apache.xerces.internal.dom.ParentNode похоже, дает вам представление, как это на самом деле работает.

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

он рекурсивно пересекает все узлы и вызывает kid.normalize()
Этот механизм переопределяется в 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);
 } 

надеюсь, что это экономит ваше время.