I have a web service which receives XML files and does unmarshalling to convert the XML file to an object. The problem is that my web service can receive different XML structures and has to do the correct unmarshalling.
So I receibe this kind of XML files:
<root>
<user>
<id>1234</id>
</user>
<XMLelements>
...
</XMLelements>
</root>
Notice that XMLelements
is an example tag name, every XML file could have differents names.
So, I think, my web service workflow should be something like:
So I receive different XML structures and for each one I have to do a different unmarshalling to get objects of different classes.
How can I perform this approach? I'm using Spring for marshalling (Metro).
Edit: This question didn't receive any answer, maybe I'm not clear. I'll try to explain it better:
I have a web service which is listening a url where receives XML files. Actually, in the same url path my web service receives two different XML schemas. How can I know how to do unmarshalling correctly? I mean, unmarshalling should return correct object when different XML schemas are passed.
There are a couple of different ways to support this use case.
OPTION #1 - DOM Approach
You could always use a DOM parser to convert the XML to a Document
perform an XPath against it to get the value of the id
element and then unmarshal the document based on the result
OPTION #2 - SAX Approach
LookAheadUnmarshallerHandler
You could leverage a SAX parser and JAXB's UnmarshallerHandler
mechanism and do the following:
ContentHandler
that queues up SAX events until the necessary information is discovered.JAXBContext
based on the value of the id
element.UnmarshallerHandler
from the JAXBContext
.UnmarshallerHandler
.UnmarshallerHandler
on the XMLReader
as the ContentHandler
.UnmarshallerHandler
.package forum13397834;
import java.util.*;
import javax.xml.bind.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
public class LookAheadUnmarshallerHandler extends DefaultHandler {
private XMLReader xmlReader;
private List<Event> events = new ArrayList<Event>();
private UnmarshallerHandler unmarshallerHandler;
public LookAheadUnmarshallerHandler(XMLReader xmlReader) {
this.xmlReader = xmlReader;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
events.add(new StartElement(uri, localName, qName, attributes));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("id".equals(localName) || "id".equals(qName)) {
Characters characters = (Characters) events.get(events.size() - 1);
String value = characters.getString();
JAXBContext jc;
try {
if("1234".equals(value)) {
jc = JAXBContext.newInstance(Root1.class);
} else if("5678".equals(value)) {
jc = JAXBContext.newInstance(Root2.class);
} else {
jc = JAXBContext.newInstance(Root3.class);
}
unmarshallerHandler = jc.createUnmarshaller().getUnmarshallerHandler();
} catch(JAXBException e) {
throw new RuntimeException(e);
}
unmarshallerHandler.startDocument();
for(Event event : events) {
event.event(unmarshallerHandler);
}
unmarshallerHandler.endElement(uri, localName, qName);
xmlReader.setContentHandler(unmarshallerHandler);
} else {
events.add(new EndElement(uri, localName, qName));
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
events.add(new Characters(ch, start, length));
}
public Object getResult() throws JAXBException {
return unmarshallerHandler.getResult();
}
private static abstract class Event {
public abstract void event(ContentHandler contentHandler) throws SAXException;
}
private static class StartElement extends Event {
private String uri;
private String localName;
private String qName;
private Attributes attributes;
public StartElement(String uri, String localName, String qName, Attributes attributes) {
this.uri = uri;
this.localName = localName;
this.qName = qName;
this.attributes = attributes;
}
@Override
public void event(ContentHandler contentHandler) throws SAXException {
contentHandler.startElement(uri, localName, qName, attributes);
}
}
private static class Characters extends Event {
private char[] ch;
private int start;
private int length;
public Characters(char[] ch, int start, int length) {
this.ch = ch;
this.start = start;
this.length = length;
}
@Override
public void event(ContentHandler contentHandler) throws SAXException {
contentHandler.characters(ch, start, length);
}
public String getString() {
return new String(ch, start, length);
}
}
private static class EndElement extends Event {
private String uri;
private String localName;
private String qName;
public EndElement(String uri, String localName, String qName) {
this.uri = uri;
this.localName = localName;
this.qName = qName;
}
@Override
public void event(ContentHandler contentHandler) throws SAXException {
contentHandler.endElement(uri, localName, qName);
}
}
}
JAVA MODEL
The following object model is based on the classes you mention in your question.
UserA
package forum13397834;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="root")
public class UserA {
}
UserB
package forum13397834;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="root")
public class UserB {
}
UserC
package forum13397834;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="root")
public class UserC {
}
INPUT (input.xml)
We will use the XML document from your question as the input for this example.
<root>
<user>
<id>1234</id>
</user>
<XMLelements>
...
</XMLelements>
</root>
DEMO CODE
package forum13397834;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
XMLReader xmlReader = spf.newSAXParser().getXMLReader();
LookAheadUnmarshallerHandler handler = new LookAheadUnmarshallerHandler(xmlReader);
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource("src/forum13397834/input.xml"));
Object object = handler.getResult();
System.out.println(object.getClass());
}
}
Output
class forum13397834.UserA
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.