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


240

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

doc.getDocumentElement().normalize();

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

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

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

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


Независимо от вашего вопроса, прочтите примечание к примеру: «DOM Parser работает медленно и потребляет много памяти, когда загружает XML-документ, который содержит много данных. Пожалуйста, рассмотрите SAX-парсер как решение для него, SAX быстрее чем DOM и использовать меньше памяти. " ,
wulfgarpro

3
@ wulfgar.pro - Я понимаю, что вы сказали. Но я хочу понять материал, который я задал в вопросе. Я также сделаю разбор SAX в ближайшее время.
Apple Grinder

Поиск в Google по запросу "normalize xml" дал некоторые результаты, которые кажутся полезными. Похоже, это похоже на нормализацию в базах данных.
Apple Grinder

2
@EJP - ммм ... до сих пор неясно, потому что я не знаю xml подробно, и я только прочитал несколько вступительных страниц о нем. Кстати, не поймите меня неправильно, вы сделали именно то, что сделал автор документа - используя сложные слова вместо простого английского (простой, как пика, персонал = легко понять). Простые слова сначала и жаргон позже работают лучше для меня.
Apple Grinder

7
На момент написания этой статьи ссылочный веб-сайт ссылается на этот пост. Мой мозг просто выбросил ошибку зависимости.
chessofnerd

Ответы:


366

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

где только структура (например, элементы, комментарии, инструкции обработки, разделы 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"/>комментариев и т. Д.


2
Ага! теперь намного понятнее. Я не знаю о структурах данных (???) и узлах. Но я быстро взглянул на древовидную структуру и, полагаю, компьютер может хранить «привет мир» так, как вы предлагали. Это правильно ?
Apple Grinder

9
Вам необходимо изучить основы DOM. Да, DOM представляет XML-документ в виде дерева. И в дереве у вас есть корневой узел, имеющий дочерний узел, каждый дочерний узел также имеет дочерние узлы и т. Д. Вот что такое дерево. Элемент является своего рода узлом, а TextNode - другим видом узла.
JB Низет

7
Спасибо JB Низет. Не могу сказать, насколько я рад, когда получил направление.
Apple Grinder

2
@ user2043553, новые строки на самом деле имеют смысл. Без перевода строки вы не увидите разницу. Если вы не должны были понимать: нормализация «исправляет» XML, поэтому один тег интерпретируется как один элемент. Если вы этого не сделали, может случиться так, что эти самые новые строки интерпретируются как разделители между несколькими элементами одного типа (соответственно в одном и том же теге).
Stacky

1
@Stacky, в примере есть две новые строки, они не отображаются после нормализации в примере, что может заставить людей поверить, что их там больше нет. Результирующий текстовый узел с отображенными символами новой строки будет выглядеть следующим образом: «Hello \ nwor \ nld» Нормализация не удаляет символы новой строки.
Кристиан

10

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


7

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.