Extensible Stylesheet Transformations (XSLT) 1.0 is a language for copying data from an XML source into a second, differently structured text format (called a result document), which in most cases is also in XML. Here's the situation in BPEL:
The primary purpose of XSLT is to reorganize the data received from one service so that the process can transmit the data to another.
The XML source must contain a single XPath element node, which may contain descendants.
To reorganize data from an XML source, do as follows:
Write an extensible stylesheet (XSL), which is an XML file that includes
XPath 1.0 expressions that select the data of interest
optionally, parameters that accept values from outside the XSL and that help specify what data to review from the XML source, as well as what data to place in the result document
XSLT statements that specify the result document, which may include data from the XML source as well as from the XSL
In the BPEL process, invoke the function doXSLTransform and specify
a path to the XSL
a variable that holds the XML source, or an XPath expression that resolves to a single element node
optionally, pairs of parameter names and values for use by the XSL
The function doXSLTransform returns a result document. If the function is a source in a copy element of the assign activity, the result document is placed in the appropriate target field.
Our next examples reflect two ways to use doXSLTransform:
single transformation, which is the conversion of an XML source to a result document by one invocation of the function
iterative construction, which is the building of an increasingly large result document by repeated invocations of the function
Figure 8.3 illustrates the use of doXSLTransform for a single transformation.
Figure 8.3: doXSLTransform, single transformation
As shown in the figure, a BPEL process can receive data from a partner service, use that data to invoke doXSLTransform in an assign activity, and use the result document when invoking a second partner service.
Listing 8.15 shows the XML source for a single transformation.
Listing 8.15: XML source for a single transformation
<Insured Customer> <CarPolicy PolicyType="Auto"> <Vehicle Category="Sedan"> <Make>Honda</Make> <Model>Accord</Model> </Vehicle> <Vehicle Category="Sport" Domestic="True"> <Make>Ford</Make> <Model>Mustang</Model> </Vehicle> </CarPolicy> <CarPolicy PolicyType="Antique"> <Vehicle Category="Sport"> <Make>Triumph</Make> <Model>Spitfire</Model> </Vehicle> <Vehicle Category="Coupe" Domestic="True"> <Make>Buick</Make> <Model>Skylark</Model> </Vehicle> <Vehicle Category="Sport"> <Make>Porsche</Make> <Model>Speedster</Model> </Vehicle> </CarPolicy> </Insured>
Listing 8.16 shows the result document.
Listing 8.16: Result document for a single transformation
<VehicleList> <OneVehicle> <Make>Honda</Make> <Model>Accord</Model> </OneVehicle> <OneVehicle> <Make>Ford</Make> <Model>Mustang</Model> </OneVehicle> <OneVehicle> <Make>Triumph</Make> <Model>Spitfire</Model> </OneVehicle> <OneVehicle> <Make>Buick</Make> <Model>Skylark</Model> </OneVehicle> <OneVehicle> <Make>Porsche</Make> <Model>Speedster</Model> </OneVehicle> </VehicleList>
Listing 8.17 shows an outline of the BPEL process.
Listing 8.17: BPEL process outline for single transformation (part 1 of 2)
<process> . . <variables> <variable name="CarPolicies" element="InsuredElement" /> <variable name="Vehicles" element="VehiclesElement" /> </variables> <sequence> <invoke ... outputVariable="CarPolicies" />
Listing 8.17: BPEL process outline for single transformation (part 2 of 2)
<assign> <copy> <from> bpel:doXslTransform ("urn:stylesheets:Insured2Vehicles.xsl", $CarPolicies) </from> <to variable="Vehicles" /> </copy> </assign> <invoke ... inputVariable="Vehicles" /> </sequence> . . </process>
Last (and though a review of XSLT is out of scope), Listing 8.18 shows the XSL, which selects the CarPolicy nodes and, for each, writes a Make and Model node to the result document.
Listing 8.18: XSL to process the CarPolicy nodes
<?xml version="1.0" encoding="ISO-8859-1" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="ISO-8859-1" omit-xml-declaration="yes" indent="yes" /> <xsl:template match="/"> <VehicleList> <xsl:apply-templates select="Insured/CarPolicy"/> </VehicleList> </xsl:template> <xsl:template match="CarPolicy"> <xsl:for-each select="Vehicle"> <OneVehicle> <xsl:copy-of select="Make"> <xsl:copy-of select="Model"> </OneVehicle> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Figure 8.4 illustrates the use of doXSLTransform for iterative construction.
Figure 8.4: doXSLTransfer, iterative constructionformation
As shown in the figure, a BPEL process loops through the following sequence:
Receive data from a partner service.
Invoke the function doXSLTransform in an assign activity to add new data to the data received in previous iterations.
In this case:
The source document (in variable AllVehicles) is different at each iteration, and the invocation of doXSLTransform is as follows.
bpel:doXslTransform ("urn:stylesheets:AddNewVehicle.xsl", $AllVehicles, "NewVehicle", $OneVehicle)
As shown, doXSLTransform submits a parameter (called NewVehicle) to the XSL. The content of that parameter is the data most recently provided by the partner service.
On completing the loop, the BPEL process invokes a second partner service with the content that was collected during the loop.
Listing 8.19 shows an outline of the BPEL process.
Listing 8.19: BPEL process outline for iterative construction
<process> . . <variables> <variable name="OneEntry" element="OneVehicleElement" /> <variable name="AllVehicles" element="VehicleListElement" <from> <literal> <VehicleList> <OneVehicle/> </VehicleList> </literal> </from> </variable> </variables> ...<while> <condition> ... </condition> <sequence> <invoke ... outputVariable="OneEntry" /> <assign> <copy> <from> bpel:doXslTransform ("urn:stylesheets:AddNewVehicle.xsl", $AllVehicles, "NewVehicle", $OneEntry) </from> <to variable="AllVehicles" /> </copy> </assign> </sequence> </while> <invoke ... inputVariable="AllVehicles" /> . . </process>
The declaration of AllVehicles initializes the variable as follows.
<VehicleList> <OneVehicle/> </VehicleList>
We'll assume that each iteration provides details on only one vehicle and that successive iterations result in the following content.
<VehicleList> <OneVehicle/> <OneVehicle> <Make>Honda</Make> <Model>Accord</Model> </OneVehicle> <OneVehicle> <Make>Ford</Make> <Model>Mustang</Model> </OneVehicle> <OneVehicle> <Make>Triumph</Make> <Model>Spitfire</Model> </OneVehicle> </VehicleList>
Listing 8.20 shows the XSL, which selects the OneVehicle nodes, copies them to the (growing) result document, and adds the OneVehicle node that was provided in the current iteration of the while loop.
Listing 8.20: XSL to select the OneVehicle nodes
<?xml version="1.0" encoding="ISO-8859-1" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="NewVehicle"/> <xsl:output method="xml" version="1.0" encoding="ISO-8859-1" omit-xml-declaration="yes" indent="yes" /> <xsl:template match="/"> <VehicleList> <xsl:apply-templates select="descendant::OneVehicle"/> </VehicleList> </xsl:template> <xsl:template match="OneVehicle"> <xsl:copy-of select="." /> <xsl:if test="position()=last()"> <xsl:copy-of select="$NewVehicle"> </xsl:if> </xsl:template> </xsl:stylesheet>