XSLT policy examples

Examples of the OpenAPI (Swagger 2.0) definitions of XSLT policies.

Note: The XML specification https://www.w3.org/TR/xml/ does not specify a preferred order for XML namespace (XMLNS) attributes. Best practice is to not rely upon the sequence of XMLNS attributes if you write custom parsing code.

Simple example with no context current payload

The following is an example of where the XSLT input document does not use the context current payload (there is no input):
- xslt:
  title: example xslt
  source: |
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
        <Hello>World!</Hello>
      </xsl:template>
    </xsl:stylesheet>

Concatenation and transformation

The following example shows a more complex XSLT transform source, where the stylesheet concatenates two input strings and transforms the third input string to the IP address of the client:
- xslt:
  title: xslt
  input: true
  source: |
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xalan="http://xml.apache.org/xslt"
        xmlns:fn="http://www.w3.org/2005/xpath-functions"
        xmlns:dp="http://www.datapower.com/extensions"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xs4xs="http://www.w3.org/2001/XMLSchema"
        xmlns:io="http://xformMessage"
        xmlns:map="http://xformMessage/xform"
        xmlns:msl="http://www.ibm.com/xmlmap"
        exclude-result-prefixes="fn dp dp map xalan msl"
        version="1.0">
      <xsl:output method="xml" encoding="UTF-8" indent="no"/>

      <!-- root wrapper template  -->
      <xsl:template match="/">
        <msl:datamap>
          <xsl:choose>
            <xsl:when test="not(msl:datamap/dataObject[1]/@xsi:nil)">
              <xsl:element name="dataObject">
                <xsl:attribute name="xsi:type">
                  <xsl:value-of select="'io:data'"/>
                </xsl:attribute>
                <xsl:call-template name="map:xform">
                  <xsl:with-param name="data" select="msl:datamap/dataObject[1]"/>
                </xsl:call-template>
              </xsl:element>
            </xsl:when>
            <xsl:otherwise>
              <xsl:element name="dataObject">
                <xsl:attribute name="xsi:type">
                  <xsl:value-of select="'io:data'"/>
                </xsl:attribute>
                <xsl:attribute name="xsi:nil">
                  <xsl:text>true</xsl:text>
                </xsl:attribute>
              </xsl:element>
            </xsl:otherwise>
          </xsl:choose>
        </msl:datamap>
      </xsl:template>

      <!-- This rule represents a type mapping: "data" to "io:data".  -->
      <xsl:template name="map:xform">
        <xsl:param name="data"/>
        <!-- a simple data mapping: "$data/StringOne"(string) to "StringOne"(string) -->
        <xsl:if test="$data/StringOne">
          <StringOne>
            <xsl:value-of select="concat($data/StringOne, $data/StringTwo)"/>
          </StringOne>
        </xsl:if>
        <!-- a simple mapping with no associated source:  to "StringTwo"(string) -->
        <StringTwo>
          <xsl:value-of select="dp:client-ip-addr()"/>
        </StringTwo>
        <!-- a simple data mapping: "$data/NumberOne"(int) to "NumberOne"(int) -->
        <xsl:if test="$data/NumberOne">
          <NumberOne>
            <xsl:value-of select="$data/NumberOne"/>
          </NumberOne>
        </xsl:if>
        <!-- a simple data mapping: "$data/NumberTwo"(int) to "NumberTwo"(int) -->
        <xsl:if test="$data/NumberTwo">
          <NumberTwo>
            <xsl:value-of select="$data/NumberTwo"/>
          </NumberTwo>
        </xsl:if>
        <!-- a simple data mapping: "$data/NumberThree"(int) to "NumberThree"(int) -->
        <xsl:if test="$data/NumberThree">
          <NumberThree>
            <xsl:value-of select="$data/NumberThree"/>
          </NumberThree>
        </xsl:if>
      </xsl:template>

      <!-- *****************    Utility Templates    ******************  -->
      <!-- copy the namespace declarations from the source to the target -->
      <xsl:template name="copyNamespaceDeclarations">
        <xsl:param name="root"/>
        <xsl:for-each select="$root/namespace::*[not(name() = '')]">
          <xsl:copy/>
        </xsl:for-each>
      </xsl:template>
    </xsl:stylesheet>

Obtain query parameter values and refer to context variables

The following example shows a complete OpenAPI (Swagger 2.0) source file. The API includes an XSLT policy that obtains a query parameter value in XSLT, and also uses the getvariable method to retrieve the value of the context variable request.headers.user-agent.
swagger: '2.0'
info:
  x-ibm-name: xslt
  title: xslt
  version: 1.0.0
schemes:
  - https
host: $(catalog.host)
basePath: /xslt
consumes:
  - application/json
produces:
  - application/json
securityDefinitions:
  clientIdHeader:
    type: apiKey
    in: header
    name: X-IBM-Client-Id
security:
  - clientIdHeader: []
x-ibm-configuration:
  testable: true
  enforced: true
  cors:
    enabled: true
  assembly:
    execute:
      - operation-switch:
          title: operation-switch
          case:
            - operations:
                - verb: get
                  path: /hello
              execute:
                - xslt:
                    title: SayHello
                    input: false
                    source: |
                      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
                        <xsl:template match="/">
                          <xsl:element name="APIc">
                             <xsl:text>Hello World!</xsl:text>
                          </xsl:element>
                        </xsl:template>
                      </xsl:stylesheet>
            - operations:
                - verb: get
                  path: /getContextQueryVar
              execute:
                - xslt:
                    title: GetContextQueryVar
                    input: false
                    source: |
                      <xsl:stylesheet version="1.0"
                        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                        xmlns:apim="http://www.ibm.com/apimanagement">
                        <xsl:import href="local:/isp/policy/apim.custom.xsl"/>
                        <xsl:template match="/">
                          <xsl:call-template name="apim:output">
                            <xsl:with-param name="mediaType" select="'application/xml'"/>
                          </xsl:call-template>
                          <APIC>
                            <xsl:element name="apim.getVariable">        
                              <xsl:element name="useragent">
                                <xsl:value-of select="apim:getVariable('request.headers.user-agent')"/>
                              </xsl:element>
                              <xsl:element name="query">
                                <xsl:value-of select="apim:getVariable('request.querystring')"/>
                              </xsl:element>
                            </xsl:element>
                          </APIC>
                        </xsl:template>
                      </xsl:stylesheet>
            - operations:
                - verb: get
                  path: /getQuery
              execute: []
          otherwise:
            - throw: null
              title: handling unknown operation
              name: Unsupported
    catch:
      - errors:
          - Unsupported
        execute:
          - set-variable:
              actions:
                - set: message.body
                  value: '<error>Not Supported</error>'
  phase: realized
paths:
  /hello:
    get:
      responses:
        '200':
          description: 200 OK
  /getContextQueryVar:
    get:
      responses:
        '200':
          description: 200 OK
definitions: {}
tags: []