问题
I'm being given xml documents (which I have no control its format). I would like to know if it is possible to demarshal this xml based on element attribute id. So different object types will share the same element name.
Also, I'm planning on using Simpile XML because I'm on Android and JAXB doesn't like Android.
So I would like something like:
class Root {
Person p;
Car c;
ArrayList<Person> plist;
}
class Person{
String name;
}
class Car {
String type;
}
from
<root>
<object id="person">
<name> bob </name>
</object>
<object id="car">
<model> ford </ford>
</object>
<sequence id="personSequence">
<object id="person">
<name> bob </name>
</object>
<object id="person">
<name> bob </name>
</object>
</sequence>
</root>
However, I know for sure that the document I am receiving will always be in the same order with the same number of top level elements. For example,
Rool will always have: 1 person, 1 car, 1 person, 2 cars, and a unknnown-size sequence of cars.
<root>
<person />
<car />
<person />
<car />
<car />
<sequence >
I don't know how many objects will be in here
<sequence >
<root>
Thanks so much.
回答1:
You can use a Converter-implementation to do this. This allows you to implement the process of (de-)serialization at your own.
Here's an suggestion how to do it:
- An abstract class as base for all objects (persons, cars etc.)
- Implementations for those
- A root-object containing all other elements
- A
Converter
which creates concrete a root-object from nodes
Btw. you don't have to add those simple-Annotations if you use converters - however, it's always a good idea, just in case you need them.
(Abstract) Base class for all objects:
@Root()
public abstract class ObjectElement
{
@Attribute(name = "id")
private String id;
public ObjectElement(String id)
{
this.id = id;
}
// ...
}
Person class:
@Root(name = "object")
public class PersonObject extends ObjectElement
{
@Element(name = "name")
private String name;
public PersonObject(String name)
{
super("person");
this.name = name;
}
// ...
}
Car class:
@Root(name = "object")
public class CarObject extends ObjectElement
{
@Element(name = "model")
private String model;
public CarObject( String model)
{
super("car");
this.model = model;
}
// ...
}
Sequence class:
@Root(name = "sequence")
public class SequenceObject extends ObjectElement
{
@ElementList(inline = true)
private final List<ObjectElement> elements;
public SequenceObject()
{
super("personSequence");
this.elements = new ArrayList<>();
}
// ...
}
The root
-element; it has instances of it's childs (cars, etc.) and maps the <root> ... </root>
element.
@Root(name = "root")
@Convert(RootElementConverter.class) // Set Converter here!
public class RootElement
{
private final List<ObjectElement> elememts;
public RootElement()
{
this.elememts = new ArrayList<>();
}
public void add(ObjectElement element)
{
this.elememts.add(element);
}
// ...
}
The Converter
:
public class RootElementConverter implements Converter<RootElement>
{
@Override
public RootElement read(InputNode node) throws Exception
{
RootElement root = new RootElement();
/*
* Iterate over all nodes and add them to root. You can use
* "node.getName()" and "node.getAttribute(...)" to test what
* instance you have to add.
*
* Use "root.add(...)" to add nodes.
*/
return root;
}
@Override
public void write(OutputNode node, RootElement value) throws Exception
{
/*
* Implement this if you also serialize to xml.
*/
throw new UnsupportedOperationException("Not supported yet.");
}
}
And finally how to call:
final String xml = ...
// Important: Don't forget the AnnotationStrategy!
Serializer ser = new Persister(new AnnotationStrategy());
// Read root-object from xml-string or whatever
RootElement root = ser.read(RootElement.class, xml);
来源:https://stackoverflow.com/questions/24563401/demarshalling-an-xml-where-attributes-determine-type