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


240

このチュートリアルで、DOMパーサーのコードに以下の行を表示しました。

doc.getDocumentElement().normalize();

なぜこの正規化を行うのですか?ドキュメント
を読みましたが、言葉が理解できませんでした。

すべてのTextノードを、このノードの下のサブツリーの完全な深さに配置します

さて、誰かがこのツリーがどのように見えるかを(できれば写真で)見せてくれますか?

正規化が必要な理由を誰かが私に説明できますか?
正規化しないとどうなりますか?


質問に関係なく、例のメモをお読みください。「DOMパーサーは低速で、大量のデータを含むXMLドキュメントをロードすると大量のメモリを消費します。SAXパーサーはその解決策として検討してください。SAXの方が高速ですDOMよりもメモリ使用量が少ない。」
wulfgarpro

3
@ wulfgar.pro-私はあなたが言ったことを理解しています。しかし、私が質問で尋ねたものを理解したいと思います。まもなくSAX解析も行います。
Apple Grinder

グーグルで「normalize xml」を検索すると、いくつかの有用な結果が得られました。データベースの正規化に似ています。
Apple Grinder

2
@EJP-うーん...それはまだ明確ではありません。私はxmlの詳細がわからず、いくつかの紹介ページしか読んでいないためです。ところで、私を誤解しないでください、あなたはドキュメントの著者がしたことを正確に行いました-プレーンな英語の代わりに複雑な単語を使用しました(パイクのスタッフとしてわかりやすい=理解しやすい)。最初は単純な言葉、その後は専門用語の方がうまくいきます。
Apple Grinder

7
これを書いている時点で、参照先のWebサイトはこのSO投稿を参照しています。私の脳は依存関係エラーを投げました。
chessofnerd 2013

回答:


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
ああ!そのはるかに明確になりました。データ構造(???)とノードについて知りません。しかし、ツリー構造をざっと見ただけで、コンピュータが「hello world」をあなたの提案した方法で保存しているのではないかと思います。そうですか?
Apple Grinder 2012

9
DOMの基本を学ぶ必要があります。はい、DOMはXMLドキュメントをツリーとして表します。そしてツリーには、子ノードを持つルートノードがあり、各子ノードにも子ノードがあるなどです。それがツリーです。Elementは一種のノードで、TextNodeはもう一種のノードです。
JB Nizet

7
JB Nizetに感謝します。いくつかの指示を得た後、私がどれほど安心したかはわかりません。
Apple Grinder

2
@ user2043553、改行は実際にはそこのポイントです。改行がなければ、違いはわかりません。理解していないはずです:1つのタグが1つの要素として解釈されるように、正規化はXMLを「修正」します。これを行わなかった場合、これらの非常に改行が同じタイプの複数の要素(それぞれ同じタグ内)間の区切り文字として解釈される可能性があります。
Stacky

1
@Stacky、例では2つの新しい行があります。例で正規化した後は表示されないため、人々はもうそこにはないと信じるかもしれません。改行が表示された結果のテキストノードは次のようになります。 "Hello \ nwor \ nld"正規化しても改行は削除されません。
クリスチャン

10

簡単に言うと、正規化は冗長性の削減です。
冗長性の例:
a)ルート/ドキュメントタグの外側の空白(... <document> </ document> ...
b)開始タグ(< ... >)と終了タグ(</)内の空白... >)
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);
 } 

これにより時間を節約できることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.