Search code examples
groovyapache-camelsmooks

Using Smooks or Groovy with Java Camel to split/transform XML


Camel version 2.14 Smooks version 1.5.1

I got a message which i want to split and transform, but i need the id from the parent. So I thought about using Smooks, splitting the message, transforming and send each output to a queue. Which will be using freemarker template for the transform.

<!-- Message -->
<data>
<id>123</id> <!-- This is needed in both portal messages -->
    <portals>
        <portal id="1" />
        <portal id="2" />
    </portals
</data>

<!-- Msg 1 -->
<portal dataId="123">
    <id>1</id>
<portal>

<!-- Msg 2 -->
<portal dataId="123">
    <id>2</id>
<portal>

There are plenty of examples. But for example the camel examples does not work, due to "java.lang.ClassNotFoundException: org.apache.camel.component.ResourceBasedComponent" which is a known issue.

An alternative would be using groovy for transformation?

So, how could this easiest be solved?


Solution

  • I don't know about smooks, but you can combine the XSLT transformer with a XPATH splitter to do this.

    First, transform the data into the blocks that should make up each message. Do it using XSLT, groovy or whatever you feel comfortable with. Here is a simple stylesheet, to be put into src/main/resources (or any classpath location).

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/">
        <portals>
            <xsl:variable name="dataId" select="/data/id"/>
            <xsl:for-each select="/data/portals/portal">
                <portal dataId="$dataId">
                    <xsl:attribute name="dataId">
                        <xsl:value-of select="/data/id"/>
                    </xsl:attribute>
                    <id><xsl:value-of select="@id"/></id>
                </portal>
            </xsl:for-each>
        </portals>
    </xsl:template>
    

    The Camel route: First the transform, then splitter. The "to" can be whatever, like a seda/direct for further processing or the target protocol.

    <camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
      <from uri="file:data"/>
      <to uri="xslt:transform.xslt"/>
      <split>
        <xpath>portals/portal</xpath>
        <to uri="log:foo.bar?level=INFO"/>
      </split>
    </route>