Transformation

Exclusive offer: get 50% off this eBook here
Apache Camel Developer's Cookbook

Apache Camel Developer's Cookbook — Save 50%

Solve common integration tasks with over 100 easily accessible Apache Camel recipes with this book and ebook

$29.99    $15.00
by Jakub Korab Scott Cranton | December 2013 | Cookbooks Java

This article by Scott Cranton and Jakub Korab, the authors of Apache Camel Developer's Cookbook, introduces various ways in which Camel allows us to transform or convert between and manipulate common message formats such as Java objects, XML, and JSON. The following ways are discussed in this article:

  • Transforming using a Simple Expression
  • Transforming inline with XQuery
  • Transforming with XSLT
  • Transforming from Java to XML with JAXB
  • Transforming from Java to JSON
  • Transforming from XML to JSON

(For more resources related to this topic, see here.)

The latest version of the example code for this article can be found at http://github.com/CamelCookbook/camel-cookbook-examples.

You can also download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

In this article we will explore a number of ways in which Camel performs message content transformation:

Let us first look at some important concepts regarding transformation of messages in Camel:

  • Using the transform statement. This allows you to reference Camel Expression Language code within the route to do message transformations.
  • Calling a templating component, such as Camel's XSLT or Velocity template style components. This will typically reference an external template resource that is used in transforming your message.
  • Calling a Java method (for example, beanref), defined by you, within a Camel route to perform the transformation. This is a special case processor that can invoke any referenced Java object method.
  • Camel's Type Converter capability that can automatically cast data from one type to another transparently within your Camel route. This capability is extensible, so you can add your own Type Converters.
  • Camel's Data Format capability that allows us to use built-in, or add our own, higher order message format converters. A Camel Data Format goes beyond simple data type converters, which handle simple data type translations such as String to int, or File to String. Data Formats are used to translate between a low-level representation (XML) and a high-level one (Java objects). Other examples include encrypting/decrypting data, and compressing/decompressing data. For more, see http://camel.apache.org/data-format.html.

A number of Camel architectural concepts are used throughout this article. Full details can be found at the Apache Camel website at http://camel.apache.org.

The code for this article is contained within the camel-cookbook-transformation module of the examples.

Transforming using a Simple Expression

When you want to transform a message in a relatively straightforward way, you use Camel's transform statement along with one of the Expression Languages provided by the framework. For example, Camel's Simple Expression Language provides you with a quick, inline mechanism for straightforward transformations.

This recipe will show you how to use Camel's Simple Expression Language to transform the message body.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.simple package. Spring XML files are located under src/main/resources/META-INF/spring and are prefixed with simple.

How to do it...

In a Camel route, use a transform DSL statement containing the Expression Language code to do your transformation.

In the XML DSL, this is written as follows:

<route> <from uri="direct:start"/> <transform> <simple>Hello ${body}</simple> </transform> </route>

In the Java DSL, the same route is expressed as:

from("direct:start") .transform(simple("Hello ${body}"));

In this example, the message transformation prefixes the incoming message with the phrase Hello using the Simple Expression Language.

The processing step after the transform statement will see the transformed message content in the body of the exchange.

How it works...

Camel's Simple Expression Language is quite good at manipulating the String content through its access to all aspects of the message being processed, through its rich String and logical operators.

The result of your Simple Expression becomes the new message body after the transform step. This includes predicates such as using Simple's logical operators, to evaluate a true or false condition; the results of that Boolean operation become the new message body containing a String: "true" or "false".

The advantage of using a distinct transform step within a route, as opposed to embedding it within a processor, is that the logic is clearly visible to other programmers. Ensure that the expression embedded within your route is kept simple so as to not distract the next developer from the overall purpose of the integration. It is best to move more complex (or just lengthy) transformation logic into its own subroute, and invoke it using direct: or seda:.

There's more...

The transform statement will work with any Expression Language available in Camel, so if you need more powerful message processing capabilities you can leverage scripting languages such as Groovy or JavaScript (among many others) as well. The Transforming inline with XQuery recipe will show you how to use the XQuery Expression Language to do transformations on XML messages.

See also

Transforming inline with XQuery

Camel supports the use of Camel's XQuery Expression Language along with the transform statement as a quick and easy way to transform an XML message within a route.

This recipe will show you how to use an XQuery Expression to do in-route XML transformation.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.xquery package. Spring XML files are located under src/main/resources/META-INF/spring and prefixed with xquery.

To use the XQuery Expression Language, you need to add a dependency element for the camel-saxon library, which provides the implementation for the XQuery Expression Language.

Add the following to the dependencies section of your Maven POM:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-saxon</artifactId> <version>${camel-version}</version> </dependency>

How to do it...

In the Camel route, specify a transform statement followed by the XQuery Expression Language code to do your transformation.

In the XML DSL, this is written as:

<route> <from uri="direct:start"/> <transform> <xquery> <books>{ for $x in /bookstore/book where $x/price>30 order by $x/title return $x/title }</books> </xquery> </transform> </route>

When using the XML DSL, remember to XML encode the XQuery embedded XML elements. Therefore, < becomes &lt; and > becomes &gt;.

In the Java DSL, the same route is expressed as:

from("direct:start") .transform(xquery("<books>{ for $x in /bookstore/book " + "where $x/price>30 order by $x/title " + "return $x/title }</books>"));

Feed the following input XML message through the transformation:

<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="PROGRAMMING"> <title lang="en">Apache Camel Developer's Cookbook</title> <author>Scott Cranton</author> <author>Jakub Korab</author> <year>2013</year> <price>49.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>

The resulting message will be:

<books> <title lang="en">Apache Camel Developer's Cookbook</title> <title lang="en">Learning XML</title> </books>

The processing step after the transform statement will see the transformed message content in the body of the exchange.

How it works...

Camel's XQuery Expression Language is a good way to inline XML transformation code within your route. The result of the XQuery Expression becomes the new message body after the transform step.

All of the message's body, headers, and properties are made available to the XQuery Processor, so you can reference them directly within your XQuery statement. This provides you with a powerful mechanism for transforming XML messages. If you are more comfortable with XSLT, take a look at the Transforming with XSLT recipe.

In-lining the transformation within your integration route can sometimes be an advantage as you can clearly see what is being changed. However, when the transformation expression becomes so complex that it starts to overwhelm the integration route, you may want to consider moving the transformation expression outside of the route.

See the Transforming using a Simple Expression recipe for another inline transformation example, and see the Transforming with XSLT recipe for an example of externalizing your transformation.

You can fetch the XQuery Expression from an external file using Camel's resource reference syntax. To reference an XQuery file on the classpath you can specify:

<transform> <xquery>resource:classpath:/path/to/myxquery.xml</xquery> </transform>

This is equivalent to using XQuery as an endpoint:

<to uri="xquery:classpath:/path/to/myxquery.xml"/>

There's more...

The XQuery Expression Language allows you to pass in headers associated with the message. These will show up as XQuery variables that can be referenced within your XQuery statements. Consider, from the previous example, to allow the value of the books that are filtered to be passed in with the message body, that is, parameterize the XQuery, you can modify the XQuery statement as follows:

<transform> <xquery> declare variable $in.headers.myParamValue as xs:integer external; <books value='{$in.headers.myParamValue}'&gt;{ for $x in /bookstore/book where $x/price>$in.headers.myParamValue order by $x/title return $x/title }&lt;/books&gt; </xquery> </transform>

Message headers will be associated with an XQuery variable called in.headers.<name of header>. To use this in your XQuery, you need to explicitly declare an external variable of the same name and XML Schema (xs:) type as the value of the message header.

The transform statement will work with any Expression Language enabled within Camel, so if you need more powerful message processing capabilities you can leverage scripting languages such as Groovy or JavaScript (among many others) as well. The Transforming using a Simple Expression recipe will show you how to use the Simple Expression Language to do transformations on String messages.

See also

Transforming with XSLT

When you want to transform an XML message using XSLT, use Camel's XSLT Component. This is similar to the Transforming inline with XQuery recipe except that there is no XSLT Expression Language, so it can only be used as an endpoint.

This recipe will show you how to transform a message using an external XSLT resource.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.xslt package. Spring XML files are located under src/main/resources/META-INF/spring and prefixed with xslt.

How to do it...

In a Camel route, add the xslt processor step into the route at the point where you want the XSLT transformation to occur. The XSLT file must be referenced as an external resource, and depending on where the file is located, prefixed with either classpath:(default if not using a prefix), file:, or http:.

In the XML DSL, this is written as:

<route> <from uri="direct:start"/> <to uri="xslt:book.xslt"/> </route>

In the Java DSL, the same route is expressed as:

from("direct:start") .to("xslt:book.xslt");

The next processing step in the route will see the transformed message content in the body of the exchange.

How it works...

The following example shows how the preceding steps will process an XML file.

Consider the following input XML message:

<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="PROGRAMMING"> <title lang="en">Apache Camel Developer's Cookbook</title> <author>Scott Cranton</author> <author>Jakub Korab</author> <year>2013</year> <price>49.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>

Process this with the following XSLT contained in books.xslt:

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="/"> <books> <xsl:apply-templates select="/bookstore/book/title[../price>30]"> <xsl:sort select="."/> </xsl:apply-templates> </books> </xsl:template> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>

The result will appear as follows:

<books> <title lang="en">Apache Camel Developer's Cookbook</title> <title lang="en">Learning XML</title> </books>

The Camel XSLT Processor internally runs the message body through a registered Java XML transformer using the XSLT file referenced by the endpoint. This processor uses Camel's Type Converter capabilities to convert the input message body type to one of the supported XML source models in the following order of priority:

  • StAXSource (off by default; this can be enabled by setting allowStAX=true on the endpoint URI)
  • SAXSource
  • StreamSource
  • DOMSource

Camel's Type Converter can convert from most input types (String, File, byte[], and so on) to one of the XML source types for most XML content loaded through other Camel endpoints with no extra work on your part. The output data type for the message is, by default, a String, and is configurable using the output parameter on the xslt endpoint URI.

There's more...

The XSLT Processor passes in headers, properties, and parameters associated with the message. These will show up as XSLT parameters that can be referenced within your XSLT statements.

You can pass in the names of the books as parameters to the XSLT template; to do so, modify the previous XLST as follows:

<xsl:param name="myParamValue"/> <xsl:template match="/"> <books> <xsl:attribute name="value"> <xsl:value-of select="$myParamValue"/> </xsl:attribute> <xsl:apply-templates select="/bookstore/book/title[../price>$myParamValue]"> <xsl:sort select="."/> </xsl:apply-templates> </books> </xsl:template>

The Exchange instance will be associated with a parameter called exchange; the IN message with a parameter called in; and the message headers, properties, and parameters will be associated XSLT parameters with the same name. To use these in your XSLT, you need to explicitly declare a parameter of the same name in your XSLT file. In the previous example, it is possible to use either a message header or exchange property called myParamValue.

See also

Transforming from Java to XML with JAXB

Camel's JAXB Component is one of a number of components that can be used to convert your XML data back and forth from Java objects. It provides a Camel Data Format that allows you to use JAXB annotated Java classes, and then marshal (Java to XML) or unmarshal (XML to Java) your data.

JAXB is a Java standard for translating between XML data and Java that is used by creating annotated Java classes that bind, or map, to your XML data schema. The framework takes care of the rest.

This recipe will show you how to use the JAXB Camel Data Format to convert back and forth from Java to XML.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.jaxb package. The Spring XML files are located under src/main/resources/META-INF/spring and prefixed with jaxb.

To use Camel's JAXB Component, you need to add a dependency element for the camel-jaxb library, which provides the implementation for the JAXB Data Format.

Add the following to the dependencies section of your Maven POM:

<dependency> lt;groupId>org.apache.camel</groupId> <artifactId>camel-jaxb</artifactId> <version>${camel-version}</version> lt;/dependency>

How to do it...

The main steps for converting between Java and XML are as follows:

  1. Given a JAXB annotated model, reference that model within a named Camel Data Format.
  2. Use that named Data Format within your Camel route using the marshal and unmarshal DSL statements.
  3. Create an annotated Java model using standard JAXB annotations. There are a number of external tools that can automate this creation from existing XML or XSD (XML Schema) files:

    @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "title", "author", "year", "price" } ) @XmlRootElement(name = "book") public class Book { @XmlElement(required = true) protected Book.Title title; @XmlElement(required = true) protected List<String> author; protected int year; protected double price; // getters and setters }

  4. Instantiate a JAXB Data Format within your Camel route that refers to the Java package(s) containing your JAXB annotated classes.

    In the XML DSL, this is written as:

    <camelContext xmlns="http://camel.apache.org/schema/spring"> <dataFormats> <jaxb id="myJaxb" contextPath="org.camelcookbook .transformation.myschema"/> </dataFormats> <!-- route definitions here --> </camelContext>

    In the Java DSL, the Data Format is defined as:

    public class JaxbRouteBuilder extends RouteBuilder { @Override public void configure() throws Exception { DataFormat myJaxb= new JaxbDataFormat( "org.camelcookbook.transformation.myschema"); // route definitions here } }

  5. Reference the Data Format within your route, choosing marshal(Java to XML) or unmarshal(XML to Java) as appropriate.

    In the XML DSL, this routing logic is written as:

    <route> <from uri="direct:unmarshal"/> <unmarshal ref="myJaxb"/> </route>

    In the Java DSL, this is expressed as:

    from("direct:unmarshal").unmarshal(myJaxb);

How it works...

Using Camel JAXB to translate your XML data back and forth to Java makes it much easier for the Java processors defined later on in your route to do custom message processing. This is useful when the built-in XML translators (for example, XSLT or XQuery) are not enough, or you just want to call existing Java code.

Camel JAXB eliminates the boilerplate code from your integration flows by providing a wrapper around the standard JAXB mechanisms for instantiating the Java binding for the XML data.

There's more...

Camel JAXB works just fine with existing JAXB tooling like the maven-jaxb2-plugin plugin, which can automatically create JAXB-annotated Java classes from an XML Schema (XSD).

See also

Transforming from Java to JSON

Camel's JSON Component is used when you need to convert your JSON data back and forth from Java. It provides a Camel Data Format that, without any requirement for an annotated Java class, allows you to marshal (Java to JSON) or unmarshal (JSON to Java) your data.

There is only one step to using Camel JSON to marshal and unmarshal XML data. Within your Camel route, insert the marshal(Java to JSON), or unmarshal(JSON to Java) statement, and configure it to use the JSON Data Format.

This recipe will show you how to use the camel-xstream library to convert from Java to JSON, and back.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.transformation.json package. The Spring XML files are located under src/main/resources/META-INF/spring and prefixed with json.

To use Camel's JSON Component, you need to add a dependency element for the camel-xstream library, which provides an implementation for the JSON Data Format using the XStream library.

Add the following to the dependencies section of your Maven POM:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-xstream</artifactId> <version>${camel-version}</version> </dependency>

How to do it...

Reference the Data Format within your route, choosing the marshal (Java to JSON), or unmarshal (JSON to Java) statement, as appropriate:

In the XML DSL, this is written as follows:

<route> <from uri="direct:marshal"/> <marshal> <json/> </marshal> <to uri="mock:marshalResult"/> </route>

In the Java DSL, this same route is expressed as:

from("direct:marshal") .marshal().json() .to("mock:marshalResult");

How it works...

Using Camel JSON simplifies translating your data between JSON and Java. This is convenient when you are dealing with REST endpoints and need Java processors in Camel to do custom message processing later on in the route.

Camel JSON provides a wrapper around the JSON libraries for instantiating the Java binding for the JSON data, eliminating more boilerplate code from your integration flows.

There's more...

Camel JSON works with the XStream library by default, and can be configured to use other JSON libraries, such as Jackson or GSon. These other libraries provide additional features, more customization, and more flexibility that can be leveraged by Camel. To use them, include their respective Camel components, for example, camel-jackson, and specify the library within the json element:

<dataFormats> <json id="myJson" library="Jackson"/> </dataFormats>

See also

Transforming from XML to JSON

Camel provides an XML JSON Component that converts your data back and forth between XML and JSON in a single step, without an intermediate Java object representation. It provides a Camel Data Format that allows you to marshal (XML to JSON), or unmarshal (JSON to XML) your data.

This recipe will show you how to use the XML JSON Component to convert from XML to JSON, and back.

Getting ready

Java code for this recipe is located in the org.camelcookbook.transformation.xmljson package. Spring XML files are located under src/main/resources/META-INF/spring and prefixed with xmljson.

To use Camel's XML JSON Component, you need to add a dependency element for the camel-xmljson library, which provides an implementation for the XML JSON Data Format.

Add the following to the dependencies section of your Maven POM:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-xmljson</artifactId> <version>${camel-version}</version> </dependency>

How to do it...

Reference the xmljson Data Format within your route, choosing the marshal(XML to JSON), or unmarshal(JSON to XML) statement, as appropriate:

In the XML DSL, this is written as follows:

<route> <from uri="direct:marshal"/> <marshal> <xmljson/> </marshal> <to uri="mock:marshalResult"/> </route>

In the Java DSL, this same route is expressed as:

from("direct:marshal") .marshal().xmljson() .to("mock:marshalResult");

How it works...

Using the Camel XML JSON Component simplifies translating your data between XML and JSON, making it convenient to use when you are dealing with REST endpoints. The XML JSON Data Format wraps around the Json-lib library, which provides the core translation capabilities, eliminating more boilerplate code from your integration flows.

There's more...

You may need to configure XML JSON if you want to fine-tune the output of your transformation. For example, consider the following JSON:

[{"@category":"PROGRAMMING","title":{"@lang":"en","#text": "Apache Camel Developer's Cookbook"},"author":[ "Scott Cranton","Jakub Korab"],"year":"2013","price":"49.99"}]

This will be converted as follows, by default, which may not be exactly what you want (notice the <a> and <e> elements):

<?xml version="1.0" encoding="UTF-8"?> <a> <e category="PROGRAMMING"> <author> <e>Scott Cranton</e> <e>Jakub Korab</e> </author> <price>49.99</price> <title lang="en">Apache Camel Developer's Cookbook</title> <year>2013</year> </e> </a>

To configure XML JSON to use <bookstore> as the root element instead of <a>, use <book> for the individual elements instead of <e>, and expand the multiple author values to use a sequence of <author> elements, you would need to tune the configuration of the Data Format before referencing it in your route.

In the XML DSL, the definition of the Data Format and the route that uses it is written as follows:

<dataFormats> <xmljson id="myXmlJson" rootName="bookstore" elementName="book" expandableProperties="author author"/> </dataFormats> <route> <from uri="direct:unmarshalBookstore"/> <unmarshal ref="myXmlJson"/> <to uri="mock:unmarshalResult"/> </route>

In the Java DSL, the same thing is expressed as:

XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat(); xmlJsonFormat.setRootName("bookstore"); xmlJsonFormat.setElementName("book"); xmlJsonFormat.setExpandableProperties( Arrays.asList("author", "author")); from("direct:unmarshalBookstore") .unmarshal(xmlJsonFormat) .to("mock:unmarshalBookstoreResult");

This will result in the previous JSON being unmarshalled as follows:

<?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="PROGRAMMING">
<author>Scott Cranton</author> <author>Jakub Korab</author>
<price>49.99</price> <title lang="en">Apache Camel Developer's
Cookbook</title> <year>2013</year> </book> </bookstore>

See also

Summary

We saw how Apache Camel is flexible in allowing us to transform and convert messages in various formats. This makes Apache Camel an ideal choice for integrating different systems together.

Resources for Article:


Further resources on this subject:


Apache Camel Developer's Cookbook Solve common integration tasks with over 100 easily accessible Apache Camel recipes with this book and ebook
Published: December 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Jakub Korab

Jakub Korab is a consulting software engineer specializing in integration and messaging. With a formal background in software engineering and distributed systems, in the 14 years that he has worked in software across the telecoms, financial services, and banking industries, he naturally gravitated from web development towards systems integration. When he discovered Apache Camel, it became apparent to him how much time and effort it could have saved him in the past compared to writing bespoke integration code, and he has not looked back since.

Over the years, working as a consultant, he has helped dozens of clients build scalable, fault-tolerant, and performant systems integrations. He currently runs his own specialist consultancy, Ameliant, which focuses on systems integration and messaging using a stack of integration products from the Apache Software Foundation, of which Camel is a corner stone.

When not gluing systems together, you will find him spending time with his young family, and far too infrequently kitesurfing or skiing—neither of which he gets much chance to do in his adopted home, London.

Scott Cranton

Scott Cranton is an open source software contributor and evangelist. He has been working with Apache Camel since the release of version 1.5 almost 5 years ago, and has over 20 years of commercial experience in middleware software as a developer, architect, and consultant. During his time at FuseSource, and now Red Hat, he has worked closely with many core committers for Apache Camel, ActiveMQ, ServiceMix, Karaf, and CXF. He has also helped many companies successfully create and deploy large and complex integration and messaging systems using Camel and other open source projects.

He divides his professional time between hacking code, delivering webinars on using Camel and open source, and helping companies to learn how to use Camel to solve their integration problems.

Books From Packt


Instant Apache Camel Message Routing [Instant]
Instant Apache Camel Message Routing [Instant]

Instant Apache Camel Messaging System [Instant]
Instant Apache Camel Messaging System [Instant]

Apache Maven 3 Cookbook
Apache Maven 3 Cookbook

Instant Apache ServiceMix How-to [Instant]
Instant Apache ServiceMix How-to [Instant]

Apache Kafka
Apache Kafka

Apache Axis2 Web Services, 2nd Edition
Apache Axis2 Web Services, 2nd Edition

Quickstart Apache Axis2
Quickstart Apache Axis2

Apache Solr Beginner’s Guide
Apache Solr Beginner’s Guide

Your rating: None Average: 1.6 (5 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
f
5
h
Q
P
T
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software