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

176

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

doc.getDocumentElement().normalize();

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

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

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

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

  • 0
    Независимо от вашего вопроса, прочтите примечание к примеру: «DOM Parser работает медленно и потребляет много памяти, когда загружает XML-документ, содержащий много данных. Пожалуйста, рассмотрите SAX-парсер как решение для него, SAX быстрее чем DOM и использовать меньше памяти. " ,
  • 3
    @ wulfgar.pro - Я понимаю, что вы сказали. Но я хочу понять материал, который я задал в вопросе. Я также сделаю разбор SAX в ближайшее время.
Показать ещё 5 комментариев
Теги:
dom
computer-science

3 ответа

292
Лучший ответ

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

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

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

<foo>hello 
wor
ld</foo>

может быть представлен таким образом в денормализованном node:

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

При нормализации, node будет выглядеть следующим образом:

Element foo
    Text node: "Hello world"

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

  • 2
    Ага! теперь намного понятнее. Я не знаю о структурах данных (???) и узлах. Но я быстро взглянул на древовидную структуру и, полагаю, компьютер может хранить «привет мир» так, как вы предлагали. Это правильно ?
  • 8
    Вам нужно изучить основы о DOM. Да, DOM представляет XML-документ в виде дерева. И в дереве у вас есть корневой узел, имеющий дочерний узел, каждый дочерний узел также имеет дочерние узлы и т. Д. Вот что такое дерево. Элемент является своего рода узлом, а TextNode - другим видом узла.
Показать ещё 7 комментариев
4

В простой, нормализация - сокращение избыточности.
Примеры избыточности:
a) пробелы вне тегов root/document (... <document> </document> )

b) белые пробелы в начале тега (<... > ) и конечный тег (</... > )
c) пробелы между атрибутами и их значениями (т.е. пробелы между ключевым именем и = ")
d) объявления избыточного пространства имен
e) разрывы строк/пробелы в текстах атрибутов и тегов
f) комментарии и т.д.

3

В качестве расширения для ответа @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);
 } 

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню