web-dev-qa-db-ja.com

JavaによるDOM解析の正規化 - どのように機能するのですか?

下の行をDOMパーサーのコードで このチュートリアル で見ました。

doc.getDocumentElement().normalize();

なぜ我々はこの正規化をするのですか?
docs を読みましたが、Wordが理解できませんでした。

このノードの下のサブツリーのすべての深さにすべてのテキストノードを配置します。

さて、それで誰かが私に(できれば絵で)この木のように見えるものを見せることができますか?

正規化が必要な理由を説明できる人はいますか。
正規化しないとどうなりますか?

221
Apple Grinder

文の残りの部分は次のとおりです。

構造(例えば、要素、コメント、処理命令、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"/>、コメントなど。

342
JB Nizet

簡単に言えば、正規化は冗長性の削減です。
冗長性の例:
a)root/documentタグの外側の空白(... <document> </document> ...
b)開始タグ(<...>)および終了タグ(</ ...>)内の空白
c)属性とその値の間の空白(つまり、キー名= "の間の空白)
d)余分な名前空間宣言
e)属性およびタグのテキスト内の改行/空白
f)コメントなど.

6
AVA

より技術的なユーザーに対する@ JBNizetの回答の拡張として、org.w3c.dom.Nodecom.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);
 } 

これが時間を節約することを願っています。

5