我在本教程中看到了下面这行DOM解析器的代码。

doc.getDocumentElement().normalize();

为什么要做这个归一化? 我看了文件,但一个字也看不懂。

将所有Text节点放在此Node下面的子树的全深度中

好吧,那谁能给我看看(最好是有照片)这棵树是什么样子的?

谁能解释一下为什么需要正常化? 如果我们不正常化会发生什么?


当前回答

作为@JBNizet为更多技术用户提供的答案的扩展,以下是org.w3c.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);
}

它递归遍历所有节点并调用child .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);
 } 

希望这能为您节省一些时间。

其他回答

作为@JBNizet为更多技术用户提供的答案的扩展,以下是org.w3c.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);
}

它递归遍历所有节点并调用child .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);
 } 

希望这能为您节省一些时间。

简单地说,正常化就是减少冗余。 冗余的例子: A)根/文档标记之外的空白(…<document></document>…) B)开始标记(<…>)和结束标记(</…>)中的空白 C)属性和值之间的空白。键名和="之间有空格) D)多余的名称空间声明 E)属性和标签文本中的换行/空格 F)评论等等……

句子的其余部分是:

其中只有结构(例如,元素、注释、处理指令、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"/>, comments,等等。