3 Stimmen

Verwendung von Jettison für den Übergang von JSON zu DOM in Java

Bislang ist dies die Geschichte eines Fehlschlags, und jeder Rat ist willkommen. Ich habe das Folgende versucht:

XMLStreamReader zu Dokument unter Verwendung von JAXP mit Saxon

Der Code:

JSONObject obj = new JSONObject("{\"alice\":{\"bob\": \"a\"}}");
AbstractXMLStreamReader reader = new MappedXMLStreamReader(obj);

StAXSource source = new StAXSource(reader);
Document document = XMLUtils.createDocument();
DOMResult result = new DOMResult(document);
Transformer identity = TransformerUtils.getIdentityTransformer();
identity.transform(source, result);
result.getNode();

Dies schlägt fehl, weil der von uns verwendete Saxon-Transformer keine StAXSource unterstützt. Die Ausnahme ist:

org.orbeon.saxon.trans.DynamicError: A source of type javax.xml.transform.stax.StAXSource is not supported in this environment
    org.orbeon.saxon.event.Sender.send(Sender.java:185)
    org.orbeon.saxon.IdentityTransformer.transform(IdentityTransformer.java:29)
    org.orbeon.oxf.xml.TransformerWrapper.transform(TransformerUtils.java:597)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:93)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

XMLStreamReader zu Dokument unter Verwendung von JAXP mit Xalan

Der Code:

JSONObject obj = new JSONObject("{\"alice\":{\"bob\": \"a\"}}");
AbstractXMLStreamReader reader = new MappedXMLStreamReader(obj);

StAXSource source = new StAXSource(reader);
Document document = XMLUtils.createDocument();
DOMResult result = new DOMResult(document);
Transformer identity = orbeon.apache.xalan.processor.TransformerFactoryImpl.newInstance().newTransformer();
identity.transform(source, result);
result.getNode();

Dies funktioniert nicht mit Xalan 2.5.1 (die Version, die wir verwenden). Die neueste Version ist 2.7.1 und vielleicht haben sie in dieser Version Unterstützung für StAXSource hinzugefügt.

javax.xml.transform.TransformerException: Can't transform a Source of type javax.xml.transform.stax.StAXSource
    orbeon.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:372)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:82)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

XMLStreamReader zu Dokument mit einem XMLEventWriter und DOMResult

Der Code:

JSONObject obj = new JSONObject("{\"alice\":{\"bob\": \"a\"}}");
AbstractXMLStreamReader streamReader = new MappedXMLStreamReader(obj);
XMLInputFactory readerFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = readerFactory.createXMLEventReader(streamReader);

Document document = XMLUtils.createDocument();
DOMResult result = new DOMResult(document);
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(result);
eventWriter.add(eventReader);
eventWriter.close();

result.getNode();

Dieser führt zu einer NPE in Xerces:

java.lang.NullPointerException
    orbeon.apache.xerces.dom.CoreDocumentImpl.setXmlVersion(CoreDocumentImpl.java:850)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    java.lang.reflect.Method.invoke(Method.java:597)
    com.sun.xml.internal.stream.writers.XMLDOMWriterImpl.writeStartDocument(XMLDOMWriterImpl.java:583)
    com.sun.xml.internal.stream.writers.XMLEventWriterImpl.add(XMLEventWriterImpl.java:96)
    com.sun.xml.internal.stream.writers.XMLEventWriterImpl.add(XMLEventWriterImpl.java:72)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:95)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

XMLStreamReader zu Dokument unter Verwendung eines XMLEventWriter und Writer

Der Code:

JSONObject obj = new JSONObject("{\"alice\": {\"bob\": \"a\"}}");
AbstractXMLStreamReader streamReader = new MappedXMLStreamReader(obj);
XMLInputFactory readerFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = readerFactory.createXMLEventReader(streamReader);

StringWriter stringWriter = new StringWriter();
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(stringWriter);
eventWriter.add(eventReader);
eventWriter.close();

out.print(stringWriter.toString());

Mit Java 5 sucht es nach com.bea.xml.stream.MXParserFactory die nirgends zu finden ist:

javax.xml.stream.FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found
    javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:72)
    javax.xml.stream.FactoryFinder.find(FactoryFinder.java:178)
    javax.xml.stream.FactoryFinder.find(FactoryFinder.java:92)
    javax.xml.stream.XMLInputFactory.newInstance(XMLInputFactory.java:136)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:79)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

Bei Java 6 führt dies zu einer NPE in Suns XMLEventAllocatorImpl :

java.lang.NullPointerException
    com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.getXMLEvent(XMLEventAllocatorImpl.java:82)
    com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.allocate(XMLEventAllocatorImpl.java:55)
    com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:86)
    com.sun.xml.internal.stream.writers.XMLEventWriterImpl.add(XMLEventWriterImpl.java:72)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:85)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

BadgerFishDOMDocumentParser verwenden

Code :

ByteArrayInputStream bais = new ByteArrayInputStream("{\"alice\": {\"bob\": \"a\"}}".getBytes());
Document resDOM = new BadgerFishDOMDocumentParser().parse(bais);

Dies führt zu einer NPE in Sun's XMLEventAllocatorImpl :

java.lang.NullPointerException
    com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.getXMLEvent(XMLEventAllocatorImpl.java:82)
    com.sun.xml.internal.stream.events.XMLEventAllocatorImpl.allocate(XMLEventAllocatorImpl.java:55)
    com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:86)
    com.sun.xml.internal.stream.writers.XMLEventWriterImpl.add(XMLEventWriterImpl.java:72)
    org.codehaus.jettison.AbstractDOMDocumentParser.parse(AbstractDOMDocumentParser.java:66)
    org.apache.jsp.gaga_jsp._jspService(gaga_jsp.java:79)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:315)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

1voto

StaxMan Punkte 107669

Nein, ich glaube nicht, dass Xalan Stax unterstützt, aus irgendeinem Grund. Sächsisch Vielleicht können Sie es stattdessen versuchen?

Aber wenn nicht, sollten Sie vielleicht einen DOM-Baum aus Stax erstellen, indem Sie Linktext , wie dieser Artikel erklärt? Xalan akzeptiert die DOM-Quelle als Eingabe.

0voto

JSON ist nicht XML - Es sieht aus wie Sie versuchen, ein JSON-Objekt mit dem XML-Parser zu analysieren? Ich könnte jedoch missverstehen, worauf Sie hinauswollen.

0voto

Jason C Punkte 35780

Ich hatte dieses Problem auch und erlebte die gleichen Frustrationen wie der Auftraggeber. Dieses Verhalten wurde irgendwo auf einer Woodstox-Mailingliste als Fehler erwähnt. Es gelang mir jedoch, eine Lösung zu entwickeln. Ich habe einen sehr einfachen XMLEventReader geschrieben, der einen XMLStreamReader umhüllt, und das hat den Trick gut gemacht. Zwei wichtige Hinweise: 1) Dieser Code wird so zur Verfügung gestellt, wie er ist; insbesondere habe ich ihn nicht gründlich getestet, abgesehen von meiner eigenen begrenzten Verwendung, und 2) Die Tatsache, dass dieses Problem praktisch nirgendwo anders im Internet auftaucht, sowie die Tatsache, dass es sich um eine relativ grundlegende Operation zu handeln scheint, die Jettison ausführen sollte, deutet für mich stark darauf hin, dass wir etwas grundlegend falsch machen und dass diese Lösung nicht notwendig sein sollte. Verwenden Sie Ihr eigenes Urteil.

Hier ist zunächst ein funktionierender XMLEventReader:

import java.util.LinkedList;
import java.util.Queue;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;

import com.sun.xml.internal.stream.events.AttributeImpl;
import com.sun.xml.internal.stream.events.CharacterEvent;
import com.sun.xml.internal.stream.events.CommentEvent;
import com.sun.xml.internal.stream.events.DTDEvent;
import com.sun.xml.internal.stream.events.EndDocumentEvent;
import com.sun.xml.internal.stream.events.EndElementEvent;
import com.sun.xml.internal.stream.events.NamespaceImpl;
import com.sun.xml.internal.stream.events.ProcessingInstructionEvent;
import com.sun.xml.internal.stream.events.StartDocumentEvent;
import com.sun.xml.internal.stream.events.StartElementEvent;

public class WorkingXMLEventReader implements XMLEventReader {

    private final XMLStreamReader streamReader;
    private final Queue<XMLEvent> eventQueue = new LinkedList<XMLEvent>();

    public WorkingXMLEventReader (XMLStreamReader streamReader) {
        this.streamReader = streamReader;
    }

    @Override public Object next () {
        try {
            return nextEvent();
        } catch (XMLStreamException x) {
            return null;
        }
    }

    @Override public void remove () {
        throw new UnsupportedOperationException("WorkingXMLEventReader iterator interface does not support remove()");
    }

    @Override public void close () throws XMLStreamException {
        streamReader.close();
        eventQueue.clear();
    }

    @Override public String getElementText () throws XMLStreamException {
        return streamReader.getElementText();
    }

    @Override public Object getProperty (String key) throws IllegalArgumentException {
        return streamReader.getProperty(key);
    }

    @Override public boolean hasNext () {
        try {
            return !eventQueue.isEmpty() || streamReader.hasNext();
        } catch (XMLStreamException x) {
            return false;
        }
    }

    @Override public XMLEvent nextEvent () throws XMLStreamException {
        if (eventQueue.isEmpty())
            parseEvents(eventQueue, streamReader, streamReader.next());
        return eventQueue.remove();
    }

    @Override public XMLEvent nextTag () throws XMLStreamException {
        if (eventQueue.isEmpty())
            parseEvents(eventQueue, streamReader, streamReader.nextTag());
        return eventQueue.remove();        
    }

    @Override public XMLEvent peek () throws XMLStreamException {
        return eventQueue.peek();
    }

    protected static void parseEvents (Queue<XMLEvent> events, XMLStreamReader reader, int type) {
        switch (type) {
        case XMLEvent.START_ELEMENT: 
            events.add(new StartElementEvent(reader.getName()));
            break;
        case XMLEvent.END_ELEMENT: 
            events.add(new EndElementEvent(reader.getName()));
            break;
        case XMLEvent.CDATA:
            events.add(new CharacterEvent(reader.getText(), true, false));
            break;
        case XMLEvent.SPACE:
            events.add(new CharacterEvent(reader.getText(), false, true));
            break;
        case XMLEvent.CHARACTERS: 
            events.add(new CharacterEvent(reader.getText(), false, false));
            break;
        case XMLEvent.ATTRIBUTE:
            for (int n = 0; n < reader.getAttributeCount(); ++ n) {
                AttributeImpl attr = new AttributeImpl(reader.getAttributePrefix(n), 
                        reader.getAttributeNamespace(n), reader.getAttributeLocalName(n), 
                        reader.getAttributeValue(n), reader.getAttributeType(n));
                events.add(attr);
            }
            break;
        case XMLEvent.NAMESPACE:
            for (int n = 0; n < reader.getNamespaceCount(); ++ n) {
                NamespaceImpl ns = new NamespaceImpl(reader.getNamespacePrefix(n), 
                        reader.getNamespaceURI(n));
                events.add(ns);
            }
            break;
        case XMLEvent.PROCESSING_INSTRUCTION:
            events.add(new ProcessingInstructionEvent(reader.getPITarget(), reader.getPIData()));
            break;
        case XMLEvent.COMMENT:
            events.add(new CommentEvent(reader.getText()));
            break;
        case XMLEvent.START_DOCUMENT:
            events.add(new StartDocumentEvent(reader.getEncoding(), reader.getVersion()));
            break;
        case XMLEvent.END_DOCUMENT:
            events.add(new EndDocumentEvent());
            break;
        case XMLEvent.DTD:
            events.add(new DTDEvent(reader.getText()));
            break;
        }   
    }

}

Als Nächstes wird beschrieben, wie man sie für das Beispiel des Auftraggebers verwendet:

XMLStreamReader streamReader = new MappedXMLStreamReader(new JSONObject("{\"alice\":{\"bob\": \"a\"}}"));
XMLEventReader eventReader = new WorkingXMLEventReader(streamReader);

Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
XMLEventWriter eventWriter = XMLOutputFactory.newInstance().createXMLEventWriter(new DOMResult(document));
eventWriter.add(eventReader);
eventWriter.close();

// test
Source testSource = new DOMSource(document);
Result testResult = new StreamResult(System.out);
TransformerFactory.newInstance().newTransformer().transform(testSource, testResult);

Die Ausgabe sollte in etwa so aussehen:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><alice><bob>a</bob></alice>

Hoffentlich hilft das jemandem.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X