Нормалізація розбору DOM з java - як це працює?


240

У цьому навчальному посібнику я побачив рядок у коді для аналізатора DOM .

doc.getDocumentElement().normalize();

Чому ми робимо цю нормалізацію?
Я читав документи, але не зміг зрозуміти жодного слова.

Вставляє всі текстові вузли на всю глибину під-дерева під цим Вузлом

Гаразд, тоді хтось може мені показати (бажано із зображенням), як виглядає це дерево?

Хтось може мені пояснити, для чого потрібна нормалізація?
Що станеться, якщо ми не нормалізуємось?


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

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

Пошук у Google за "нормалізацією xml" дав деякі результати, які здаються корисними. Це схоже на його нормалізацію в базах даних.
Apple Grinder

2
@EJP - umm ... його все ще не зрозуміло, тому що я не знаю 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 Nizet

7
Дякую JB Nizet Не можу сказати, наскільки я полегшений після отримання певного напрямку.
Apple Grinder

2
@ user2043553, новинки - це насправді сенс. Без нових рядків ви не побачили б різниці. Якщо ви не мали б зрозуміти: нормалізація "виправляє" XML, так що один тег інтерпретується як один елемент. Якщо ви цього не зробили, може статися, що ці самі нові рядки трактуються як роздільники між декількома елементами одного типу (відповідно в одному тезі).
Стакі

1
@Stacky, у прикладі є два нові рядки, вони не відображаються після нормалізації в прикладі, що може змусити людей повірити, що їх більше немає. Отриманий текстовий вузол із відображеними новими рядками виглядатиме так: "Привіт \ nwor \ nld" Нормалізація не видаляє нові рядки.
Крістіан

10

Простіше кажучи, нормалізація - це скорочення скорочень.
Приклади надлишків:
а) пробіли поза тегами кореня / документа ( ... <документ> </document> ... )
б) пробіли в тезі старту (< ... >) та кінцевого тега (</ ... >)
в) пробіли між атрибутами та їх значеннями (тобто пробіли між назвою ключа та = " )
г) зайві декларації простору імен;
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.