【问题标题】:Obtain XML entity replacement text from DOM in Xerces在 Xerces 中从 DOM 获取 XML 实体替换文本
【发布时间】:2011-09-01 05:44:25
【问题描述】:

org.w3c.dom.Entity 的 Javadoc 声明:

XML 不强制非验证 XML 处理器读取和处理在外部子集中或在参数实体中声明的实体声明。这意味着在外部子集中声明的解析实体不需要由某些类的应用程序扩展,并且实体的替换文本可能不可用。当replacement text 可用时,对应的Entity 节点的子列表代表了那个替换值的结构。否则,子列表为空。

虽然它没有引用内部子集中的实体声明,但肯定有一些解析器配置可以读取和处理任一子集中的实体声明?事实上,我对文档的阅读表明这是默认设置。

无论如何,我已经针对已在内部子集(如图所示)和外部子集中声明的实体测试了以下方法(使用 Xerces),但 foo.hasChildNodes() 返回 false(并且 foo.getChildNodes() 返回foo!) 在每种情况下:

// some trivial example XML
String xml = "<!DOCTYPE example [ <!ENTITY foo 'bar'> ]>\n<example/>";
InputStream is = new ByteArrayInputStream(xml.getBytes());

// parse
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DocumentType docType = builder.parse(is).getDoctype();

// retrieve the entity - works fine
Entity foo = (Entity) docType.getEntities().getNamedItem("foo");

// now how to get the entity's replacement text?

毫无疑问,我遗漏了一些相当明显的东西;感谢您的想法。


编辑

从到目前为止的答案看来,我的 Xerces 实现行为不端。我将尝试将所有 Xerces 库更新到最新版本,如果这解决了我的问题,我将关闭这个问题。非常感谢。


更新

更新 Xerces 确实解决了这个问题,前提是该实体是从文档中引用的;如果不是,则该节点仍然没有子节点。我并不完全清楚为什么会这样。如果有人能解释发生了什么和/或指出我如何在不明确引用文档中的每个实体的情况下强制创建子节点,将不胜感激。

【问题讨论】:

    标签: java xml dom entities xerces


    【解决方案1】:

    我在 Xerces-J 用户邮件列表中询问了文档中没有引用实体的子节点不存在;有Michael Glavassevich helpfully pointed mean old post from Andy Clark解释如下:

    不幸的是(对您而言)这是一项功能。并且实施了 这种方式主要是出于性能原因。如果一个实体永远 在文档中引用,那么我们永远不必浪费时间 阅读它。如果外部实体很大但从未被引用, 我们不会浪费时间或记忆。

    另外,还有一个与命名空间有关的更深层次的问题。 DOM 甚至帮不上忙。我会解释...

    取以下文件和外部实体:

      <!-- entity.ent -->
      <hello/>
    
      <!-- document.xml -->
      <!DOCTYPE root [
      <!ENTITY entity SYSTEM 'entity.ent'>
      ]>
      <root>
        <sub xmlns='foo'> &entity; </sub>
        <sub xmlns='bar'> &entity; </sub>
      </root>
    

    请注意,每个点的默认命名空间都不同 引用实体的位置。这意味着 元素将绑定到不同的命名空间。所以两者 同一实体的实例实际上是不同的元素!

    在这种情况下,DOM doctype中的Entity节点应该是什么 返回:“foo”命名空间中的子项或“bar”中的子项 命名空间?

    简而言之,这是一个复杂的问题。

    您最好尝试阅读文档片段 当你寻找实体节点时你自己,它没有 孩子们。 Xerces 在 impl 中有一个文档片段扫描仪 用于此目的的软件包。你必须 编写为 DOM 文档片段构建子级的代码 不过,来自 XNI 方法。但这并不难做到。我能 如果需要,请为您提供示例。

    【讨论】:

      【解决方案2】:

      我认为您可能误解了替换文本的工作原理。根据一些阅读 (http://www.javacommerce.com/displaypage.jsp?name=entities.sql&id=18238),在我看来,替换文本就像一个变量。因此,在上面的示例中,您永远不会引用 &amp;foo; 实体。如果您运行下面的代码示例,您会看到&amp;foo; 被替换为字符串bar

      // some trivial example XML
      String xml = "<!DOCTYPE example [ <!ENTITY foo 'bar'> ]><example><foo>&foo;</foo></example>";
      InputStream is = new ByteArrayInputStream(xml.getBytes());
      
      // parse
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document doc = builder.parse(is);
      DocumentType docType = doc.getDoctype();
      
      // retrieve the entity - works fine
      Entity foo = (Entity) docType.getEntities().getNamedItem("foo");
      for(int i = 0; i < foo.getChildNodes().getLength(); i++) {
        System.out.println(foo.getChildNodes().item(i));
      }
      

      您看到打印的是[#text: bar],它是 XML 中的文本替换。

      【讨论】:

      • 遗憾的是,这正是 不适合我的——即使我引用 &foo;从文档中(尽管我完全同意根据文档应该这样做)。在我的情况下foo.getChildNodes() == foo.getLength().item(0) 分别返回 0null。您使用的是什么实现方式?
      • 我正在使用 JDK 1.6.0_20 并从那里使用 org.w3c.dom.Entity 类。您从上面剪切并粘贴了代码,但控制台没有打印任何内容?
      • 确实如此。 foo.getChildNodes().getLength() 返回 0,因此永远不会进入循环,永远不会调用 System.out.println
      • 我正在使用 Xerces 2.8.1 - 您使用的是哪个版本,因为它会为我打印 [#text: bar]
      【解决方案3】:

      我不知道为什么foo.getChildNodes() 不起作用,但我发现了以下内容。如果实体在文档中被使用(引用),

      &lt;!DOCTYPE example [&lt;!ENTITY foo 'bar'&gt;]&gt;\n&lt;example&gt;&amp;foo;&lt;/example&gt;,

      那么替换文本可以通过

      foo.getTextContent()

      【讨论】:

      • 可悲的是,对我来说,foo.getTextContent() 正在返回空字符串 "",即使 &foo;在文档中引用。您使用的是什么解析器实现?
      • 另见我的cmets回复StaxMan's answer:我相信文字内容和替换文字不太一样。
      【解决方案4】:

      我可能错了,但我认为实体节点将替换文本存储为文本值,而不是节点集;这是因为在解析实体定义时实际上并未完全解析实体:这主要是因为 DTD 处理程序是一种在实际解析过程之前发生的预处理器。 所以检查实体节点的文本值而不是子节点列表。

      【讨论】:

      • 认为实体节点的文本内容应该是它的“字面值”(即实体声明中包含的确切文本);而我在“替换文本”之后(即在字符和参数引用被替换之后)。无论如何,请参阅我对mzjn's answer 的评论:无论如何它都会为我返回一个空字符串!
      • 对,以前我希望是正确的。但后者我不希望是真的;虽然我想阅读 DOM 规范会很好。无论哪种方式,公开任何与 DTD 相关的内容都是相当棘手的,因为它与“常规”XML 处理完全不同,具有不同的语法,并且是完全常规的文本替换,完全没有结构意识。
      • 谢谢; DOM 规范的relevant bits(我的问题中引用的 Javadoc 从中提取)明确链接到 XML 规范中的定义;如上所述,它非常明确地区分了“文字实体值”和“替换文本”。但是,我认为对于实体节点,文本内容无论如何都被定义为其子节点的文本内容的聚合,所以它很可能是我所需要的。感谢您的帮助!
      猜你喜欢
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 2010-12-02
      • 2017-03-13
      • 2018-12-16
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多