【问题标题】:StAX and DOM using XMLEventReader rather than XMLStreamReaderStAX 和 DOM 使用 XMLEventReader 而不是 XMLStreamReader
【发布时间】:2013-06-02 11:54:56
【问题描述】:

我想写一些基本上类似于Reading a big XML file using stax and dom 的代码 但使用 XMLEventReader 而不是 XMLStreamReader(在继续创建 DOM 之前,我需要能够检查某些元素的值)。

有没有人有一个最小的例子来说明这看起来如何?到目前为止,我尝试过的所有操作都会出现错误或空指针异常。

谢谢! 爱洛

【问题讨论】:

    标签: java dom stax


    【解决方案1】:

    看看:http://www.vogella.com/articles/JavaXML/article.html#javastax_read

    它提供了一个很好的小例子,如何使用 xml-streaming 和 XMLEventReader

    【讨论】:

    • 谢谢。好资源。我的问题实际上是从 EventReader 创建一个 DOM 结构。我可以使用 xmlStreamReader 和 xmlEventReader 很好地读取文件,但只能从 StreamReader 创建一个 DOM(如我添加到问题中的链接所示)。
    【解决方案2】:

    我遇到了同样的问题,据我调试,一切都表明 JDK 中存在错误(至少在构建 1.8.0_162-b12 上),更具体地说是在 com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX 类中。

    NPE实际上只是另一个bug的结果,这与该类的bridge()方法中如何处理阅读器有关。如果读者不是处于START_DOCUMENT 状态,那么下一个事件只会在第一次使用nextEvent() 时被偷看但不会被推进。这导致第一个START_ELEMENT 事件被处理两次。如果您使用StreamResult 而不是DOMResult,则可以很好地观察到这一点。那里不会发生 NPE,但结果流中生成的 XML 将包含两次第一个元素的标记的开头。

    我现在正在尝试使用接收DOMResultXmlEventWriter 来解决此问题。因此,基本上模拟Transformer 会做什么,将每个读取事件直接推送给该作者。如果我成功了,我也会在这里发布我的解决方案。

    PS:我想在 JDK 上报告这个问题,或者最终推一个潜在的解决方案。如果有人能告诉我这应该怎么做,我将不胜感激。

    更新:

    所以,我设法通过上述方法解决了这个问题。根据Reading a big XML file using stax and dom中建议的代码,您可以使用以下方法,而不是使用Transformer

      private Node readToNode(final XMLEventReader reader) throws XMLStreamException, ParserConfigurationException {
        XMLEvent event = reader.peek();
        if (!event.isStartElement()) {
          throw new IllegalArgumentException("reader must be on START_ELEMENT event");
        }
        final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        final XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(new DOMResult(document));
        int depth = 0;
        do {
          event = reader.nextEvent();
          writer.add(event);
          if (event.isStartElement()) {
            depth++;
          } else if (event.isEndElement()) {
            depth--;
          }
        } while (reader.hasNext() && !(event.isEndElement() && depth <= 0));
        return document.getDocumentElement();
      }
    

    但是,这种方法有一些限制!从代码中可以看出,我们需要创建一个包装节点的Document 对象,否则 XML 编写器会遇到问题。如果您打算再次使用Transformer 操作此DOM 并随后将其发送到另一个活动的XMLEventWriter(正如我试图做的那样),它将失败。这是因为Transformer 将向已经启动的编写器发送一个 START_DOCUMENT 事件。我反过来尝试了同样的方法,我。 e.将节点包装成DOMSource,将其发送到另一个XmlEventReader 并将事件通过管道传输到我现有的XmlEventWriter,但这也不起作用,因为XmlEventReader 显然只支持StreamSources(参见here )。

    总而言之,如果您只需要 DOM 对象,这可能会很好,但如果您尝试将 XML 片段转换为将事件管道传输到写入器(就像我一样),您可能会遇到问题。

    【讨论】:

      猜你喜欢
      • 2016-08-11
      • 2019-06-19
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 2012-03-11
      相关资源
      最近更新 更多