Monday, April 11, 2011

Is it possible to transform javabeans with XSLT and JXPath?

Suppose I have a vanilla javabean:

class Person {
  String firstName;
  String lastName;
  ...
}

Now suppose I want to transform this into another javabean:

class Human {
  String name;
  ...
}

I'm currently using JXPath to help me transform one to the other:

JXPathContext personContext = JXPathContext.newContext(person);
JXPathContext humanContext = JXPathContext.newContext(new Human());
humanContext.setValue("name", personContext.getValue("firstName") +
                              personContext.getValue("lastName"));

Instead of doing this sort of things by hand, is there a way to use eg XSLT with JXPath to specify these transformations?

From stackoverflow
  • I'm sure it is possible, but it seems a little convoluted. For one, it looks like there is an inheritance relation between the two classes you mention. If so, you should probably have a constructor that accepts the other type as an argument.

    If there is no obvious inheritance relation, why not just use the javabeans setter? What is the need to use JXPath at all here? That would almost certainly be slower.

    VoidPointer : If the two beans come from different modules and the relationships are very complex, there may actually be a benefit in expressing the relationship in a declarative fashion with XSLT. With a simple example as given in the question it would indeed seem convoluted.
  • I think this is not possible with just JXPath as that is an XPath implementation and not an XSLT implementation. XSLT uses XPath as a part of the language, but it is more than that.

    What you could try to to is to serialize your beans to XML, transform the XML with XSLT and deserialize the resulting XML into the target class. Thus, for your person object, you might get

    <person>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
    </person>
    

    You can than use XSLT with a template such as this

    <xslt:template match="/person">
        <human>
            <name><xslt:value-of select="./firstName"/> <xslt:value-of select="./lastName"/></name>
        </human>
    </xslt:template>
    

    This should yield a result document like this:

    <human>
        <name>John Doe</name>
    </human>
    

    This document could than be deserialized into an instance of the Human class.

    Note: The XML representations of the beans is made up for sake of this example. In reality, you could either use the java.beans.XMLEncoder or you could look for any other Java/XML binding implementation that's out there (JAXB, etc...)

    Mario Ortegón : This would be closer to what XML is meant to be used for, to transport data between two different apps. +1

0 comments:

Post a Comment