communicate between stylesheets using websphere datapower context variables

46
Communicate between stylesheets using WebSphere DataPower context variables Websphere® DataPower SOA Appliances provide a high-speed engine for transforming XML using XSLT 1.0. A processing policy can run multiple stylesheets over a given input, or perform processing on messages passing through the device in both directions. This article discusses the dp:variable XSLT extension, which allows values to be shared between stylesheet executions in the same transaction. 13 Comments Share: Facebook Twitter Linked In Google+ David Z. Maze ([email protected] ), Software Engineer, IBM 15 August 2007 Try IBM WebSphere DataPower XC10 Virtual Appliance for Developers Table of contents Develop and deploy your next app on the IBM Bluemix cloud platform. Start building for free About DataPower XML appliances You can use WebSphere DataPower SOA Appliances for XML to accelerate filtering, transformation, and securing of XML data flows. A basic configuration might check schema validity, digital signatures, and other attributes of inbound messages, then pass it on to a fixed back- end. More complicated rules might decrypt inbound messages,

Upload: dhinakar-reddy

Post on 16-Jan-2016

248 views

Category:

Documents


1 download

DESCRIPTION

use

TRANSCRIPT

Page 1: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Communicate between stylesheets using WebSphere DataPower context variablesWebsphere® DataPower SOA Appliances provide a high-speed engine for transforming XML using XSLT 1.0. A processing policy can run multiple stylesheets over a given input, or perform processing on messages passing through the device in both directions. This article discusses the dp:variable XSLT extension, which allows values to be shared between stylesheet executions in the same transaction.13  CommentsShare:

Facebook Twitter Linked In Google+

David Z. Maze ([email protected]), Software Engineer, IBM15 August 2007Try IBM WebSphere DataPower XC10 Virtual Appliance for Developers

Table of contents

Develop and deploy your nextapp on the IBM Bluemix

cloud platform.

Start building for free

About DataPower XML appliances

You can use WebSphere DataPower SOA Appliances for XML to accelerate filtering,

transformation, and securing of XML data flows. A basic configuration might check schema

validity, digital signatures, and other attributes of inbound messages, then pass it on to a fixed

back-end. More complicated rules might decrypt inbound messages, dynamically select a back-

end based on XML content, transform the data to a different format, and so on. In custom XSLT,

DataPower extensions also make available information about an inbound connection''s IP

address, port number, and such for logging or inserting into outbound messages.

One powerful feature of the DataPower engine is the use of context variables to communicate

information across processing steps, possibly even across different rules in the same

Page 2: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

transaction. Fpr example, you could configure a policy to capture a SOAP header on a request

rule and insert that same header into the response to the original client. You could use the same

context variable mechanism to capture the complete result of an earlier processing step in a

custom stylesheet, or to access the transaction metadata mentioned previously.

This article will discuss how to use the dp:variable() and <dp:set-variable/> extensions to

access context and service variables. You can also use context variables to control which

stylesheet is executed, which rule is called, or which input is used for a future processing step. If

the state needs to be used only within a single stylesheet, DataPower appliances also provide

stylesheet-local variables that can be easier to use than passing around XSLT template

parameters.

Using dp:variable() and <dp:set-variable/> extensions

The DataPower Extension Elements/Functions Catalog lists all of the XSLT extension elements

and functions available to stylesheets run on the appliance. Among these extensions are an

extension function, dp:variable(), and an extension element, <dp:set-variable/>. To use these

extensions, a stylesheet needs to tell the XSLT engine about the dp: XML namespace, and that

that namespace contains extension elements. It's also common to also ask the processor not to

include that namespace in the stylesheet's output. This set-up occurs in

the<xsl:stylesheet> element at the topmost level of the stylesheet.

In addition to the extensions described here, given a fixed variable name and a fixed string

value, a setvar action in the processing policy will set the variable to the value. It can then be

accessed in later stylesheets using dp:variable().

Contexts, context variables, and system variables

In the DataPower processing policy configuration, every step has a labeled input and output.

The names provided in the configuration are actually the names of contexts in the system. A

context stores not only data, such as an XML tree that is the input or output of a transformation,

but also a set of context variables. There are a small set of special contexts, such as INPUT and

OUTPUT to refer to the current rule's input and output data, and PIPE for streaming

transformations. Otherwise, the set of contexts persists across an entire transaction, including

the request and response rules and any called or error rule that might be invoked.

Every variable has a name, which is really a URL beginning with var:. There are four variable

syntaxes:

var://context/contextname/varname always refers to a variable called varname in the context named contextname. As a special

Page 3: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

case, var://context/contextname/_roottree refers to the actual data stored in the context, not a specific variable within it.

var://local/varname refers to a variable called varname. If setting a variable, it is set in the output context of the current stylesheet; if reading one, it is read from the input context.

var://system/contextname/varname refers to a global variable. Global variables can be used in much the same way as context variables, but their values persist beyond the current transaction. Global variables are difficult to use safely because there is no way to protect a variable from being updated in separate concurrent transactions or to have a variable's value persist across device restarts.

var://service/property refers to a service variable. You can find a full listing of service variables in Appendix A of the Extension Elements/Functions Catalog; reading var://service/protocol, for example, retrieves the protocol ("http", "https", and so on) for the current request.Using the extensions

Let's copy a SOAP header from an input message into the response. First we need to extract

the SOAP header we're interested in, and use <dp:set-variable/> to save it to a context variable.

The following stylesheet can do that:Listing 1. Extracting a SOAP header<?xml version="1.0"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:tns="http://www.example.org/tns"

xmlns:dp="http://www.datapower.com/extensions"

extension-element-prefixes="dp"

exclude-result-prefixes="dp">

<xsl:output method="xml"/>

<xsl:template match="/">

<dp:set-variable name="'var://local/header'"

value="/soap:Envelope/soap:Header/tns:MyHeader"/>

<xsl:copy-of select="/"/>

</xsl:template>

</xsl:stylesheet>

Note that the dp: XML namespace prefix is declared, and referenced as both an extension

element prefix -- explicit dp: elements should be processed as extensions, not copied to the

output -- and that the prefix should be excluded from the stylesheet's result. We set a variable

namedheader on whatever our output context is containing an XSLT node-set with the header

we're interested in, and then also copy the entire contents of our input into that context. If a

transform action is configured with an input context of INPUT and an output context of saved,

then the savedcontext will contain the input tree, plus an additional header variable with the

SOAP header we're interested in. This policy is shown in Figure 1.Figure 1. Processing policy configuration invoking "get SOAP header" stylesheet

Page 4: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

You can use the dp:variable() extension function to retrieve the contents of the variable in the

response rule. This is called like any other XPath function. Because we expect its value to be a

node-set, we'll call it from an <xsl:copy-of/> statement to insert its value into the result, as

shown in Listing 2.Listing 2. Inserting a saved SOAP header<?xml version="1.0"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:tns="http://www.example.org/tns"

xmlns:dp="http://www.datapower.com/extensions"

extension-element-prefixes="dp"

exclude-result-prefixes="dp">

<xsl:output method="xml"/>

<xsl:template match="/">

<soap:Envelope>

<soap:Header>

<xsl:copy-of select="/soap:Envelope/soap:Header/*"/>

<xsl:copy-of select="dp:variable('var://context/saved/header')"/>

</soap:Header>

<xsl:copy-of select="/soap:Envelope/soap:Body"/>

</soap:Envelope>

</xsl:template>

</xsl:stylesheet>

This stylesheet refers to the "saved" context from the request rule explicitly, so it might be

configured to take INPUT as its input and OUTPUT as its output. Since this is running as the

response rule, it reads its input from the back-side service and writes its output as the response

to the initial front-side connection.

Page 5: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

As a debugging aid, the DataPower probe can be used to look at the saved variables. Figure 2

shows how the probe presents the list of variables after sending a sample XML file through the

device with this policy. Because the context variables can be accessed from any other

stylesheet, the probe considers these "global".Figure 2. DataPower XI50 probe with context variables

Dynamically generated stylesheets and dynamically selected inputs

In most places where context names or target URLs appear in a processing policy configuration,

a context variable name can be used instead. If the context variable contains a string, the value

of the variable is interpreted as the name of the thing. Setting a processing step's input

tovar://context/context/input, for example, looks at the input variable in the context context. If

that variable is set to ctx1, the step's input is taken from the ctx1 variable. A more typical use

would be to set a context variable to hold the URL of a stylesheet, and then use the context

variable name as the stylesheet name in a transform action to dynamically select a stylesheet to

run.

Listing 3 shows how this technique can be applied to select a different stylesheet depending on

the SOAP version of the input message. The stylesheet looks at the input message, and

chooses either a stylesheet suited to handling SOAP 1.1 or 1.2 messages based on the name

of its root element. A processing policy is then configured to run first this stylesheet, and then

the stylesheet named byvar://context/stylesheet/name.Listing 3. Picking a stylesheet based on SOAP version

Page 6: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"

xmlns:tns="http://www.example.org/tns"

xmlns:dp="http://www.datapower.com/extensions"

extension-element-prefixes="dp"

exclude-result-prefixes="dp">

<xsl:output method="xml"/>

<xsl:template match="/">

<xsl:apply-templates mode="pick-stylesheet"/>

<xsl:copy-of select="/"/>

</xsl:template>

<xsl:template match="/soap11:Envelope" mode="pick-stylesheet">

<dp:set-variable name="'var://context/stylesheet/name'"

value="'local:///soap-1.1.xsl'"/>

</xsl:template>

<xsl:template match="/soap12:Envelope" mode="pick-stylesheet">

<dp:set-variable name="'var://context/stylesheet/name'"

value="'local:///soap-1.2.xsl'"/>

</xsl:template>

<xsl:template match="*" mode="pick-stylesheet">

<xsl:message terminate="yes">Unrecognized SOAP envelope</xsl:message>

</xsl:template>

</xsl:stylesheet>

You could also use context variables to name a schema for a validate action if a particular

schema variant is only known through something like aversion attribute on the

document root element. Using a context variable as the target rule name for a call action lets

you call a rule dynamically based on something in the input.

One other interesting set-up is providing a context name, rather than a URL, as the stylesheet

name in a transform action. In this case, the contents of that context are used as a stylesheet,

rather than fetching a fixed stylesheet. You might use this to fill in XPath expressions in the

stylesheet for<xsl:key/> based on an unknown input, or otherwise set a fixed element name in

an actual stylesheet from the input. Note that you need to use the <xsl:namespace-

alias/> directive to generate XSLT from XSLT. For more information, see section 7.1.1 of

the XSLT 1.0 specification.

Using dp:local-variable() and <dp:set-local-variable/> extensions

XSLT variables are immutable: once a variable gets a value

via <xsl:variable/> or <xsl:param/>, it cannot be changed. For a value to be computed in one

template to be used in another, it must be passed along via a long sequence of parameters in

template invocations.

EXSLT user extension functions

DataPower appliances support most of the EXSLTextension functions. Of note, they support

thefunc:function extension to create user-defined extension functions. These functions act like

XSLT named templates, except that they're called using the XPath function call syntax, and they

Page 7: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

can return any XPath type, whereas named templates can return only XSLT result tree

fragments.

DataPower users have used the context-variable mechanism to provide mutable state within a

single stylesheet. Calling <dp:set-variable/> multiple times on the same variable name causes

that variable's value to be overwritten, so stylesheets have been written that use context

variables to save a value for use elsewhere within the same stylesheet without using XSLT

parameters. However, the bookkeeping required to track these context variables can be

significant, and any variables set this way are persistent until the end of the transaction, which

may be after the response rule has run.

To address the need to provide a mutable state in a single stylesheet, the DataPower appliance

provides similar <dp:set-local-variable/> and dp:local-variable() extensions. These work the

same way as <dp:set-variable/> and dp:variable(), but with two differences: local variables

always refer to a value specific to the current stylesheet execution, and they may have any

string as a name.

One interesting use for local variables is to implement a table mapping some key to some value,

where the value can be updated later in the same stylesheet. Note that we've used XPath string

syntax in all of the examples so far. You can actually use any XPath expression resolving to a

string as a variable name. Listing 4 demonstrates this technique: matching a kvp (key-value

pair) element sets a local variable whose name is derived from a key child element, and sets it

to the children of a value element, while the tns:lookup() function gets the value corresponding

to a named key.Listing 4. Using local variables for a lookup table<?xml version="1.0"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:tns="http://www.example.org/tns"

xmlns:dp="http://www.datapower.com/extensions"

xmlns:func="http://exslt.org/functions"

extension-element-prefixes="dp func"

exclude-result-prefixes="dp func">

...

<xsl:template match="tns:kvp">

<dp:set-local-variable name="concat('key:',tns:key)" value="tns:value/*"/>

</xsl:template>

<func:function name="tns:lookup">

<xsl:param name="key" select="''"/>

<func:result select="dp:local-variable(concat('key:',$key))"/>

</func:function>

...

</xsl:stylesheet>

Summary

DataPower extensions provide powerful features for communicating between stylesheets. A

value or XML tree can be computed in one stylesheet, saved, and used in another stylesheet,

possibly on the return path in the same transaction. You can also use context variables to

dynamically select a stylesheet, or use the output of one step as the stylesheet of the next.

Page 8: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Develop and deploy your nextapp on the IBM Bluemix

cloud platform.

Start building for free

Introduction

In the world of Web services, Web Services Description Language (WSDL) documents

describe the interfaces provided by Web services -- and indicate where instances of

those Web services can be found on the network. In general, WSDL documents are

composed and consumed with the aid of various development tools. As with virtually all

Web service related information, WSDL documents are expressed as standard XML

documents.

One of the strengths of XML is the availability of increasingly powerful tools to process

the data. One such tool, XSLT, can be used to effect complex transformations on XML

data. Since WSDL documents are expressed as XML, it is possible to automate a wide

variety of WSDL conversion tasks using XSLT. This article describes some of the

approaches that have proven useful in processing WSDL documents with XSLT (and

some that haven't) and lists some general techniques that can be applied to simplify

automated processing of WSDL documents.

This document assumes a working knowledge of both WSDL and XSLT. The following

links on IBM developerWorks offer useful background information:

For background on Web services standards such as WSDL, visit Standards and Web services.

For more information on WSDL, refer to the article, New to SOA and Web services.

For more information on XSLT, refer to New to XML.Back to top

SAX and DOM versus XSL

There are two basic approaches to modifying a WSDL document. The first uses a

language such a Java or C and an XML-parsing API such as SAX or DOM. The original

WSDL document is read, its contents parsed and modified by the algorithm and the

modified WSDL document constructed -- either by manually assembling the document

out of strings or by using a language-specific XML library. The second approach utilizes

Page 9: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

an XSL transform that specifies how the input WSDL document should be manipulated

to produce the output WSDL document. While many of the techniques described here

apply to the first approach, the XML approach has several advantages:

1. General-purpose languages have no special constructs for dealing with XML documents. While it is certainly possible to use them for such tasks, it requires much more effort to achieve equivalent results.

2. With a general-purpose language, the concepts behind the transformation get lost in the sheer volume of code necessary to achieve it. The relative terseness of the XSL transform makes the underlying concepts more apparent and thus easier to debug and maintain.

3. XSL transforms can be processed by a number of different tools, many of which are already widely available. For example, the ant build tool, the libxslt package available on most Linux distributions, the Java runtime environment and many Web browsers can execute XSL transforms.For completeness, it should be noted that XSL is somewhat weak in its ability to

express algorithms that are not directly related to the structure of the input XML

document. If the needed transformations make heavy use of such algorithms, a general-

purpose language is likely to be a better choice than XSL.

Back to top

Challenges of WSDL

Extracting structure from a WSDL document using XSL results in some interesting

challenges. To allow use of the widest possible set of XSL transform engines, restrict

stylesheets to features defined in XSL version 1.1. Some of the features added in XSL

version 2.0 will simplify some of the XSL shown here, but will not be prevalent in many

environments for some time.

The largest obstacle in processing WSDL documents with XSL is the extensive use of

namespace prefixes within attribute values in WSDL documents. These namespace

prefixes are used to correlate messages, portTypes, bindings and ports. While XSL is

adept at handling namespaces on both elements and attributes in the input document,

its constructs for dealing with them inside attribute values and character data are

somewhat weak.

Back to top

Relationships within a WSDL document

Page 10: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

While it is not possible to fully describe the structure of a WSDL document here, it is

worth describing a few of the salient relationships among elements of the WSDL

document. Correct manipulation of the WSDL document depends on understanding and

preserving these relationships.Figure 1. Relationship of WSDL document elements

Each <wsdl:message>, <wsdl:portType> and <wsdl:binding> element contains a

required "name" attribute of type ncname, but is referenced from elsewhere in the

WSDL document using a qname. The URIs associated with the qnames are inherited

from thetargetNamespace attribute on the <wsdl:definitions> element. If

the <wsdl:definitions> element does not specify a targetNamespace, the qname inherits

a null namespace URI. This implicit namespace qualification is shown by dashed gray

arrow in figure 1.

The following additional "interesting" relationships exist among the elements in a WSDL

document. Each is shown with a solid black arrow in figure 1.

Page 11: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Within the <wsdl:operation>s defined in a <wsdl:portType>, each <wsdl:input>, <wsdl:output> and <wsdl:fault> element refers to a <wsdl:message> via its message attribute.That is:

wsdl:portType/wsdl:operation/wsdl:input/@message -> wsdl:message

wsdl:portType/wsdl:operation/wsdl:output/@message -> wsdl:message

wsdl:portType/wsdl:operation/wsdl:fault/@message -> wsdl:message

The "type" attribute on a <wsdl:binding> element refers to a <wsdl:portType> element. That is:

wsdl:binding/@type -> wsdl:portType

Within a <wsdl:binding> element, each <wsdl:operation> has a "name" attribute that equals the "name" attribute on a<wsdl:operation> in the associated <wsdl:portType>.

wsdl:binding/wsdl:operation/@name = wsdl:portType/wsdl:operation/@name

Within the <wsdl:operation>s defined in a <wsdl:binding>, each <wsdl:input>, <wsdl:output> and <wsdl:fault> element may contain a name attribute whose value matches a name attribute on the corresponding element in the <wsdl:portType>. That is:

wsdl:binding/wsdl:operation/wsdl:input/@name =

wsdl:portType/wsdl:operation/wsdl:input/@name

wsdl:binding/wsdl:operation/wsdl:output/@name =

wsdl:portType/wsdl:operation/wsdl:output/@name

wsdl:binding/wsdl:operation/wsdl:fault/@name =

wsdl:portType/wsdl:operation/wsdl:fault/@name

Back to top

Techniques

What follows are several techniques and XSL snippets that have proven useful in

processing WSDL documents. Many of these approaches could be generalized to work

with non-WSDL XML documents as well.

In addition to an XSL snippet, each technique described below includes a simple

example stylesheet showing how the technique can be used to process a WSDL

document. For each example stylesheet, the output of applying the stylesheet to the

following contrived WSDL document is also shown:Listing 1. test.wsdl used in examples

Page 12: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<?xml version="1.0" encoding="UTF-8"?>

<!--

This file contains an imaginary WSDL used to illustrate how varioustypes of XSL transformations can be applied to it.

-->

<wsdl:definitions name="test" targetNamespace="http://tempuri.org/test/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:test="http://tempuri.org/test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" >

<wsdl:message name="inputmsg1"> <wsdl:part name="inputmsg1-part" type="xsd:string"/> </wsdl:message>

<wsdl:message name="inputmsg2"> <wsdl:part name="inputmsg2-part" type="xsd:decimal"/> </wsdl:message>

<wsdl:message name="inputmsg3"> <wsdl:part name="inputmsg3-part" type="xsd:integer"/> </wsdl:message>

<wsdl:message name="outputmsg"> <wsdl:part name="outputmsg-part" type="xsd:base64Binary"/> </wsdl:message> <wsdl:message name="faultmsg"/> <wsdl:portType name="porttype"> <!-- one-way operation --> <wsdl:operation name="porttype-op1"> <wsdl:input message="test:inputmsg1" name="porttype-op1-input"/> </wsdl:operation>

<!-- request-response operation --> <wsdl:operation name="porttype-op2"> <wsdl:input message="test:inputmsg2" name="porttype-op2-input"/> <wsdl:output message="test:outputmsg" name="porttype-op2-output"/> <wsdl:fault message="test:faultmsg" name="porttype-op2-fault"/> </wsdl:operation>

<!-- solicit-response operation --> <wsdl:operation name="porttype-op3"> <wsdl:output message="test:outputmsg" name="porttype-op3-output"/> <wsdl:input message="test:inputmsg3" name="porttype-op3-input"/> <wsdl:fault message="test:faultmsg" name="porttype-op3-fault"/> </wsdl:operation>

<!-- notification operation --> <wsdl:operation name="porttype-op4"> <wsdl:output message="test:outputmsg" name="porttype-op4-output"/> </wsdl:operation> </wsdl:portType>

<wsdl:binding name="binding" type="test:porttype"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

<wsdl:operation name="porttype-op1"> <soap:operation soapAction="http://tempuri.org/test/soapAction"/>

<wsdl:input name="porttype-op1-input"> <soap:body use="literal" parts="inputmsg1-part"/> </wsdl:input> </wsdl:operation>

<wsdl:operation name="porttype-op2"> <soap:operation soapAction="http://tempuri.org/test/soapAction"/>

<wsdl:input name="porttype-op2-input"> <soap:body use="literal" parts="inputmsg2-part"/> </wsdl:input>

<wsdl:output name="porttype-op2-output"> <soap:body use="literal" parts="outputmsg-part"/> </wsdl:output>

<wsdl:fault name="porttype-op2-fault"> <soap:fault name="porttype-op2-fault" use="literal"/> </wsdl:fault> </wsdl:operation>

<wsdl:operation name="porttype-op3"> <soap:operation soapAction="http://tempuri.org/test/soapAction"/>

<wsdl:input name="porttype-op3-input"> <soap:body use="literal" parts="inputmsg3-part"/> </wsdl:input>

<wsdl:output name="porttype-op3-output"> <soap:body use="literal" parts="outputmsg-part"/> </wsdl:output>

<wsdl:fault name="porttype-op3-fault"> <soap:fault name="porttype-op3-fault" use="literal"/> </wsdl:fault>

Page 13: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

</wsdl:operation>

<wsdl:operation name="porttype-op4"> <soap:operation soapAction="http://tempuri.org/test/soapAction"/>

<wsdl:output name="porttype-op4-output"> <soap:body use="literal" parts="outputmsg-part"/> </wsdl:output> </wsdl:operation> </wsdl:binding>

<wsdl:service name="service"> <wsdl:port name="service-port" binding="test:binding"> <soap:address location="http://localhost:9080/not/used"/> </wsdl:port> </wsdl:service>

</wsdl:definitions>

Technique 1: Map a namespace prefix to a namespace URI

Many WSDL elements define attributes of type qname. Since the mapping of

namespace prefixes to URIs is not required to be unique or consistent even within a

single document, any robust WSDL parsing logic must be able to translate the

namespace prefixes in qnames to namespace URIs. The XSL namespace-uri() function

maps a namespace prefix to a namespace URI, but only understands nodes in the input

document. Since the namespace prefix is part of an attribute value in the WSDL case,

some additional work is required.

The following XSL code translates the namespace prefix in a string to the corresponding

namespace URI. If the supplied string does not contain a prefix, the namespace URI is

an empty string. Placing this logic in its own template allows it to be easily invoked from

anywhere, in the context of arbitrary elements.Listing 2. Technique 1 XSL<!-- emits the namespace uri associated with the prefix of the specified qname based on current()'s namespace nodes -->

<xsl:template name="namespace-uri-of-qname"> <xsl:param name="qname"/>

<xsl:if test="contains($qname,':')"> <xsl:value-of select="namespace::*[name()=substring-before($qname,':')]"/> </xsl:if></xsl:template>

Here is an example of how this XSL template is used:Listing 3. Technique 1 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- print out the namespace URIs associated with input messages --> <xsl:template match="wsdl:input[@message]">

<xsl:text>prefix of </xsl:text> <xsl:value-of select="name()"/> <xsl:text> maps to namespace uri </xsl:text>

<xsl:call-template name="namespace-uri-of-qname"> <xsl:with-param name="qname" select="name()"/> </xsl:call-template> <xsl:text></xsl:text>

<xsl:text>prefix of </xsl:text> <xsl:value-of select="@message"/> <xsl:text> maps to namespace uri </xsl:text>

<xsl:call-template name="namespace-uri-of-qname"> <xsl:with-param name="qname" select="@message"/> </xsl:call-template> <xsl:text></xsl:text>

Page 14: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 4. Technique 1 example outputprefix of wsdl:input maps to namespace uri http://schemas.xmlsoap.org/wsdl/prefix of test:inputmsg1 maps to namespace uri http://tempuri.org/test/prefix of wsdl:input maps to namespace uri http://schemas.xmlsoap.org/wsdl/prefix of test:inputmsg2 maps to namespace uri http://tempuri.org/test/prefix of wsdl:input maps to namespace uri http://schemas.xmlsoap.org/wsdl/prefix of test:inputmsg3 maps to namespace uri http://tempuri.org/test/

Technique 2: Map a namespace URI to a namespace prefix

The reverse problem exists when an XSL stylesheet needs to generate qnames in

WSDL document attributes. That is, the XSL stylesheet knows the namespace URI, but

needs to emit a namespace prefix that is mapped to that URI for the current element.

The XSL transform engine would handle this automatically if the namespace were

associated with an output element, but since WSDL requires it to be in an attribute

value, manual processing is required. Error handling makes the XSL for this technique a

bit more complex than for the first technique. Also shown in the following XSL is a

special case template that emits a prefix for the WSDL

document's targetNamespace URI.Listing 5. Technique 2 XSL<!-- emits a prefix that maps to the specified namespace uri for current() -->

<xsl:template name="prefix-for-namespace"> <xsl:param name="namespace-uri"/>

<xsl:if test="$namespace-uri"> <!-- terminate if current() does not have a prefix for $namespace-uri --> <xsl:if test="not(namespace::*[string() = $namespace-uri])"> <xsl:message terminate="yes"> <xsl:text>Unable to find namespace prefix for namespace </xsl:text> <xsl:value-of select="$namespace-uri"/> <xsl:text> while processing </xsl:text> <xsl:value-of select="name()"/> <xsl:text> element.</xsl:text> </xsl:message> </xsl:if>

<xsl:value-of select="name(namespace::*[string() = $namespace-uri])"/> <xsl:text>:</xsl:text> </xsl:if> </xsl:template>

<!-- emits a prefix that maps to the wsdl:definitions/@targetNamespace -->

<xsl:template name="prefix-for-target-namespace"> <xsl:if test="/wsdl:definitions/@targetNamespace"> <xsl:call-template name="prefix-for-namespace"> <xsl:with-param name="namespace-uri"> <xsl:value-of select="/wsdl:definitions/@targetNamespace"/> </xsl:with-param> </xsl:call-template> </xsl:if></xsl:template>

Here is an example of how this XSL template is used:Listing 6. Technique 2 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- all the namespaces are defined globally, so just pick an arbitrary element --> <xsl:template match="wsdl:definitions">

<xsl:text>namespace uri http://www.w3.org/2001/XMLSchema</xsl:text> <xsl:text> mapped by prefix </xsl:text>

<xsl:call-template name="prefix-for-namespace"> <xsl:with-param name="namespace-uri"

Page 15: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

select="'http://www.w3.org/2001/XMLSchema'"/> </xsl:call-template> <xsl:text></xsl:text>

<xsl:text>targetNamepace uri mapped by prefix </xsl:text> <xsl:call-template name="prefix-for-target-namespace"/> <xsl:text></xsl:text>

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 7. Technique 2 example outputnamespace uri http://www.w3.org/2001/XMLSchema mapped by prefix xsd:targetNamepace uri mapped by prefix test:

Technique 3: Extract the local name from a qname

The last of the qname techniques provides an analog to theXSL local-name() function.

As with the previous techniques XSL provides this function for nodes in the source

document, but the fact that WSDL uses an attribute value to store the qname

complicates matters.Listing 8. Technique 3 XSL<!-- emits the local name of the specified qname -->

<xsl:template name="local-name-of-qname"> <xsl:param name="qname"/> <xsl:choose> <xsl:when test="contains($qname,':')"> <xsl:value-of select="substring-after($qname,':')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$qname"/> </xsl:otherwise> </xsl:choose></xsl:template>

Here is an example of how this XSL template is used:Listing 9. Technique 3 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- match an arbitrary element so we can invoke the template --> <xsl:template match="wsdl:definitions">

<xsl:text>local name of foo:bar is </xsl:text>

<xsl:call-template name="local-name-of-qname"> <xsl:with-param name="qname" select="'foo:bar'"/> </xsl:call-template> <xsl:text></xsl:text>

<xsl:text>local name of baz is </xsl:text>

<xsl:call-template name="local-name-of-qname"> <xsl:with-param name="qname" select="'baz'"/> </xsl:call-template> <xsl:text></xsl:text>

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 10. Technique 3 example outputlocal name of foo:bar is barlocal name of baz is baz

Technique 4: Correlate portType operations with messagesWhen processing WSDL documents, it is often necessary to navigate from <wsdl:portType>/<wsdl:operation> elements back to

Page 16: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

the<wsdl:message> elements they refer to. Within the WSDL document, this is accomplished via the message attributes on <wsdl:input>,<wsdl:output> and <wsdl:fault> messages. While it is tempting to use simple XPath expressions to perform this navigation, this approach is not guaranteed to work in all cases. In particular, this approach does not correctly handle multi-file WSDL documents or inconsistent use of namespace prefixes within the WSDL document (both of which are perfectly legal according to the specifications).

The approach shown below uses XSL named keys in conjunction with the templates

introduced in the previous techniques to build a robust solution to this problem.Listing 11. Technique 4 XSL<!-- index of wsdl:message by namespace uri, wsdl:message/@name -->

<xsl:key name="message" match="wsdl:message" use="concat(/wsdl:definitions/@targetNamespace,' ',@name)"/>

<!-- message key value that corresponds to a wsdl:portType/wsdl:operation/wsdl:* -->

<xsl:template match="wsdl:portType/wsdl:operation/wsdl:input | wsdl:portType/wsdl:operation/wsdl:output | wsdl:portType/wsdl:operation/wsdl:fault" mode="message-key"> <xsl:call-template name="namespace-uri-of-qname"> <xsl:with-param name="qname" select="@message"/> </xsl:call-template>

<xsl:text> </xsl:text>

<xsl:call-template name="local-name-of-qname"> <xsl:with-param name="qname" select="@message"/> </xsl:call-template></xsl:template>

Here is an example of how this XSL template is used:Listing 12. Technique 4 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- dump out message part counts for all operations --> <xsl:template match="wsdl:portType/wsdl:operation">

<xsl:value-of select="@name"/> <xsl:text> has </xsl:text>

<!-- count input parts -->

<!-- get the correct value for the message name key --> <xsl:variable name="input-message-key"> <xsl:apply-templates select="wsdl:input" mode="message-key"/> </xsl:variable>

<xsl:value-of select="count(key('message',$input-message-key)/ wsdl:part)"/> <xsl:text> input parts, </xsl:text>

<!-- count output parts -->

<!-- get the correct value for the message name key --> <xsl:variable name="output-message-key"> <xsl:apply-templates select="wsdl:output" mode="message-key"/> </xsl:variable>

<xsl:value-of select="count(key('message',$output-message-key)/ wsdl:part)"/> <xsl:text> output parts, </xsl:text>

<!-- count fault parts -->

<!-- get the correct value for the message name key --> <xsl:variable name="fault-message-key"> <xsl:apply-templates select="wsdl:fault" mode="message-key"/> </xsl:variable>

Page 17: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<xsl:value-of select="count(key('message',$fault-message-key)/ wsdl:part)"/> <xsl:text> fault parts</xsl:text>

<xsl:text></xsl:text>

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 13. Technique 4 example outputporttype-op1 has 1 input parts, 0 output parts, 0 fault partsporttype-op2 has 1 input parts, 1 output parts, 0 fault partsporttype-op3 has 1 input parts, 1 output parts, 0 fault partsporttype-op4 has 0 input parts, 1 output parts, 0 fault parts

Technique 5: Correlate binding operations with portType operations

A similar problem occurs when navigating from

a <wsdl:binding>/<wsdl:operation> element back to the

corresponding<wsdl:portType>/<wsdl:operation> element. As with the previous

technique, the XSL approach shown below uses named keys to solve the problem.Listing 14. Technique 5 XSL<!-- index of wsdl:portType by namespace uri, wsdl:portType/@name -->

<xsl:key name="porttype" match="wsdl:portType" use="concat(/wsdl:definitions/@targetNamespace,' ',@name)"/>

<!-- porttype key that corresponds to a wsdl:binding -->

<xsl:template match="wsdl:binding" mode="porttype-key"> <xsl:call-template name="namespace-uri-of-qname"> <xsl:with-param name="qname" select="@type"/> </xsl:call-template> <xsl:text> </xsl:text>

<xsl:call-template name="local-name-of-qname"> <xsl:with-param name="qname" select="@type"/> </xsl:call-template></xsl:template>

Here is an example of how this XSL template is used:Listing 15. Technique 5 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- delve into each binding --> <xsl:template match="wsdl:binding"> <xsl:text>binding: </xsl:text> <xsl:value-of select="@name"/> <xsl:text></xsl:text>

<xsl:apply-templates select="wsdl:operation"/> </xsl:template>

<!-- dump out the messages associated with each binding operation --> <xsl:template match="wsdl:binding/wsdl:operation">

<xsl:text> operation: </xsl:text> <xsl:value-of select="@name"/> <xsl:text></xsl:text>

<xsl:variable name="porttype-key"> <xsl:apply-templates select=".." mode="porttype-key"/> </xsl:variable>

<xsl:variable name="opname"> <xsl:value-of select="@name"/> </xsl:variable>

<xsl:for-each select="wsdl:input"> <xsl:text> input: </xsl:text> <xsl:value-of select="@name"/> <xsl:text> -> message: </xsl:text>

Page 18: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<xsl:for-each select="key('porttype',$porttype-key)/ wsdl:operation[@name=$opname]/ wsdl:input[@name=current()/@name]"> <xsl:value-of select="@message"/> </xsl:for-each> <xsl:text></xsl:text> </xsl:for-each>

<xsl:if test="not(wsdl:input)"> <xsl:text> (no inputs)</xsl:text> </xsl:if>

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 16. Technique 5 example outputbinding: binding operation: porttype-op1 input: porttype-op1-input -> message: test:inputmsg1 operation: porttype-op2 input: porttype-op2-input -> message: test:inputmsg2 operation: porttype-op3 input: porttype-op3-input -> message: test:inputmsg3 operation: porttype-op4 (no inputs)

Technique 6: Correlate service ports with bindings

The final qname mapping is from the wsdl:service/wsdl:port back to the wsdl:binding.

Again, named keys provide the solution.Listing 17. Technique 6 XSL<!-- index of wsdl:binding by namespace uri and wsdl:binding/@name -->

<xsl:key name="binding" match="wsdl:binding" use="concat(/wsdl:definitions/@targetNamespace,' ',@name)"/>

<!-- binding key value for wsdl:port -->

<xsl:template match="wsdl:port" mode="binding-key"> <xsl:call-template name="namespace-uri-of-qname"> <xsl:with-param name="qname" select="@binding"/> </xsl:call-template> <xsl:text> </xsl:text>

<xsl:call-template name="local-name-of-qname"> <xsl:with-param name="qname" select="@binding"/> </xsl:call-template></xsl:template>

This example puts together many of the techniques described here to generate a

summary of the operations provided by each wsdl:servicein a WSDL document.Listing 18. Technique 6 example<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:import href="wsdl-util.xsl"/> <xsl:strip-space elements="*"/> <xsl:output method="text"/>

<!-- just process the services --> <xsl:template match="wsdl:definitions"> <xsl:apply-templates select="wsdl:service"/> </xsl:template>

<!-- dump out some information for each service --> <xsl:template match="wsdl:service"> <xsl:text>service: </xsl:text> <xsl:value-of select="@name"/> <xsl:text></xsl:text>

<xsl:apply-templates select="wsdl:port"/> </xsl:template>

<!-- follow the linkages from the wsdl:port through the wsdl:binding, back to the wsdl:portType and its wsdl:operations --> <xsl:template match="wsdl:port">

<!-- key for looking up the wsdl:binding -->

Page 19: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<xsl:variable name="binding-key"> <xsl:apply-templates select="." mode="binding-key"/> </xsl:variable>

<xsl:for-each select="key('binding',$binding-key)"> <!-- key for looking up the wsdl:portType --> <xsl:variable name="porttype-key"> <xsl:apply-templates select="." mode="porttype-key"/> </xsl:variable>

<!-- process each operation in the wsdl:portType --> <xsl:for-each select="key('porttype',$porttype-key)/wsdl:operation"> <xsl:apply-templates select="."/> </xsl:for-each> </xsl:for-each> </xsl:template>

<!-- generate a Java-like method signature for each operation --> <xsl:template match="wsdl:portType/wsdl:operation">

<xsl:text> </xsl:text>

<!-- return type --> <xsl:for-each select="wsdl:output">

<!-- get the correct value for the message name key --> <xsl:variable name="output-message-key"> <xsl:apply-templates select="." mode="message-key"/> </xsl:variable>

<!-- output the type of the first part of the message --> <xsl:for-each select="key('message',$output-message-key)/wsdl:part[1]"> <xsl:value-of select="@type"/> </xsl:for-each>

</xsl:for-each>

<xsl:if test="not(wsdl:output)"> <xsl:text>void</xsl:text> </xsl:if>

<!-- method name --> <xsl:text> </xsl:text> <xsl:value-of select="@name"/>

<!-- arguments --> <xsl:text>(</xsl:text> <xsl:for-each select="wsdl:input">

<!-- get the correct value for the message name key --> <xsl:variable name="input-message-key"> <xsl:apply-templates select="." mode="message-key"/> </xsl:variable>

<!-- output the type of the type and name of each part of the message --> <xsl:for-each select="key('message',$input-message-key)/wsdl:part"> <xsl:value-of select="@type"/> <xsl:text> </xsl:text> <xsl:value-of select="@name"/> <xsl:if test="not(last())"> <xsl:text>, </xsl:text> </xsl:if> </xsl:for-each>

</xsl:for-each> <xsl:text>)</xsl:text>

<!-- exceptions --> <xsl:if test="wsdl:fault"> <xsl:text> throws </xsl:text> <xsl:for-each select="wsdl:fault">

<!-- get the correct value for the message name key --> <xsl:variable name="fault-message-key"> <xsl:apply-templates select="." mode="message-key"/> </xsl:variable>

<xsl:for-each select="key('message',$fault-message-key)"> <xsl:value-of select="@name"/> </xsl:for-each>

<xsl:if test="not(last())"> <xsl:text>, </xsl:text> </xsl:if>

</xsl:for-each> </xsl:if>

<xsl:text>;</xsl:text>

</xsl:template>

</xsl:stylesheet>

Running the above example against the test WSDL document produces:Listing 19. Technique 6 example output

Page 20: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

service: service void porttype-op1(xsd:string inputmsg1-part); xsd:base64Binary porttype-op2(xsd:decimal inputmsg2-part) throws faultmsg; xsd:base64Binary porttype-op3(xsd:integer inputmsg3-part) throws faultmsg; xsd:base64Binary porttype-op4();

Technique 7: Importing additional definitions

This is more of a best practice than a technique per se, but it has proven extremely

useful. When transforming WSDL documents into new WSDL documents, it is often

tempting to insert additional data types and messages directly into the new WSDL

document. If this new information is static (that is, does not depend on the input WSDL)

consider using the WSDL import mechanism instead. Importing these definitions gives

you the ability to change them later without re-transforming all the WSDL documents.

Due to the nature of this technique, it is not included in the downloadable wsdl-util.xsl.Listing 20. Technique 7 XSL<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/> <xsl:preserve-space elements="*"/>

<!-- add a wsdl:import for mystuff.wsdl -->

<xsl:template match="wsdl:definitions"> <xsl:copy> <xsl:copy-of select="@*"/>

<wsdl:import namespace="http://tempuri.org/mystuff" location="mystuff.wsdl"/>

<xsl:copy-of select="node()| comment()|text()"/> </xsl:copy> </xsl:template></xsl:stylesheet>

Here are the relevant portions of test.wsdl after being updated by the XSL shown

above:Listing 21. Technique 7 example output<?xml version="1.0"?><wsdl:definitions name="test" targetNamespace="http://tempuri.org/test/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:test="http://tempuri.org/test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

<wsdl:import namespace="http://tempuri.org/mystuff" location="mystuff.wsdl"/>

<wsdl:message name="inputmsg1"> <wsdl:part name="inputmsg1-part" type="xsd:string"/> </wsdl:message>

...

Technique 8: Append a suffix to an attribute value

When transforming WSDL documents, it is often necessary to derive new and/or

additional definitions from existing definitions. To help preserve the origin of these new

definitions, it is often useful to assign them names similar to the source elements from

which they are derived. Due to the nature of this technique, it is not included in the

downloadable wsdl-util.xsl.

The following XSL illustrates one way to accomplish this by appending a suffix to the

existing name.

Page 21: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Listing 22. Technique 8 XSL<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/> <xsl:preserve-space elements="*"/>

<!-- Except as overridden by more specific templates below, do a deep copy of everything. --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template>

<!-- append a suffix to wsdl:portType/@names -->

<xsl:template match="wsdl:portType/@name"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> <xsl:text>-mysuffix</xsl:text> </xsl:attribute> </xsl:template></xsl:stylesheet>

Here are the relevant portions of test.wsdl after being updated by the XSL shown

above:Listing 23. Technique 8 example output ... <wsdl:message name="faultmsg"/> <wsdl:portType name="porttype-mysuffix"> <!-- one-way operation --> <wsdl:operation name="porttype-op1"> <wsdl:input message="test:inputmsg1" name="porttype-op1-input"/> </wsdl:operation> ...

Back to top

Themes

In conclusion, here are some higher-level themes from the techniques shown above for

processing WSDL documents with XSL. Hopefully they will save you some time and

mental anguish the next time you need to hack a WSDL document with XSL:

1. Always be prepared for null namespaces on qualified names. While this almost always adds complexity to the XSL transforms, wsdl:definitions/@targetNamespace is optional.

2. Change namespace prefixes to URIs as soon as possible. Namespace prefixes are basically meaningless to anyone except the author of the original document and relying on a constant one-to-one mapping of namespace prefixes to URIs is unwise at best.

3. When trying to correlate constructs in a WSDL document, keys are almost always a better choice than XPath expressions. This is largely a result of the previous two items, but in almost every case using keys instead of XPath expressions results in simpler and shorter XSL transforms.

4. Pay very close attention to current() when evaluating namespaces. The XSL constructs for mapping from namespace prefixes to URIs work best for

Page 22: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

current(). Trying to evaluate namespace prefixes for a node other than current() is error-prone.

5. Import rather than augment. When adding new types and messages to a WSDL document, it is tempting to simply include the definitions in the output WSDL document. Unless these changes are cast in concrete (for example, part of a published standard), it is almost always a better idea to place the new definitions in a separate WSDL document and add an import element to the generated document. Doing so makes future changes significantly less painful.

6. Be prepared for multi-part WSDL documents. While this might not be a common usage pattern with current tooling, the WSDL specification specifically describes how to split a WSDL document across multiple files. Don't assume that simple XPath expressions will correctly navigate among sections of the WSDL document that reside in different input files. Multi-part WSDL documents can also have more subtle effects. For example, it is not always possible to determine if a message is used as an input or output since the definitions of the message and the operations that use it can be in separate files.XSL transforms allow you to make complex changes to WSDL documents in an

automated fashion. The approaches and XSL snippets contained in this article can give

you a jump start processing WSDL documents and help you avoid the most common

pitfalls

There are the following distinct variable types, each expressed in the var://URL format and GatewayScript format, as appropriate.

var://local/variable

Page 23: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

A local context variable to address a variable that is called variable in the default (current) context. The following example transforms the document in the tmp1 context with a style sheet. The style sheet is referenced by the stylesheet-1 variable (also in the tmp1 context) and stores the transformed document in the tmp2 context:

xform tmp1 var://local/stylesheet-1 tmp2

The local context does not persist beyond the scope of the transaction. A transaction can include both a request component and a response component. The local context cannot be accessed by any object outside the scope of the transaction. In other words, a service cannot read and use the variable.

A local context variable can be user-defined or based on an extension variable.

var://context/context/variable

Addresses a variable that is called variable in a context called context. The following example transforms the document in the tmp1context with a style sheet. The style sheet is referenced by the stylesheet-1 variable (in the apple context) and stores the transformed document in the tmp2 context:

xform tmp1 var://context/apple/stylesheet-1 tmp2

A named context does not persist beyond the scope of the transaction. A transaction can include both a request component and a response component. The local context cannot be accessed by any object outside of the scope of the transaction. In other words, the service cannot read and use the variable.

Note: Creating variables in a named context is the preferred approach. This form decouples the variable from the input and output contexts and allows the variable to be accessed from any step in a scope.

A named context variable can be user-defined or can be based on an extension variable.

var://service/variable

Addresses a variable that is made available to a DataPower service that is attached to a session.

Page 24: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Many service variables are supported in XSLT and GatewayScript . For example, the variable skip-backside has the XSLT formvar://service/mpgw/skip-backside and the GatewayScript form mpgw.skipBackside. The term "slash notation" refers to the XSLT name form and the term "dot notation" refers to the GatewayScript name form. GatewayScript variables that are not supported do not appear in the syntax section of the description of the variable.

Calls to GatewayScript variables support both forms of names. A program that uses the dot notation form establishes access to the service variables in two steps: requiring the module that holds the service variables (service-metadata) and setting a variable to access the variables. For example:

var serviceVars = require ( 'service-metadata' ); // import the service variables functionsserviceVars.mpgw.skipBackside = true; // write to the

skipbackside service variable

In the information for each variable that is supported by GatewayScript, the specifications assume a require statement (var serviceVars=require ('service-metadata')) already established access. You must establish access to the service metadata by using a require statement in your code (naming serviceVars or other variable) to manipulate the use service variable. The skipBacksidevariable call uses serviceVars.

A GatewayScript program establishes access to an XSLT service variable by using the slash notation name form in getVar and setVarfunction calls. For example:

var genPattern = serviceVars.GetVar("var://service/wsa/genpattern");

Both these name forms are listed in the function information where both are supported. When the GatewayScript name form is not in the list, the GatewayScript form is not supported. GatewayScript checks the data type when a new value is assigned to a service variable. The gettermethod returns a value with the correct data type.

var://system/variable

Addresses a global variable that is available in all contexts. System variables persist beyond the scope of request-response processing and can be read by

Page 25: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

other objects on the appliance. If the content of a variable needs to be read or set outside the scope of request-response processing, use a system variable.

Service variables Service variables enable the setting and retrieval of pieces of state that usually reflect the state of the current transaction.

Parent topic: DataPower Gateway

Integrating WebSphere DataPower XML Security Gateway XS40 with WebSphere Message Broker

Introduction

The following diagram illustrates the scenario described in this article:Figure 1. The full scenario

The requesting application communicates to an IBM® WebSphere® DataPower® XML

Security Gateway XS40 (hereafter called the DataPower appliance) using SOAP over

HTTP, with the message body encrypted to the WS-Security standard. The DataPower

appliance decrypts the body of the message it receives, and this content is then passed

to WebSphere Message Broker (hereafter called Message Broker) over a connection

Page 26: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

secured by HTTPS. Message Broker receives the SOAP message and transforms it into

a COBOL structure for the final WebSphere MQ application. The responses then flow

back in a similar fashion. The initial configuration uses simple HTTP between the

DataPower appliance and Message Broker. The modifications to use HTTPS are

performed as a second stage of the configuration.

The components described here can be placed within an SOA design pattern in which

the DataPower appliance provisions WS-Security within the demilitarized zone that

protects an enterprise.Figure 2. The scenario aligned within a demilitarized zone

Configuration

The following sections concentrate on the configuration of DataPower and on the

relevant externals that Message Broker presents to DataPower.

Configuring the DataPower applianceFigure 3. Focusing on the DataPower configuration

WS-Security

Page 27: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

WS-Security describes enhancements to SOAP messaging to provide quality of

protection through message integrity, message confidentiality, and single message

authentication. These mechanisms can be used to accommodate a wide variety of

security models and encryption technologies.

The DataPower appliance is configured with a simple XML firewall with a static backend

that connects to the Message Broker’s HTTP listener. After the main page of the XML

firewall is configured,an addition must be made to the Headers page before a

processing policy is associated with the XML firewall. This processing policy provides

the encryption and decryption of the SOAP body using the WS-Security standard.

Figure 4 below shows the main configuration of the XML firewall with the following items

configured:

Name and summary Server address and port Device port Request and response type set to SOAP

Figure 4. Configuration of the XML firewall

Page 28: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Once the header has been configured as described in the next section, the firewall

policy is added.

Headers

In the firmware version, the DataPower appliance generated two connection header

tags. By adding suppression for this tag, only one connection header is sent by the

DataPower appliance. Figure 5 shows the Headers page with the connection header tag

suppressed in the "back" direction:Figure 5. Configuring the headers

Page 29: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Processing policy

The processing policy includes just two rules: the Request rule decrypts the incoming

message body, and the Response rule encrypts the message body of the reply.

Following the traditions of security literature, the keys used in this article are named

AliceKey and BobKey. The requesting application sends messages encrypted with the

AliceKey, and the DataPower appliance encrypts the reply with the BobKey.

Request (decryption) rule

The Request rule includes a match rule property and a decrypt action as in the following

figure. The matching rule property matches on all URLs.Figure 6. The decryption rule

Page 30: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

The decrypt action is configured to decrypt the incoming message as determined from

the WS-Security headers and information contained within the SOAP message. As the

requesting application has encrypted the message with the AliceKey, it is used for

decryption within the DataPower appliance.Figure 7. The decryption action

Page 31: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

Response (encryption) rule

The response rule performs the opposite, encrypting the messages flowing in this

direction:Figure 8. The encryption rule

Page 32: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

The encryption action is configured to encrypt the SOAP message body using WS-

Security, and it uses the predefined key BobKey:Figure 9. The encryption action

Page 33: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

The private half of the BobKey is owned by the requesting application, so that it can

decrypt the message sent by the DataPower appliance.

Configuring Message Broker

On receiving a decrypted SOAP/HTTP message from the DataPower appliance, a

message flow running in a Message Broker instance converts the incoming message

into a fixed length message in a COBOL format, which is then processed by a separate

WebSphere MQ application. The message is updated and passed to a second message

flow, which converts the message into a SOAP/HTTP message containing the reply:Figure 10. Focusing on the Message Broker function

Page 34: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

The processing being performed is that of the Web services sample WSHOST, which is

supplied with WebSphere Message Broker V6. For more information about this sample,

go to the Message Broker toolkit and select Help => Samples Gallery on the Toolkit

menu:Figure 11. The two WebSphere Message Broker message flows

The first message flow processes the incoming SOAP/HTTP message after t has been

decrypted by the DataPower appliance. After converting the message format and

protocol, it writes an output message to a WebSphere MQ queue, which is read and

processed by the WebSphere MQ application.

The second message flow receives the WebSphere MQ reply message from the

WebSphere MQ application and converts the format and protocol of the input message

into a SOAP/HTTP reply message. The reply message generated by the second

message flow is passed to the DataPower appliance, so that it can be encrypted prior to

being returned to the requesting application.

HTTP Input node properties

The input node properties show the URL on which this flow is configured to receive

requests. The HTTPS box remains unchecked -- a later section enables it to complete

the security.

Page 35: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

WebSphere MQ application

The WebSphere MQ application provided with the WSHOST sample performs an MQ

Get on its input queue waiting for messages from the broker. When one is received, it

modifies the message and writes a reply to a queue that will be read by a message flow.

Messages

The following sections show the messages that flow within the system to and from the

DataPower appliance. Figure 12 below shows the placement of these messages within

the overall flow. Messages between Message Broker and the backend WebSphere MQ

application are not shown.Figure 12. Highlighting the messages described in this section

Message sent from the requesting application to the DataPower appliance

Shown below is the HTTP body of the message sent to the DataPower appliance by the

requesting application. The real content of the message in its encrypted form is

highlighted (in bold) and has been truncated for readability. For the full contents of this

and subsequent messages, see Downloads below.Message 1. The message sent from the application to the DataPower appliance

Click to see code listing

Message sent from the DataPower appliance to WMB

Here is the HTTP body of the message sent by the DataPower appliance to Message

Broker. The body (in bold) has been decrypted to reveal the SOAP request:Message 2. Message sent from the DataPower appliance to Message Broker<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope

xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:c="http://www.brokersamplewshost.ibm.com"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Header>

<wsse:Security soapenv:mustUnderstand="1"xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-

wssecurity-secext-1.0.xsd"></wsse:Security>

</soapenv:Header><soapenv:Body>

<c:IA81CONFIN><MessageId>IA81CONF</MessageId><OrderNumber>ON4002</OrderNumber><ItemReference>IY4003</ItemReference>

Page 36: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

<ItemQuantity>4</ItemQuantity><CustomerNumber>CY4004</CustomerNumber>

</c:IA81CONFIN></soapenv:Body>

</soapenv:Envelope>

Message sent from Message Broker to the DataPower appliance

Here is the HTTP body of the message returned by Message Broker to the DataPower

appliance. For this return trip, two additional fields, DeliveryRef and Confirm (in bold),

are included at the end of the message:Message 3. Message sent from Message Broker to the DataPower appliance<?xml version="1.0"?><tns:Envelope xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:NS1="http://www.brokersamplewshost.ibm.com"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><tns:Body>

<NS1:IA81CONFOUT><MessageId>IA81CONF</MessageId><OrderNumber>ON4002</OrderNumber><ItemReference>IY4003</ItemReference><ItemQuantity>4</ItemQuantity><CustomerNumber>CY4004</CustomerNumber>

<DeliveryRef>JOHNCORP</DeliveryRef><Confirm>Y</Confirm>

</NS1:IA81CONFOUT></tns:Body>

</tns:Envelope>

Message sent by the DataPower appliance to the requesting application

The HTTP body of the message returned by the DataPower appliance to the requesting

application follows a similar pattern to the first message sent to the DataPower

appliance. The difference is that the contents of this message is encrypted using the

return key. Decrypting this message would reveal the message sent by Message

Broker.Message 4. Message sent from the DataPower appliance to the application

Click to see code listing

Securing the connection between the DataPower appliance and Message Broker

Adding SSL support between the DataPower appliance and Message Broker completes

the security of the connections between them:Figure 13. Securing the link between the DataPower appliance and Message Broker

Page 37: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

SSL enabling HTTP for Message Broker

To enable SSL for Message Broker, it must first be configured and assigned a

certificate. For this article, a self-signed certificate within a key store is used by the

Message Broker HTTP listener process. You could also use a certificate signed by a

certificate authority. The broker is then configured to use this key store.

The Java ikeyman application is used to create the key store. To create a self-signed

certificate stored within this key store, select New Self-Signed Certificate. For this

article the following configuration is used:Figure 14. The self-signed certificate in ikeyman

To provide the public half of this certificate to the the DataPower appliance,

select Extract certificate. The following commands enable SSL, configure the key

store, provide the password for this key store, and set the HTTPS port:Listing 4. The commands to enable HTTPS in Message Broker>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPListener -n enableSSLConnector -v true

>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector -n keystoreFile -v "c:\Program Files\IBM\WMBv6.0\MyKeystore.jks"

>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector -n keystorePass -v ********

>mqsichangeproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector -n port -v 7083

Page 38: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

The broker must be restarted for these changes to take effect within the HTTP listener

process. You can then use the following two commands to verify the previous settings:Listing 5. The commands report the HTTPS settings in Message Broker>mqsireportproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPListener -a

HTTPListener=''uuid='HTTPListener'enableSSLConnector='true'traceLevel='none'traceSize='4194304'

BIP8071I: Successful command completion.

>mqsireportproperties WBRK6_DEFAULT_BROKER -b httplistener -o HTTPSConnector -a

HTTPSConnector=''uuid='HTTPSConnector'keystoreFile='c:\Program Files\IBM\WMBv6.0\MyKeystore.jks'keystorePass='********'port='7083'

BIP8071I: Successful command completion.

Enable the message flow for SSL

With the broker restarted, you can configure the HTTP input node for HTTPS and

redeploy the message flow to the broker. Figure 15 shows the properties of the HTTP

Input node within the message flow, with Use HTTPS checked:Figure 15. Properties of the HTTP node with the Use HTTPS item checked

You can use the netstat -a (or equivalent) command after Message Broker is restarted

and an HTTPS flow is deployed, to confirm that the HTTP listener is listening on the

configured port.

Configuring client-side SSL in the DataPower appliance

You must upload a certificate of the key generated for Message Broker into the

DataPower appliance, which is added as a trusted server within an SSL profile that is

then used for the SSL client crypto profile. To create and associate an SSL client crypto

profile, select Create on the main XML Firewall configuration page. To configure the

profile upload, then add the certificate exported from ikeyman to the Trusted Servers

section of the crypto profile. Select the option to authenticate and validate the certificate.

With this check the DataPower appliance can be trusted to connect only to trusted

servers.Figure 16. The Trusted Server configuration

Page 39: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

You must also reconfigure the XML firewall to point to the SSL port of the HTTP listener

(in this case the default value of 7083).

SSL encryption

To observe this change, an HTTP tunnel is placed between the DataPower appliance

and Message Broker and used to observe messages that pass in both directions

between the two components. Whilst some of the initial exchange that forms the SSL

protocol passes as clear text, after the private keys are established for the session, all

data is encrypted.

Message Broker Explorer

Message Broker Explorer (IS02 support pack) now includes a wizard that can configure

an XML firewall within the DataPower appliance for connection with HTTP flows

provisioned by Message Broker. For more information, see the first article below under

"Resources."

Conclusion

Page 40: Communicate Between Stylesheets Using WebSphere DataPower Context Variables

This article has demonstrated how you can use a WebSphere DataPower SOA

appliance to extend the function provided by WebSphere Message Broker and provide

WS-Security of SOAP messages to HTTP message flows. The article also showed how

to provide security between WebSphere Message Broker and the DataPow