Splitting XML messages

XML is one of the most frequently split payload types. This recipe will show how you can use Camel's support for implicit type conversion, and XPath support, to process XML fragments individually.

Getting ready

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

How to do it...

Consider the following XML file:

<books>
  <book category="Tech" 
        title="Apache Camel Developer's Cookbook">
    <authors>
      <author>Scott Cranton</author>
      <author>Jakub Korab</author>
    </authors>
  </book>
  <book category="Cooking" title="Camel Cookbook">
    <authors>
      <author>Heston Ramsey</author>
      <author>Gordon Blumenthal</author>
    </authors>
  </book>
</books>

To extract the authors of a particular book category, you use an XPath Expression within the split DSL statement to isolate the nodes that you are interested in.

In the XML DSL, this is written as:

<from uri="direct:in"/>
<split>
  <xpath>//book[@category='Tech']/authors/author/text()</xpath>
  <to uri="mock:out"/>
</split>

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

from("direct:in")
  .split(xpath("//book[@category='Tech']/authors/author/text()"))
    .to("mock:out")
  .end();

As a result, two messages will be sent to the mock:out endpoint:

  • Scott Cranton
  • Jakub Korab

How it works...

The XPath Expression is used to uniquely identify XML DOM nodes that should be isolated for splitting. The Splitter processes each of the identified nodes, and any child nodes, through the steps defined within the split statement.

There's more...

The preceding example assumes an XML document without any namespaces. Using XML namespaces with XPath involves only a little bit of extra configuration.

Assume that the document being passed through the route varies from the previous example only in the definition of a namespace:

<books xmlns="http://camelcookbook.org/schema/books">
  <!-- remainder as per example above -->
</books>

In order for our XPath Expression to match, we will need to refer to the namespace through a prefix (c:):

//c:book[@category='Tech']/c:authors/c:author/text()

What remains is to define the association between the full namespace URI and that prefix.

In the XML DSL, the namespace definition is provided on some parent XML element such as the camelContext:

<camelContext
    xmlns="http://camel.apache.org/schema/spring"
    xmlns:c="http://camelcookbook.org/schema/books">
  <route>
    <from uri="direct:in"/>
    <split>
      <xpath>
        //c:book[@category='Tech']/c:authors/c:author/text()
      </xpath>
      <to uri="mock:out"/>
    </split>
  </route>
</camelContext>

When using the Java DSL, you can append a namespace to the xpath() expression:

from("direct:in")
  .split(
    xpath(
      "//c:book[@category='Tech']/c:authors/c:author/text()"
    ).namespace("c", "http://camelcookbook.org/schema/books")
  )
    .to("mock:out")
  .end();

Once again, two messages will be sent to the mock:out endpoint:

  • Scott Cranton
  • Jakub Korab

Multiple namespaces can be defined through chaining as follows:

.namespace("c", "http://camelcookbook.org/schema/books")
.namespace("se", "http://camelcookbook.org/schema/somethingElse")

If you are going to be using the same namespaces in multiple places throughout your routes, you can make use of the org.apache.camel.builder.xml.Namespaces builder to avoid repeating that definition:

Namespaces ns = 
    new Namespaces("c", "http://camelcookbook.org/schema/books")
      .add("se", "http://camelcookbook.org/schema/somethingElse");

from("direct:in")
  .split(
    ns.xpath(
      "//c:book[@category='Tech']/c:authors/c:author/text()"
    )
  )
    .to("mock:out")
  .end();

Tip

When splitting via an XPath Expression, Camel loads the entire XML document into memory. This may not be desirable for very large messages. See the Splitter documentation on the Camel website for details on using the Tokenizer Expression Language along with streaming to address this. You can also use the Camel StAX Component for this purpose.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.20.156