【问题标题】:Convert Java w3c Document to XMLStreamReader将 Java w3c 文档转换为 XMLStreamReader
【发布时间】:2011-11-07 14:54:59
【问题描述】:

我想在我们的代码库中重用一些现有代码,这些代码接受XMLStreamReader 我的应用程序具有所需的数据作为 w3c 文档。

下面的例子是一个最小的测试用例:

public static void main(String[] args) throws Exception {
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = builderFactory.newDocumentBuilder();

    Document doc = builder.newDocument();

    Element rootElement = doc.createElement("Groups");
    doc.appendChild(rootElement);
    Element group = doc.createElement("Group");
    group.setTextContent("Wibble");
    rootElement.appendChild(group);

    DOMSource source = new DOMSource(doc);

    XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(source);

    reader.nextTag();
    System.out.println("NextTag:" + reader.getName());
}

预期的输出应该类似于:NextTag:Groups,但会抛出以下内容:

Exception in thread "main" javax.xml.stream.XMLStreamException: java.net.MalformedURLException
    at com.sun.xml.stream.XMLReaderImpl.setInputSource(XMLReaderImpl.java:196)
    at com.sun.xml.stream.XMLReaderImpl.<init>(XMLReaderImpl.java:179)
    at com.sun.xml.stream.ZephyrParserFactory.createXMLStreamReader(ZephyrParserFactory.java:139)
    at Main.main(Main.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.net.MalformedURLException
    at java.net.URL.<init>(URL.java:601)
    at java.net.URL.<init>(URL.java:464)
    at java.net.URL.<init>(URL.java:413)
    at com.sun.xml.stream.XMLEntityManager.startEntity(XMLEntityManager.java:762)
    at com.sun.xml.stream.XMLEntityManager.startDocumentEntity(XMLEntityManager.java:697)
    at com.sun.xml.stream.XMLDocumentScannerImpl.setInputSource(XMLDocumentScannerImpl.java:300)
    at com.sun.xml.stream.XMLReaderImpl.setInputSource(XMLReaderImpl.java:193)
    ... 8 

当前使用 Java 6 更新 22。

更多信息:ZephyrParserFactory#jaxpSourcetoXMLInputSource 的源似乎表明 Source 对象是通过处理 SystemId 而不是 DOMSource 的实际内容来转换的。

更新:我上面的原始测试用例实际上是使用我的项目类路径运行的,该类路径实际上包括 JAXB 2.2.1 库,而该库又引入了 sjsxp 1.0.1。在干净的类路径上运行会产生:

Exception in thread "main" java.lang.UnsupportedOperationException: Cannot create XMLStreamReader or XMLEventReader from a javax.xml.transform.dom.DOMSource
    at com.sun.xml.internal.stream.XMLInputFactoryImpl.jaxpSourcetoXMLInputSource(XMLInputFactoryImpl.java:302)
    at com.sun.xml.internal.stream.XMLInputFactoryImpl.createXMLStreamReader(XMLInputFactoryImpl.java:145)

这符合@Gary Rowe 的回答。

【问题讨论】:

  • 它是否正在尝试下载 xsd?
  • nope..xml 或多或少是您上面的内容:Wibble
  • 只是头脑风暴。你不应该在 createXMLStreamReader 中使用 source.getSystemId() 吗?
  • createXmlStreamReader 确实使用了 getSystemId,我认为这是我痛苦的根源。 DOMSource 没有 systemId。
  • 我正在寻找相反的:XMLStreamReaderDocument :-(

标签: java xml stax xmlstreamreader


【解决方案1】:

Woodstox 的 WstxDOMWrappingReader 类正好满足您的需求。请参阅https://fasterxml.github.io/woodstox/javadoc/5.0/com/ctc/wstx/dom/WstxDOMWrappingReader.html 上的 Javadoc

小例子:

  DOMSource domSource = new DOMSource(node);
  ReaderConfig config = ReaderConfig.createFullDefaults();
  XMLStreamReader reader = WstxDOMWrappingReader.createFrom(domSource, config);

【讨论】:

    【解决方案2】:

    我使用以下代码遇到了同样的错误(Windows 7/Oracle JDK 7):

    DOMSource domSource = new DOMSource(element);
    XMLEventReader parser = XMLInputFactory.newInstance().createXMLEventReader(domSource);
    

    我通过添加一个新的 Woodstox 依赖项来修复它:

    <dependency>
        <groupId>org.codehaus.woodstox</groupId>
        <artifactId>woodstox-core-lgpl</artifactId>
        <version>4.1.5</version>
    </dependency>
    

    但这也是一个讨厌的解决方案。

    【讨论】:

      【解决方案3】:

      我的实用解决方案是使用ByteArrayOutputStream 将文档输出到byte 数组,然后使用ByteArrayInputStream 将其反馈回

      Transformer xformer = TransformerFactory.newInstance().newTransformer();
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      StreamResult out = new StreamResult(outputStream);
      xformer.transform(source, out);
      reader = xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(outputStream.toByteArray()));
      

      它不漂亮,但它有效。

      【讨论】:

      • 它不仅不美观,而且还涉及序列化和重新解析文档,这在时间和内存使用方面都非常昂贵。
      【解决方案4】:

      这有点令人费解,但任何支持 XQJ API(例如 Saxon)的 XQuery 实现都将允许您提供一个 DOM 作为查询“.”的输入,并以 XMLStreamReader 的形式获得结果。虽然涉及很多重量级机器,但它应该非常高效。

      使用 Saxon,您还可以使用类似的东西将 XQuery 端短路

      Document doc; // the DOM document
      XMLStreamReader reader = new PullToStax(PullProvider.makePullProvider(new DocumentWrapper(doc));
      

      但我认为 XQJ 方法更清洁。

      【讨论】:

        【解决方案5】:

        在我看来 DOMSource 不是 StreamSource 的实例,所以它被踢出。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-07-22
          • 2014-09-17
          • 1970-01-01
          • 2011-07-29
          • 2017-01-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多