 | Level: Advanced David Z. Maze (dmaze@us.ibm.com), Software Engineer, IBM
15 Aug 2007 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.
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 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 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
named header 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 saved context 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
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.
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 to var://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 by var://context/stylesheet/name.
Listing 3. Picking a stylesheet based on SOAP version
<?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 a
version 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 EXSLT extension functions. Of note, they support the
func: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 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.
Download | Description | Name | Size | Download method |
|---|
| DataPower domain export with dp:variable sample | dpvar-ssonly.zip | 2KB | HTTP |
|---|
Resources
About the author  | 
|  |
David Maze is an engineer in the IBM WebSphere DataPower XML Technology group. His major DataPower projects have included rewriting the XML Schema
validation engine, software integration for the XG4 XML accelerator, and work on the DataPower rule execution engine. |
Rate this page
|  |