2

我想编写一些基本上类似于使用 stax 和 dom 读取大型 XML 文件 但使用 XMLEventReader 而不是 XMLStreamReader 的代码(我需要能够在继续创建 DOM 之前检查某些元素的值)。

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

谢谢!爱洛

4

2 回答 2

2

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

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

于 2013-06-06T15:56:48.587 回答
0

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

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

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

PS:我想在 JDK 上报告这个问题,或者最终推一个潜在的解决方案。如果有人能告诉我这应该如何完成,我将非常感激。

更新:

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

  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 编写器会遇到问题。如果您打算操作此 DOM 并随后XMLEventWriter使用再次将其发送到另一个活动(正如我试图做的那样)Transformer,它将失败。这是因为Transformer将向已经启动的编写器发送一个 START_DOCUMENT 事件。我反过来尝试了相同的方法,即将节点包装成 a DOMSource,将其发送到另一个XmlEventReader并将事件通过管道传输到我现有的XmlEventWriter,但这也不起作用,因为XmlEventReader显然只支持StreamSources (请参见此处)。

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

于 2018-03-01T22:37:04.270 回答