【问题标题】:Normalization in DOM parsing with java - how does it work?使用 java 进行 DOM 解析的规范化 - 它是如何工作的?
【发布时间】:2012-11-27 00:28:24
【问题描述】:

我在this tutorial 的 DOM 解析器代码中看到了下面的代码行。

doc.getDocumentElement().normalize();

我们为什么要进行这种标准化?
我读了docs,但一个字都听不懂。

将所有文本节点放在此节点下的子树的完整深度

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

谁能解释一下为什么需要标准化?
如果我们不规范化会发生什么?

【问题讨论】:

  • 不管您的问题是什么,请阅读示例说明:"DOM Parser 很慢,在加载包含大量数据的 XML 文档时会消耗大量内存。请考虑将 SAX 解析器作为解决方案,SAX 比 DOM 更快并且使用更少的内存。".
  • @wulfgar.pro - 我明白你说的。但是,我想了解我在问题中提出的内容。我也会很快做 SAX 解析。
  • 在 google 中搜索“normalize xml”会得到一些似乎有用的结果。它看起来类似于数据库中的规范化。
  • @EJP - 嗯......它仍然不清楚,因为我不深入了解 xml,我只阅读了一些介绍性页面。顺便说一句,不要误会我的意思,您完全按照文档的作者所做的 - 使用复杂的单词而不是简单的英语(像派克员工一样简单 = 易于理解)。先说简单的词,然后再用行话更适合我。
  • 在撰写本文时,所引用的网站正在引用此 SO 帖子。我的大脑刚刚抛出了一个依赖错误。

标签: java xml dom


【解决方案1】:

句子的其余部分是:

其中只有结构(例如元素、cmets、处理指令、CDATA 部分和实体引用)分隔 Text 节点,即既没有相邻的 Text 节点也没有空的 Text 节点。

这基本上意味着下面的 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"

属性也是如此:&lt;foo bar="Hello world"/&gt;、cmets 等

【讨论】:

  • 啊哈!现在更清楚了。我不知道数据结构(???)和节点。但是我快速浏览了树结构,我猜计算机可能会按照您建议的方式存储“hello world”。是这样吗?
  • 你需要学习 DOM 的基础知识。是的,DOM 将 XML 文档表示为一棵树。在树中,您有一个具有子节点的根节点,每个子节点也有子节点,等等。这就是树。 Element是一种节点,TextNode是另一种节点。
  • 感谢 JB 尼泽特。在得到一些指导后,我无法告诉你我是多么的松了一口气。
  • @user2043553,换行符实际上是重点。如果没有换行符,您将看不到区别。如果您不应该理解:规范化“纠正”了 XML,因此一个标签被解释为一个元素。如果您不这样做,则这些换行符可能会被解释为同一类型的多个元素之间的分隔符(分别在同一标记中)。
  • @Stacky,示例中有两个新行,示例中规范化后没有显示,这可能会让人们相信不再存在。显示换行符的结果文本节点如下所示:“Hello\nwor\nld” 规范化不会删除换行符。
【解决方案2】:

简单来说,标准化就是减少冗余。
冗余示例:
a) 根/文档标签之外的空格(......)
b) 开始标签 (...>) 和结束标签 (...>) 中的空格
c) 属性及其值之间的空格(即 key name=" 之间的空格)
d) 多余的命名空间声明
e) 属性和标签文本中的换行符/空格
f) cmets 等...

【讨论】:

    【解决方案3】:

    作为@JBNizet 对更多技术用户的回答的扩展,以下是com.sun.org.apache.xerces.internal.dom.ParentNodeorg.w3c.dom.Node 接口的实现方式,让您了解它的实际工作原理。

    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);
     } 
    

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

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 2014-07-06
      • 2020-07-31
      • 2021-05-19
      • 2013-03-18
      • 2013-07-18
      • 1970-01-01
      • 2012-03-07
      • 2017-09-26
      相关资源
      最近更新 更多