Преобразование документа Java w3c в XMLStreamReader

Я хотел бы повторно использовать некоторый существующий код в нашей базе кода, который принимает 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.


person Gareth Davis    schedule 31.08.2011    source источник
comment
Он пытается загрузить xsd?   -  person sje397    schedule 31.08.2011
comment
нет.. xml более или менее соответствует тому, что у вас есть выше: ‹Groups›‹Group›Wibble‹/Group›‹/Groups›   -  person Gareth Davis    schedule 31.08.2011
comment
просто мозговой штурм. Разве вы не должны использовать source.getSystemId() внутри createXMLStreamReader?   -  person dierre    schedule 31.08.2011
comment
createXmlStreamReader действительно использует getSystemId, и я думаю, что это корень моей боли. DOMSource не имеет системного идентификатора.   -  person Gareth Davis    schedule 31.08.2011
comment
Я ищу наоборот: XMLStreamReader на Document :-(   -  person fommil    schedule 27.11.2013


Ответы (5)


Это несколько запутанно, но любая реализация XQuery, поддерживающая XQJ API (например, Saxon), позволит вам предоставить DOM в качестве входных данных для запроса "." и получить результат в виде XMLStreamReader. Несмотря на то, что задействовано много тяжелой техники, она должна быть совершенно эффективной.

С Saxon вы также можете обойти сторону XQuery, используя что-то вроде

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

но я думаю, что подход XQJ чище.

person Michael Kay    schedule 31.08.2011

Woodstox предоставляет именно то, что вам нужно, с классом WstxDOMWrappingReader. См. Javadoc по адресу https://fasterxml.github.io/woodstox/javadoc/5.0/com/ctc/wstx/dom/WstxDOMWrappingReader.html

Небольшой пример:

  DOMSource domSource = new DOMSource(node);
  ReaderConfig config = ReaderConfig.createFullDefaults();
  XMLStreamReader reader = WstxDOMWrappingReader.createFrom(domSource, config);
person Bas de Bakker    schedule 15.03.2016

Мне кажется, что DOMSource не является экземпляром StreamSource, поэтому его выгоняют.

person Gary Rowe    schedule 31.08.2011

Мое прагматичное решение заключалось в том, чтобы вывести документ в массив byte, используя ByteArrayOutputStream, а затем передать его обратно, используя 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()));

Это некрасиво, но это работает.

person Gareth Davis    schedule 01.09.2011
comment
Это не только непривлекательно, но и требует сериализации и повторного анализа документа, что может быть очень затратным как по времени, так и по использованию памяти. - person Michael Kay; 04.09.2011

Я столкнулся с той же ошибкой (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>

Но это тоже неприятное решение.

person Jan Tosovsky    schedule 13.10.2013