Reputation: 1741
I have a XML in which some common part that wrappes a specific part that can change in any way.
For example I would have to manage these 2 XML (simplified):
...
<xml>
<common>
<data1>1</data1>
<data2>2</data2>
</common>
<specific>
<specific-info>
<color>blue</color>
</specific-info>
</specific>
</xml>
...
And this one:
...
<xml>
<common>
<data1>33</data1>
<data2>42</data2>
</common>
<specific>
<another-info>
<age>42</age>
</another-info>
</specific>
</xml>
...
So I've inherit this code (simplified), using JAXB, that works:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {})
@XmlRootElement(name = "xml")
public class Specific{
@XmlElement(name = "common", required = true)
protected CommonData common;
@XmlElement(name = "specific")
protected SpecificInfo specificInfo;
@XmlElement(name = "specific")
protected AnotherInfo anotherInfo;
// getters and setters
}
The problem is that when a new sort of info arrives I've to add new XMLElement with same name and I think that it smells... And also that they are getters an setters for each of it.
There's another way to afford this? It's a standar way to unwrap a wrapped XML with JAXB?
Upvotes: 1
Views: 179
Reputation: 143
If I understand your need, you want to be able to get content of another elements into <specific/>
?
so maybe you can take a look to @XmlAnyElement depending on the structure your want to catch.
you might be interested in lax attribute aiming to preserve the processing of specificInfo and anotherInfo
@XmlAnyElement(lax="true")
public Object[] others;
Upvotes: 1
Reputation: 1741
In the way that @fisc showed me I used in my bean @XmlAnyElement in his way:
@XmlAnyElement(lax=true)
public Object[] others;
Which gets the specific part of the xml as an xml DOM object and ALSO this method to get the actual object and not a DOM representation of whatever there is in the xml:
@SuppressWarnings("unchecked")
public <T> T getOthersParsedAs(Class<T> clazz) throws JAXBException{
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
T res = (T) unmarshaller.unmarshal((Node)others[0]);
if (res instanceof JAXBElement){
res = (T)JAXBIntrospector.getValue(res);
}
return res;
}
This way I cant get them with:
Specific spec = ...
SpecificInfo info = spec.getOthersParsedAs(SpecificInfo.class);
or:
AnotherInfo info = spec.getOthersParsedAs(AnotherInfo .class);
UPDATE:
I've done a method to insert any object to that xml in that node (ugly but shows all the code in same method):
public <T> void setOthersInXML(T data) throws JAXBException, ParserConfigurationException{
JAXBContext context = JAXBContext.newInstance(data.getClass());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db= dbf.newDocumentBuilder();
Document document = db.newDocument();
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(data, document);
others = new Object[]{document.getDocumentElement()};
}
And is used like a setter.
Edited again
Because I found a problem: if the class haven't well defined the XMLRootElement getOthersParsedAs will return you a JAXBElement object and this could be problematic, so I've added the check to the method
Upvotes: 1