tanstaafl
tanstaafl

Reputation: 168

Transform java objects to dynamic xml

I'm working with a dynamic xml table format consisting of a schema that specifies column names and types, and a values tag which contains the rows. Simplified version of xsd below:

<xs:complexType name="data">
    <xs:sequence>
        <xs:element name="schema" type="schema"/>
        <xs:element name="values" type="values"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="schema">
    <xs:anyAttribute/>
</xs:complexType>

<xs:complexType name="values">
    <xs:anyAttribute/>
</xs:complexType>

And a example xml generated by it:

<data>
    <schema firstName="string" lastName="string" age="integer">
    <values>
        <value firstName="A" lastName="B" age="23"/>
        <value firstName="C" lastName="D" age="63"/>
        …
    </values>
</data>

Data to generate the xml comes from a list of data objects, for our example:

public class Person {
    private String firstName;
    private String lastName;
    private int age;

    // getters and setters…
}

Currently I'm creating it by adding code like this to the class (I'm using jaxb to generate the xml):

private static QName FIRST_NAME = new QName("firstName");
private static QName LAST_NAME = new QName("lastName");
private static QName AGE = new QName("age");

private static Map<QName, String> schema;

static {
    schema = new HashMap<QName, String>();
    schema.put(FIRST_NAME, "string");
    schema.put(LAST_NAME, "string");
    schema.put(AGE, "integer"):
}

public Map<QName, String> asMap() {
    Map<QName, String> map = new HashMap<QName, String>();
    map.put(FIRST_NAME, firstName);
    map.put(LAST_NAME, lastName);
    map.put(AGE, Integer.toString(age)):
    return map;
}

public static Map<QName, String> getSchema() {
    return schema;
}

And then do that for each data object that would be used to generate xml. This works though I don't feel it's the best solution. Major problem I see with it is that there is no connection between the schema and the values, if something changes in one of them you have to remember to update the other one too. Also it's a bit noisy adding this to all classes.

Could someone suggest a better (cleaner/more generic) way of doing this? Maybe some good way to auto generate the schema and/or values maps? Or any other suggestion....

(It probably would be nicest if I could have something that worked given any java bean without changing the class, but I'm fine with decorating / adding things to the class if necessary.)

Thanks

Upvotes: 1

Views: 750

Answers (1)

Gabriel Jiva
Gabriel Jiva

Reputation: 184

The whole problem is that the table is dynamic. Does it need to be?

If not, the solution is straightforward, because you can make a static table and then bind it to Java beans using JAXB.

If it does need to be dynamic, then the only thing you can do is link static instances of the table to Java beans using a custom binder. Meaning if you have a static instance of the table that contains firstName, lastName and age, then you can write a custom binder that will generate Java beans from that table, which will have the proper bindings (firstName, lastName and age), which is what you're now doing manually. The problem with this approach is writing the binding tool.

But using off-the-shelf software, the easiest thing to do would be to not use the dynamic table and instead write schemas for each instance of the dynamic table. The XML documents from these schemas would still conform to the one that defines the dynamic table, but it would allow you to use JAXB to automate all the code generation and keep the Java classes in sync with the XML documents.

Upvotes: 2

Related Questions