Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Basic SOA Using REST


3.4 SOA-Style Integration Using XSLT and JAXP for Data Transformation

Some readers may be wondering why I might include a section on XSLT. The reason is that XLST provides a powerful and efficient data transformation engine that can be used to translate messages from one format to another. When building SOA applications, developers commonly encounter problems where they need to integrate systems that require the same message type (e.g., purchase order) in different formats. XSLT provides a standard mechanism for translating between message formats when messages are represented as XML documents.

The preceding section introduced two Web services:

  • The OMS “NewOrders” Web service that provides access to the new orders that have come in during the past day
  • The CSS “CustomerHistory” Web service that receives updates to the customer history database

This section shows how to build a simple SOA application that links these two Web services together. I am going to walk through an example that gets the new orders, transforms them into customer history entries, and posts those entries to the CSS. This example introduces data transformation using XSLT—a cornerstone of SOA-style loosely coupled integration.

3.4.1 How and Why to Use XSLT for Data Transformation

A core component of any SOA system is its capability to transform data from one format to another. Often referred to as data transformation, this capability is most naturally addressed within the Web Services context using eXtensible Stylesheet Language Transformations (XSLT). We assume the reader is familiar with the basics of XSLT. Our focus is on the application of XSLT to SOA-style loosely coupled integration. To brush up on XSLT, see the W3C’s Web site at www.w3.org/Style/XSL/. In addition to the specification (the examples in this book use Version 1.0—see [XSLT 1.0]), the site has links to a variety of helpful tutorials. Another good refresher can be found in Sun’s Java/XML Tutorial (http://java.sun.com/webservices/jaxp/ dist/1.1/docs/tutorial/xslt/index.html). Sun’s tutorial is especially useful because it discusses the JAXP APIs along with XSLT.

Because XSLT is a sophisticated data transformation language, it can take a long time to learn in depth. Fortunately, the data transformations required by most SOA applications need to use only a small part of the XSLT language that does not take a long time to learn. If you are struggling to understand this section of the book, you should have no trouble once you review the Sun tutorial. There is no need to study XSLT in great depth at this point.

XSLT makes sense as the transformation tool of choice within SOA integration frameworks, because it is a universally accepted standard and the transformation engines that interpret XSLT to perform data transformations keep getting better and faster. Although it may be expedient to write some quick and dirty code to perform a simple transformation here and there, it does not make sense to leave the data transformation language and processing unstandardized when developing a framework for SOA integration that will be used across an organization.

To demonstrate how XSLT can be used for data transformation, we consider a scenario where the new orders, accessed from the OMS, are used to create customer history records that update the CSS customer history database.

The business reason for doing this is so that users of the CSS have fast access to an up-to-date record of the transactions a customer has made with the company. Such information needs to be available nearly instantly when handling customer care telephone calls, for example. If the customer care representative needs to examine the details of any transaction in the customer history, the information stored there from the OMS provides important keys, such as OrderKey and ITM_NUMBER, that will enable detailed information to be retrieved from the OMS rapidly.

Figure 3-7 illustrates the data mapping that transforms an OMS order record into a CSS customer history record. The order record and customer history record are introduced in Figure 3-1 and Figure 3-2, respectively.

As illustrated in Figure 3-7, the Customer Number in the Order becomes a foreign key in the Customer History Record, which links it back to other information about the customer. Order Number, PO Number, and Item Number are mapped over because having them in the CSS will enable additional SOA components to be built that provide quick lookups from a customer history record to detailed order, purchase order, and item information in the OMS and other systems. Note that there may be multiple instances of an item number in a customer history record, if an order includes more than one type of item.

The following examples review the XSLT for transforming a set of OMS orders into a set of CSS customer history entries. The set of orders is formatted as an oms:Orders element in the schema http://soabook.com/ example/oms/orders.xsd (Example 3-2). The set of customer histories is formatted as a css:CustomerHistoryEntries element in the schema http://soabook.com/example/css/custhistentries.xsd (Example 3- 4). The XSL transformation from an order to a customer history is represented pictorially in Figure 3-7.

The XSLT language is declarative. It defines transformations of source documents to target documents. An XSL transformation comprises a set of template rules—represented by instances of the xsl:template element— that are children of the root xsl:stylesheet element. Hence, an XSLT document is often referred to as a stylesheet. The template elements in the stylesheet define the structure of the target document that is created from the source.

XSLT uses the XPath language (see [XPath]) to identify chunks of data in the source document (e.g., OrderKey). Together with the template rules, the XPath expressions determine where to place the chunks of data in the target document.

Example 3-9 illustrates a stylesheet for transforming orders to customer histories. This discussion breaks the stylesheet into bite-size chunks.

The example shows the beginning of the XSLT document, including the xsl:stylesheet namespace declarations and xsl:output element.

Example 3-9 XSLT for Customer History—Namespaces and Output Elements

4 <xsl:stylesheet version="1.0"
5 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
6 xmlns:oms="http://www.example.com/oms">
7 <xsl:output method="xml" version="1.0" encoding="UTF-8"/>
book-code/chap03/xslt/etc/order_to_history.xslt

As you can see, the prefix oms is used to denote the Order Management System namespace: http://www.example.com/oms. The xsl:output element controls the format of the stylesheet output. The attribute method="xml" indicates that the result should be output as XML. Note that this stylesheet does not specify that the output should be indented (i.e., it does not include the attribute indent="yes"). You should avoid specifying visual formatting such as indentation in the base-level transformation. I recommend using a separate XSLT stylesheet to format XML for human-readable output when necessary. Note that the encoding is specified (encoding="UTF-8"), as it is throughout this book, as UTF-8.

The next portion of the XSLT, shown in Example 3-10, provides the rules for processing the oms:Orders element.

Example 3-10 XSLT for Customer History—Creating the Customer History Entry

11 <xsl:template match="oms:Orders">
12 <CustomerHistoryEntries xmlns="http://www.example.com/css"
13 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:schemaLocation="http://www.example.com/css
15 http://soabook.com/example/css/custhistentries.xsd">
16 <xsl:apply-templates/>
17 </CustomerHistoryEntries>
18 </xsl:template>
19 <xsl:template match="oms:Order">
20 <CustomerHistoryEntry xmlns="http://www.example.com/css">
21 <CustomerNumber>
22 <xsl:apply-templates select="./oms:OrderHeader/oms:CUST_NO"/>
23 </CustomerNumber>
24 <OrderLookupInfo>
25 <xsl:apply-templates select="./oms:OrderKey"/>
26 <xsl:apply-templates
27 select="./oms:OrderHeader/oms:PURCH_ORD_NO"/>
28 <xsl:apply-templates
29 select="./oms:OrderItems/oms:item/oms:ITM_NUMBER"/>
30 <xsl:apply-templates select="./oms:OrderText"/>
31 </OrderLookupInfo>
32 </CustomerHistoryEntry>
33 </xsl:template>
book-code/chap03/xslt/etc/order_to_history.xslt

At the beginning of the block, you see a template being defined to match the pattern “oms:Orders”—in other words, it matches the oms:Orders element in the source document. Inside this template, you see the definition of a CustomerHistoryEntries element. The contents appearing inside the template form the output for the target document. So, this template provides the rules for transforming an oms:Orders element into a css:CustomerHistoryEntries element.

Now, notice that this template has the instruction <xsl:apply-templates/> inside it. Inside a template, XML in the xsl namespace is interpreted as instructions and not as content to be output to the target document. This particular instruction tells the XSLT processor to apply the other templates in the stylesheet to the children of the oms:Orders node and insert the results into the target document. So, that is how the css:CustomerHistoryEntries element gets constructed in the target document.

Its opening and closing tags are specified in this template. Its children are defined by the results of the <xsl:apply-templates> instruction and are inserted between the opening and closing tags.

Continuing to examine Example 3-10, you can see that the bottom half defines another template matching the oms:Order element. So, if any children of oms:Orders are instances of oms:Order, these children will be processed by this template and the results will be inserted the CustomerHistoryEntries tags. Looking inside this template for oms:Order, you can see that it contains the contents for an element, CustomerHistoryEntry, and the two top-level elements CustomerNumber and OrderLookupInfo. Now, look inside the tags for CustomerNumber and you see another xsl:apply-templates instruction. However, this one has the attribute:

select="./oms:OrderHeader/oms:CUST_NO"

This template is providing the instructions for filling in the contents of the CustomerNumber element. And the XPath expression ./oms:Order- Header/oms:CUST_NO restricts the children of oms:Order that this template is applied to. That XPath expression tells the XSLT processor to only apply templates to oms:CUST_NO elements that are children of oms:OrderHeader.

In this manner, the XPath expression reaches into the source document, pulls out the oms:CUST_NO element, processes it, and inserts the results inside the CustomerNumber tags. That is how oms:CUST_NO gets transformed into css:CustomerNumber and inserted into the right place in the target document.

Looking at some of the other xsl:apply-templates instructions occurring in Example 3-10, you can see that the <OrderLookupInfo> element is populated from the source elements specified by the XPath expressions:

./oms:OrderKey, ./oms:OrderHeader/PURCH_ORD_NO, ./oms:OrderItems/ item/ITM_NUMBER, and ./oms:OrderText. Notice that these XPath expressions correspond to the dotted line mappings in Figure 3-7.

Continuing to review this stylesheet, now have a look at Example 3-11, which shows the templates that match these XPath expressions.

Example 3-11 XSLT for Customer History—Detail-Level Templates

37 <xsl:template match="oms:CUST_NO">
38 <xsl:value-of select="."/>
39 </xsl:template>
40 <xsl:template match="oms:OrderKey">
41 <OrderNumber xmlns="http://www.example.com/css">
42 <xsl:value-of select="."/>
43 </OrderNumber>
44 </xsl:template>
45 <xsl:template match="oms:PURCH_ORD_NO">
46 <PURCH_ORD_NO xmlns="http://www.example.com/css">
47 <xsl:value-of select="."/>
48 </PURCH_ORD_NO>
49 </xsl:template>
50 <xsl:template match="oms:ITM_NUMBER">
51 <ITM_NUMBER xmlns="http://www.example.com/css">
52 <xsl:value-of select="."/>
53 </ITM_NUMBER>
54 </xsl:template>
55 <xsl:template match="oms:OrderText">
56 <OrderText xmlns="http://www.example.com/css">
57 <xsl:value-of select="."/>
58 </OrderText>
59 </xsl:template>
book-code/chap03/xslt/etc/order_to_history.xslt

Here you can see, for example, that the template matching oms:OrderKey simply returns the value of that element (the instruction <xsl:value-of select="."/> returns the string value of the current node). The net result is that this stylesheet maps the value of oms:OrderKey to a subelement in the target document named OrderNumber that is a child of CustomerHistoryEntry.

Having walked through an example of an XSLT, the next section looks at how such transformations are applied using Java.

3.4.2 XSLT Processing Using JAXP

XSLT processing in Java is accomplished using the Java API of XML Processing (JAXP) [JSR 206]. Specifically, the JAXP javax.xml.transform.

Transformer class can be used to convert a source document to a target document according to the rules specified in a stylesheet. JAXP provides the foundation from which all Java XML processing is built.

Figure 3-8 shows a simplified architecture diagram illustrating the role of the JAXP API. A variety of different types of Java applications can use the JAXP API, including servlets, JSPs, and EJBs. All of these use JAXP to access the various capabilities that are included in any JAXP implementation, such as a SAX parser, a DOM implementation, and an XSL processor that supports XSLT. The package javax.xml.parsers provides a common factory interface to access different implementations of SAX and DOM (e.g., Xerces) as well as XSLT (e.g., Xalan). The interfaces for SAX and DOM are found in the org.xml.sax and org.w3c.dom packages, respectively.

The XSLT APIs are found in the javax.xml.transform packages.

As shown in Figure 3-8, JAXP isolates a Java application (e.g., client, servlets, JSP, EJB) from the implementation of the XSLT transformer, and the SAX and DOM parsers. JAXP defines factory classes that instantiate wrapper objects on the transformer and parser implementations. The transformer/ parser implementation classes that are used at runtime are determined by system property and/or classpath settings.

JAXP is an important enabling standard making it feasible to use Java and Web Services for constructing SOA-style systems integration applications. Not only does it integrate the XML parsing and transformation standards with Java, but also it isolates the SOA application components from the SAX, DOM, and XSLT implementations. This is important, because as better and faster implementations come to market, SOA components will be able to take advantage of them to improve the performance without needing to be rewritten.

By using the JAXP architecture and XML for messaging, most of the data transformation work involved in integrating SOA components with Java boils down to writing XSLT. The example used to demonstrate this is illustrated in Figure 3-9. This application reads orders from an OMS Web service, transforms them into customer history updates, and writes these updates to a CSS Web service.

This example is constructed by tying together the examples from Sections 3.3.2 and 3.3.4 and using XSLT in the middle to transform the orders into customer histories. The steps in the process illustrated in Figure 3-9 are:

1. A Service instance is used to create two Dispatch<Source> instances—one to invoke the OMS Web service, and the other to invoke the CSS Web service.
2. The first
Dispatch<Source> instance’s invoke method is used to get the orders from the OMS Web service.
3.
The orders (an XML document) are returned from invoke() as a Source instance.
4.
The XSLT stylesheet file (order_to_history.xslt) is used, by a TransformerFactory, to construct a Transformer instance based on the stylesheet.
5.
The Transfomer.transform() method is invoked to apply the stylesheet rules to the Source instance (orders). The resulting cus- tomer histories (an XML document—see Example 3-3) are written to a Result instance that has been created.
6.
In this case, the Result instance is created as a wrapper from a ByteArrayInputStream. So, the XML is extracted from the underlying array and wrapped in a StreamSource object that can be consumed by the second Dispatch instance.
7.
Lastly, as in Figure 3-6, the Dispatch.invoke() method is used to post the customer histories XML to the CSS Web service.

The code in Example 3-12 shows how the steps from Figure 3-9 are implemented. The Java used to create and invoke the Dispatch instances (to get and send the XML to the RESTful Web services) is the same as in Example 3-6 and Example 3-8—please see those discussions for an overview of how Dispatch works in this scenario.

Example 3-12 Java Code That Applies the XSLT for Customer History

51 // Get the new orders
52 Service svc = Service.create(svcQName);
53 svc.addPort(orderQName, HTTPBinding.HTTP_BINDING
, newOrdersUrl);
54 Dispatch<Source> getOrdersDispatch =
55 svc.createDispatch(orderQName, Source.class, Service.Mode.PAYLOAD);
56 Source newOrdersSource =
57 getOrdersDispatch.invoke(new StreamSource(new StringReader("<empty/>")));
58 // Instantiate a Transformer using our XSLT file
59 Transformer transformer =
60 TransformerFactory.newInstance().newTransformer
61 (new StreamSource(new File(xsltFile)));
62 // Transform the new orders into history entry files
63 ByteArrayOutputStream ba = new ByteArrayOutputStream();
64 transformer.transform(newOrdersSource, new StreamResult(ba));
65 // Update the customer histories
66 svc.addPort(histQName, HTTPBinding.HTTP_BINDING, addCustHistUrl);
67 Dispatch<Source> postCustomerHistoryDispatch =
68 svc.createDispatch(histQName, Source.class, Service.Mode.PAYLOAD);
69 postCustomerHistoryDispatch
70 .invoke(new StreamSource(new StringReader(ba.toString())));
book-code/chap03/xslt/src/java/samples/OrderToCustHist.java

To see how the XSLT is implemented, look to the middle of the example code where an instance of the default TransformerFactory is obtained using TransformerFactory.newInstance(). Using this factory, a Transformer is created by passing the XSLT file (the one discussed previously that implements the mapping illustrated in Figure 3-7) as a StreamSource to the newTransformer() method. The resulting Transformer then applies the XSLT to the Source instance obtained by invoking the getOrdersDispatch instance. As shown here, the second parameter used in the invocation of transformer.transform() is a StreamResult wrapping an underlying ByteArrayOutputStream. In this manner, the results of the XSL transformation are written to that byte array. The end of the example code shows how that byte array is wrapped inside a StreamSource that can be passed to the postCustomerHistoryDispatch.invoke() method to post the customer histories to the CSS Web service.

To run this example, do the following. After the example is run, the results (customer history entries) are written by the application to a temporary file of the form ${user.home}/tmp/soabook*.xml. So, you can look to your ${user.home}/tmp directory to verify that the example ran properly.

1. Start GlassFish (if it is not already running).
2. Go to
<book-code>/chap03/rest-post/endpoint-servlet.
3.
To build and deploy the Web service enter:
mvn install
... and when that command finishes, then enter:
ant deploy
4.
Go to <book-code>/chap03/rest-get/endpoint-servlet.
5.
To build and deploy the Web service enter:
mvn install
... and when that command finishes, then enter:
ant deploy
6.
Go to <book-code>/chap03/xslt.
7.
To run the client enter:
mvn install
8. To undeploy the Web service, go back to <book-code>/chap03/ rest-get/endpoint-servlet and enter:
ant undeploy
9. Do the same in the directory <book-code>/chap03/rest-post/endpoint- servlet.

That concludes this brief introduction to data transformation using XSLT with JAXP. XML processing with JAXP is examined in more detail in Chapter 5 where data binding is introduced and JAXB is compared with SAX and DOM. The next two sections of this chapter look at how RESTful services are deployed—with and without the JWS.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.