Skip to end of metadata
Go to start of metadata

Purpose

The Translation filter translates requests and responses so that services receive requests in the format that they expect and clients receive responses in the format that they prefer. The translation files consumed by the Translation filter (for example,  some-translation-file.xsl ) may be placed at any valid location accessible by the Repose node.

General filter information

Filter name: translation

Filter configuration: translation.cfg.xml

Released: version 2.4.0

Prerequisites

Headers: The Translation filter has no required request headers.

Filter order: The Translation filter has no required preceding filters.

Standard filter order:  Place the Translation filter last in your filter chain.

Basic translation configuration

Configure the Translation filter by editing the translation.cfg.xml file.

1. Set Up Repose 
Configure Repose using either a cluster or a single instance configuration.

2. Add the Client Authentication Filter 
Add the Translation filter to your system model configuration. Place this filter last in your filter chain.

3. Configure the Translation Filter 

Configure the request and response translation using the following structure:

translation.cfg.xml
<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0" allow-doctype-decl="true" multi-match="true">
    <request-translations>
      <request-translation ...>
         <style-sheets>
            ....
         </style-sheets>
      </request-translation>
      ....
    </request-translations>
    <response-translations>
      <response-translation ...>
         <style-sheets>
            ....
         </style-sheets>
      </response-translation>
      ....
    </response-translations>
</translation>

Optional configuration examples

Example 1: Remove an element

The following translation.cfg.xml will apply two style sheets (identity.xsl and remove-element.xsl) to responses with status code 2xx and content type of application/xml if the Accept is also application/xml. The output of the translation chain will be application/xml. Two parameters (my-param and my-param2) will be passed to the identity.xsl.

Configuration 1 - response
    <response-translations>
        <response-translation 
               content-type="application/xml" 
               accept="application/xml" 
               translated-content-type="application/xml">
            <style-sheets>
                <style id="response1a" href="identity.xsl" />
                <style id="response1b" href="remove-element.xsl" />
            </style-sheets>
        </response-translation>

Testing application/xml - response

curl -X POST -H "content-type: application/xml" -H "accept: application/xml" http://localhost:8088/response/echobody -d "<a><remove-me>test</remove-me>Stuff</a>" -v
Output

In the resulting output, the remove-me element and its contents will be removed:

<a>Stuff</a>


Configuration 1 Request
<request-translations>
        <request-translation content-type="application/xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="request1a" href="identity.xsl" />
                <style id="request1b" href="remove-element.xsl" />
            </style-sheets>
        </request-translation>
Testing Application/xml Request
curl -X POST -H "content-type: application/xml" -H "accept: application/xml" http://localhost:8088/request/echobody -d "
<a><remove-me>test</remove-me>Stuff</a>" -v

Example 2: Add an element

The following translation.cfg.xml will apply two style sheets (identity.xsl and add-element.xsl) to responses with status code 2xx and content type of application/xhtml+xml if the Accept is application/xml. The output of the translation chain will be application/xml. 

Configuration 2 - response
<response-translation code-regex="2[\d]{2}"  content-type="application/xhtml+xml" accept="application/xml" translated-content-type="application/xml">
     <style-sheets>
            <style id="response2a" href="identity.xsl" />
            <style id="response2b" href="add-element.xsl" />
     </style-sheets>
</response-translation>

Testing application/xhtml+xml - response

curl -X POST -H "content-type: application/xhtml+xml" -H "accept: application/xml" -d "<a>Stuff</a>" http://localhost:8088/response/echobody -v
Configuration 2 Request
<request-translation content-type="application/xhtml+xml" accept="application/xml" translated-content-type="application/xml">
     <style-sheets>
         <style id="request2a" href="identity.xsl" />
         <style id="request2b" href="add-element.xsl" />
      </style-sheets>
</request-translation>

Testing application/xhtml+xml - request

curl -X POST -H "content-type: application/xhtml+xml" -H "accept: application/xml" -d "<a>Stuff</a>" http://localhost:8088/request/echobody -v


Output

In the resulting output, the add-element style sheet will add a new container element called add-me.

<add-me><a>Stuff</a></add-me>


Example 3: Convert JSON to JSONx

JSON content is converted into JSONx prior to sending the content to the style sheet chain.  For example, if the following JSON is sent in the request: 

JSON
{"field1": "value1", "field2": "value2"}

Click here to read more about JSONx.

Configuration 3 - response
        <response-translation 
			content-type="application/json" 
			accept="application/xml" 
			translated-content-type="application/xml">
            <style-sheets>
                <style id="response3a" href="identity.xsl" />
            </style-sheets>
        </response-translation>

Testing application/xml - response

curl -X POST -H "content-type: application/json" -H "accept: application/xml" -d '{"field1": "value1", "field2": "value2"}' http://localhost:8088/response/echobody -v


Configuration 3 Request
<request-translation content-type="application/json" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="request3a" href="identity.xsl" />
            </style-sheets>
        </request-translation>
Testing Application Request
curl -X POST -H "content-type: application/json" -H "accept: application/xml" -d '{"field1": "value1", "field2": "value2"}' http://localhost:8088/request/echobody -v
Output
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <json:string name="field1">value1</json:string>
  <json:string name="field2">value2</json:string>
</json:object>

Example 4: Convert JSON --> JSONx --> JSON

This example will convert JSON to JSONx, apply the identity translation, and then convert JSONx back to JSON. In order for your origin service to receive JSON, you must add line seven to your configuration. Otherwise, the request or response body will remain in JSONx.

Configuration 4 - response
          <response-translation 
			content-type="application/json" 
			accept="application/json" 
			translated-content-type="application/json">
            <style-sheets>
                <style id="response4a" href="identity.xsl" />
                <style id="response4b" href="jsonx2json.xsl" />
            </style-sheets>
        </response-translation>

 

 

Testing application/xml - response

curl -X POST -H "content-type: application/json" -H "accept: application/json" -d '{"field1": "value1", "field2": "value2"}' http://localhost:8088/response/echobody -v
Configuration 4 Request
<request-translation content-type="application/json" accept="application/json" translated-content-type="application/json">
        <style-sheets>
            <style id="request4a" href="identity.xsl" />
            <style id="request4b" href="jsonx2json.xsl" />
        </style-sheets>
</request-translation>

 

Testing application - request

curl -X POST -H "content-type: application/json" -H "accept: application/json" -d '{"field1": "value1", "field2": "value2"}' http://localhost:8088/request/echobody -v
Output
 { "field1":"value1", "field2":"value2" }

 

Example 5: Convert XML to JSON

Configuration 5 - response
<response-translation 
	content-type="application/xml" 
	accept="application/json" 
	translated-content-type="application/json">
            <style-sheets>
                <style id="response5a" href="limits-json.xsl" />
            </style-sheets>
</response-translation>

Testing application/json - response

Place the attached Translation filter file in the directory the curl command is being run from, to be able to get translated JSON output as shown.

curl -X POST -H "content-type: application/xml" -H "accept: application/json" -d @absolute-limits.xml  http://localhost:8088/response/echobody -v
Configuration 5 Request
<request-translation content-type="application/xml" accept="application/json" translated-content-type="application/json">
       <style-sheets>
          <style id="request5a" href="limits-json.xsl" />
       </style-sheets>
</request-translation>
Testing Application Request
curl -X POST -H "content-type: application/xml" -H "accept: application/json" -d @absolute-limits.xml http://localhost:8088/request/echobody -v
Output
{ "limits" : {    "absolute" : {"an absolute" : 5,"domain_value" : 3}}}

Example 6: Convert XML to Atom

This example will convert XML to an Atom feed.

Configuration 6 - response
<response-translation content-type="application/xml" accept="application/atom+xml" translated-content-type="application/atom+xml"
            <style-sheets>
                <style id="response6a" href="version-atom.xsl" />
            </style-sheets>
</response-translation>

Testing application/atom+xml - response

Place the attached version.xml file in the directory the curl command is being run from, to be able to get translated Atom feed output as shown.

curl -X POST -H "content-type: application/xml" -H "accept: application/atom+xml" -d @version.xml http://localhost:8088/response/echobody -v
Configuration 6 Request
<request-translation content-type="application/xml" accept="application/atom+xml" translated-content-type="application/atom+xml">
      <style-sheets>
            <style id="request6a" href="version-atom.xsl" />
      </style-sheets>
</request-translation>
Testing Application Request
curl -X POST -H "content-type: application/xml" -H "accept: application/atom+xml" -d @version.xml http://localhost:8088/request/echobody -v
Output
Embedded XSL
<feed xmlns="http://www.w3.org/2005/Atom">
   <title type="text">About This Version</title>
   <updated>2010-12-12T18:30:02.25Z</updated>
   <id>http://service.api.vendor.com/v1.0/</id>
   <author>
      <name>Rackspace</name>
      <uri>http://www.rackspace.com/</uri>
   </author>
   <link rel="self" href="http://service.api.vendor.com/v1.0/"/>
   <entry>
      <id>http://service.api.vendor.com/v1.0/</id>
      <title type="text">Version v1.0</title>
      <updated>2010-12-12T18:30:02.25Z</updated>
      <link href="http://service.api.vendor.com/v1.0/" rel="self"/>
      <link href="http://service.api.vendor.com/v1.0/Docs.pdf" type="application/pdf"
            rel="describedby"/>
      <link href="http://service.api.vendor.com/v1.0/application.wadl"
            type="application/vnd.sun.wadl+xml"
            rel="describedby"/>
      <content type="text">Version v1.0 DEPRECATED (2010-12-12T18:30:02.25Z)</content>
   </entry>
</feed>

Example 7: Convert XML to HTML

This example will convert XML to HTML.

Configuration 7 - response
<response-translation content-type="application/xml" accept="application/xhtml+xml" translated-content-type="application/xhtml+xml">
     <style-sheets>
          <style id="response7a" href="version-html.xsl" />
     </style-sheets>
  </response-translation>

Testing application/xml - response

Place the attached version.xml file in the directory the curl command is being run from, to be able to get translated html output attached.

curl -X POST -H "content-type: application/xml" -H "accept: application/xhtml+xml" -d @version.xml http://localhost:8088/response/echobody -v

 

 

Configuration 7 Request
<request-translation content-type="application/xml" accept="application/xhtml+xml" translated-content-type="application/xhtml+xml">
       <style-sheets>
            <style id="request7a" href="version-html.xsl" />
            </style-sheets>
       </request-translation>
</request-translations>
Testing Application Request
curl -X POST -H "content-type: application/xml" -H "accept: application/xhtml+xml" -d @version.xml http://localhost:8088/request/echobody -v 

Output
 

Example 8: Embedded XSL

By using an xsl element within the style element, xsl can be directly embedded into the translation configuration file.

Embedded XSL
<?xml version="1.0" encoding="UTF-8"?>
<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0">
    <response-translations>
        <response-translation content-type="application/xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="1" href="identity.xsl" />
                <style id="2" href="remove-element.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/xhtml+xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="1" href="identity.xsl" />
                <style id="3">
		  <xsl>
		    <xsl:stylesheet version="1.0"
				    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				    xmlns:xs="http://www.w3.org/2001/XMLSchema">
		      <xsl:output method="xml"/>
		      
		      <xsl:template match="/">
			<add-me>
			  <xsl:copy-of select="."/>
			</add-me>
		      </xsl:template>
		      
		    </xsl:stylesheet>
		  </xsl>
		</style>
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/json" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="1" href="identity.xsl" />
                <style id="3">
		  <xsl>
		    <xsl:stylesheet version="1.0"
				    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				    xmlns:xs="http://www.w3.org/2001/XMLSchema">
		      <xsl:output method="xml"/>
		      
		      <xsl:template match="/">
			<add-me>
			  <xsl:copy-of select="."/>
			</add-me>
		      </xsl:template>
		      
		    </xsl:stylesheet>
		  </xsl>
		</style>
            </style-sheets>
        </response-translation>
    </response-translations>
</translation>

Example 9: Header transformation

This example will demonstrate how to transform a given header to a desired header.

translation.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://wiki.openrepose.org/display/REPOSE/Translation -->
<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0">
  <request-translations>
    <request-translation http-methods="ALL" content-type="*/*" accept="*/*" translated-content-type="*/*">
       <style-sheets>
         <style id="ht1" href="header-transform.xsl" />
       </style-sheets>
    </request-translation>
 </request-translations>
</translation>

Example 10: URI and Query Transformation

This example will demonstrate how to transform path segments in the URI into query parameters for all requests.

<?xml version="1.0" encoding="UTF-8"?>
<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0" allow-doctype-decl="true">
    <request-translations>
        <request-translation>
            <style-sheets>
                <style id="ss1" href="path-to-query.xsl"/>
            </style-sheets>
        </request-translation>
    </request-translations>
</translation>

Configurable parameters

XML schema definition

Example configuration

The translation.cfg.xml file contains the following elements and attributes. Add the filter to your Repose deployment through the System Model Configuration.

ElementsAttributes

Required/

Optional

Description
<translation>-RequiredSpecifies the sub-elements and attributes to define your translation configuration.

<allow-doc-type>

-OptionalIf false, then any request/response body that contains an DOCTYPE section will be rejected.  If true, then DOCTYPE sections will be allowed.  However, repose will limit the entity definitions allowed in these sections.  Default is false.

<multi-match>

-OptionalIf true, then all translation chains that match the request will be applied in the order in which they are defined in the configuration.  If false, then only the first translation chain to match the request will be applied.  Default is false.  This attribute was added in version 2.6.8.

<xsl-engine>

-Optional

Select the XSL parser from the list.  

  • SaxonHE
  • SaxonEE

SaxonHE is the default. SaxonEE has initial support for XSLT 3.0 and requires a Saxon license.  This attribute was added in version 2.7.1.

<response-translation>

<request-translation>

-OptionalThe enumerated translation specifies a chain of stylesheets to be applied to a request response body and the criteria for when the chain should be applied.  All of the criteria must match before a chain is applied.  Both the <response-translation> and <request-translation> nodes have the same attributes & abilities.
http-methodsOptionalList of HTTP methods associated with this rate limit.
code-regexOptionalCode regex specifies for which response codes this style sheet chain should be applied. This is a regex.  
For example, 4[\d]{2} would match all response codes in the range from 400 to 499.
content-typeOptionalContent type specifies for which response content types this style sheet chain should be applied.  
For example, application/xml.
acceptOptionalSpecifies to which Accept type this chain should be applied.
For example, application/xml.
translated-content-typeOptionalSpecifies the content-type which is output by this chain. The response content-type is set to this if the style sheets are applied successfully.
<style-sheets>-RequiredContains the list of style sheets to be applied for this translation chain.
<style>-OptionalSpecifies one style sheet within the chain.  
idRequired only if using style.Unique id for this style sheet.
hrefNot required if style is embedded.URI which specifies the location of the style sheet. If a relative path is specified, then this will be relative to the REPOSE configuration directory.
<param>-OptionalSpecifies the attributes that define the parameters to be passed in to the transformer for the style sheet.
 nameRequired only if using param.Name of the parameter to be passed in to the transformer for the style sheet.
 valueRequired only if using param.Value of the parameter to be passed in to the transformer for the style sheet.
<xsl>-OptionalA style sheet can contain an embedded XSL. The embedded XSL would be placed within an xsl element within the style element.  If the XSL is embedded, then the href attribute of the style element would not be specified.

Return codes and conditions

This filter does not return specific response codes. The request will simply pass through to the next filter or to the origin service.

Translation filter notes

SAXON 9.4 functionality

The translation component processes requests and responses with XSLT 2.0 stylesheets.  If a SaxonEE license is installed, the XSLT 3.0 functionality can be enabled.  See the documentation on the xsl-engine attribute of the translation node for more information.

User defined entities in requests

As of Repose 2.6.0, the translation component will automatically remove, without expanding, user defined entities from requests and responses.  This is to prevent XXE attacks against Repose or any service behind Repose.

JSONX Translation for the message content

The translation component allows services to receive request message content as JSONx when the message content of the request that is sent to the service is JSON. JSON content will automatically be converted to JSONx when the request or response body contains JSON data.  See below for an example.  Click here to read more about JSONx.

JSONx content can be converted back to JSON by using the jsonx2json.xsl style sheet (attached; see below).

Dynamic translation XSLT updates

The translation component allows dynamic updates so that the translation XSLT files can be updated at runtime.

Sample files

The preceding examples use these XSL files and Repose configuration files. Using these files, after updating container.cfg.xml to use appropriate paths, you can run the example cURL commands. Click the arrow on the right of each sample to expand the source.

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

<limits xmlns="http://docs.openstack.org/common/api/v1.0">
    <absolute>
        <limit name="an absolute" value="5" />
        <limit name="domain_value" value="3" />
    </absolute>
</limits>
add-elements.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml"/>
  <xsl:template match="/">
    <add-me>
    <xsl:copy-of select="."/>
    </add-me>
  </xsl:template>
</xsl:stylesheet>
container.edit.me.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>

<repose-container xmlns='http://docs.openrepose.org/repose/container/v2.0'>
    <deployment-config client-request-logging="true" http-port="8088" proxy-thread-pool="20">
        <deployment-directory auto-clean="true">/edit/path/repose/deploy</deployment-directory>
        <artifact-directory check-interval="60000">/edit/path/repose/filters</artifact-directory>
    </deployment-config>
</repose-container>
header-transform.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:httpx="http://openrepose.org/repose/httpx/v1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:param name="input-headers-uri"/>
    <xsl:param name="output-headers-uri"/>
    <xsl:variable name="headersDoc" select="doc($input-headers-uri)"/>
    <xsl:template match="/">
        <xsl:copy-of select="."/>
        <xsl:apply-templates select="$headersDoc/*"/>
    </xsl:template>
    <xsl:template match="httpx:headers">
        <xsl:result-document method="xml" href="repose:output:headers.xml" include-content-type="no">
           <httpx:headers>
             <httpx:request>
               <xsl:apply-templates/>
             </httpx:request>
           </httpx:headers>
        </xsl:result-document>
     </xsl:template>
     <xsl:template match="httpx:header">
        <xsl:choose>
           <xsl:when test="@name = 'x-rackspace-webhook-token'">
             <xsl:element name="httpx:header">
               <xsl:attribute name="name">
                 <xsl:value-of select="'x-auth-token'"/>
               </xsl:attribute>
               <xsl:attribute name="value">
                 <xsl:value-of select="@value"/>
               </xsl:attribute>
               <xsl:attribute name="quality">
                 <xsl:value-of select="@quality"/>
               </xsl:attribute>
             </xsl:element>
           </xsl:when>
         </xsl:choose>
         <xsl:element name="httpx:header">
           <xsl:attribute name="name">
             <xsl:value-of select="@name"/>
           </xsl:attribute>
           <xsl:attribute name="value">
             <xsl:value-of select="@value"/>
           </xsl:attribute>
           <xsl:attribute name="quality">
             <xsl:value-of select="@quality"/>
           </xsl:attribute>
         </xsl:element>
     </xsl:template>
</xsl:stylesheet>
identity.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xsl:output method="xml"/>
  <xsl:template match="/">
    <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>
jsonx2json.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
    <xsl:output method="xml" encoding="utf-8" indent="no" omit-xml-declaration="no" media-type="application/xml"/>

    <xsl:template name="json:doNameAttr">
       <xsl:if test="local-name(..)!='array' and string-length(@name)>0">
          <xsl:value-of select="concat('&quot;', @name, '&quot;', ':')"/>
       </xsl:if>
    </xsl:template>

    <xsl:template match="json:object">
        <xsl:call-template name="json:doNameAttr"/>
        <xsl:text>{ </xsl:text>
        <xsl:for-each select="*">
           <xsl:apply-templates select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
       </xsl:for-each>
       <xsl:text> }</xsl:text>
    </xsl:template>

    <xsl:template match="json:array">
        <xsl:call-template name="json:doNameAttr" />
        <xsl:text>[ </xsl:text>
        <xsl:for-each select="*">
            <xsl:apply-templates select="." />
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text> ]</xsl:text>
    </xsl:template>

    <xsl:template match="json:string">
        <xsl:call-template name="json:doNameAttr"/>
        <xsl:text>"</xsl:text>
        <!-- XXX Need to replace " with &amp;quot; -->

        <xsl:value-of select="normalize-space()"/>
        <xsl:text>"</xsl:text>
    </xsl:template>

    <xsl:template match="json:number">
       <xsl:call-template name="json:doNameAttr"/>
       <xsl:value-of select="normalize-space()"/>
    </xsl:template>

    <xsl:template match="json:boolean">
       <xsl:call-template name="json:doNameAttr"/>
       <xsl:value-of select="normalize-space()"/>
    </xsl:template>

    <xsl:template match="json:null">
        <xsl:call-template name="json:doNameAttr"/>
        <xsl:text>null</xsl:text>
    </xsl:template>

</xsl:stylesheet>        
limits-json.xsl
<?xml version="1.0" encoding="UTF-8"?>

<transform xmlns="http://www.w3.org/1999/XSL/Transform"
           xmlns:lim="http://docs.openstack.org/common/api/v1.0"
           version="1.0">
    <output method="text" encoding="UTF-8"/>

    <template match="lim:limits">
        <text>{ "limits" : {</text>
        <apply-templates />
        <text>}}</text>
    </template>

    <template match="lim:rates">
        <text> "rate" : [</text>
        <apply-templates select="./lim:rate"/>
        <text>]</text>
    </template>

    <template match="lim:absolute">
        <if test="/lim:limits/lim:rates">
            <text>,</text>
        </if>
        <text>"absolute" : {</text>
        <apply-templates select="./lim:limit" mode="absolute"/>
        <text>}</text>
    </template>

    <template match="lim:rate">
        <variable name="attribs" select="./@*"/>
        <if test="position() != 1">
            <text>,</text>
        </if>
        <text>{</text>
        <apply-templates select="$attribs"/>
        <if test="$attribs">
            <text>,</text>
        </if>
        <text> "limit" : [</text>
        <apply-templates select="./lim:limit" mode="rate"/>
        <text>]</text>
        <text>}</text>
    </template>

    <template match="lim:limit" mode="rate">
        <if test="position() != 1">
            <text>,</text>
        </if>
        <text>{</text>
        <apply-templates select="./@*"/>
        <text>}</text>
    </template>

    <template match="lim:limit" mode="absolute">
        <if test="position() != 1">
            <text>,</text>
        </if>
        <call-template name="json-string">
            <with-param name="in" select="@name"/>
        </call-template>
        <text> : </text>
        <value-of select="@value"/>
    </template>

    <template match="@value | @remaining">
        <if test="position() != 1">
            <text>,</text>
        </if>
        <call-template name="json-string">
            <with-param name="in" select="name()"/>
        </call-template>
        <text> : </text>
        <value-of select="."/>
    </template>

    <template match="@*">
        <if test="position() != 1">
            <text>,</text>
        </if>
        <call-template name="json-string">
            <with-param name="in" select="name()"/>
        </call-template>
        <text> : </text>
        <call-template name="json-string">
            <with-param name="in" select="."/>
        </call-template>
    </template>

    <template name="json-string">
        <param name="in"/>
        <variable name="no-backslash">
            <call-template name="escape-out">
                <with-param name="in" select="$in"/>
                <with-param name="char" select="'\'"/>
            </call-template>
        </variable>
        <variable name="no-quote">
            <call-template name="escape-out">
                <with-param name="in" select="$no-backslash"/>
                <with-param name="char" select="'&quot;'"/>
            </call-template>
        </variable>
        <value-of select="concat('&quot;',$no-quote,'&quot;')"/>
    </template>

    <template name="escape-out">
        <param name="in" />
        <param name="char"/>
        <variable name="before" select="substring-before($in, $char)"/>
        <variable name="after" select="substring-after($in, $char)"/>
        <choose>
            <when test="string-length($before) &gt; 0 or string-length($after) &gt; 0">
                <value-of select="concat($before,'\',$char)"/>
                <call-template name="escape-out">
                    <with-param name="in" select="$after"/>
                    <with-param name="char" select="$char"/>
                </call-template>
            </when>
            <otherwise>
                <value-of select="$in"/>
            </otherwise>
        </choose>
    </template>
</transform>
path-to-query.xml
 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:httpx="http://openrepose.org/repose/httpx/v1.0">
    <!-- Declare the format of the output document -->
    <xsl:output method="xml"/>

    <!-- The params that get populated by the translation filter -->
    <xsl:param name="input-request-uri"/>
    <xsl:param name="input-query-uri"/>
    <xsl:param name="output-request-uri"/>
    <xsl:param name="output-query-uri"/>

    <!-- Assign variables to the request XML documents -->
    <xsl:variable name="requestDoc" select="doc($input-request-uri)"/>
    <xsl:variable name="queryDoc" select="doc($input-query-uri)"/>
    <!-- We parse the state and county here, but don't cover the corner cases (e.g., if the path ends with a '/') -->
    <xsl:variable name="state" select="tokenize($requestDoc//httpx:uri, '/')[position()=last()-1]"/>
    <xsl:variable name="county" select="tokenize($requestDoc//httpx:uri, '/')[position()=last()]"/>

    <!-- Match on the body, copy it, then process the rest of the request by applying templates -->
    <xsl:template match="/">
        <xsl:copy-of select="."/>
        <xsl:apply-templates select="$queryDoc/*"/>
        <xsl:apply-templates select="$requestDoc/*"/>
    </xsl:template>

    <!-- Write the query parameters by copying the existing parameters and adding the two we want -->
    <xsl:template match="httpx:parameters">
        <xsl:result-document method="xml" include-content-type="no" href="{$output-query-uri}">
            <parameters xmlns="http://openrepose.org/repose/httpx/v1.0">
                <xsl:apply-templates/>
                <parameter name="state" value="{$state}"/>
                <parameter name="county" value="{$county}"/>
            </parameters>
        </xsl:result-document>
    </xsl:template>

    <!-- Copy the existing parameters -->
    <xsl:template match="httpx:parameter">
        <xsl:copy/>
    </xsl:template>

    <!-- Remove the path segments from the uri and url that are now represented as query parameters -->
    <xsl:template match="httpx:request-information">
        <xsl:result-document method="xml" include-content-type="no" href="{$output-request-uri}">
            <request-information xmlns="http://openrepose.org/repose/httpx/v1.0">
                <!-- This will remove the state and county that we parsed above from the end of the uri and url -->
                <uri><xsl:value-of
                        select="substring(httpx:uri, 1, string-length(httpx:uri) - string-length(concat('/', $state, '/', $county)))"/>
                </uri>
                <url><xsl:value-of
                        select="substring(httpx:url, 1, string-length(httpx:url) - string-length(concat('/', $state, '/', $county)))"/>
                </url>
            </request-information>
        </xsl:result-document>
    </xsl:template>
</xsl:stylesheet>
remove-element.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="remove-me"/>

</xsl:stylesheet>
response-messaging.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>

<response-messaging xmlns="http://docs.openrepose.org/repose/response-messaging/v1.0">
    <status-code id="413" code-regex="413">
        <message media-type="*/*" content-type="application/json">
{
    "overLimit" : {
        "code" : 413,
        "message" : "OverLimit Retry...",
        "details" : "Error Details...",
	    "retryAfter" : "%{Retry-After DATE ISO_8601}o"
    }
}
        </message>

        <message media-type="application/xml" content-type="application/xml">
<![CDATA[
<overLimit
    xmlns="http://docs.openstack.org/compute/api/v1.1"
    code="413"
    retryAfter="%{Retry-After DATE ISO_8601}o">
  <message>OverLimit Retry...</message>
  <details>Error Details...</details>
</overLimit>
]]>
        </message>
    </status-code>
   
</response-messaging>
system-model.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>

<system-model xmlns="http://docs.openrepose.org/repose/system-model/v2.0">
    <repose-cluster id="repose-service">
        <nodes>
            <node id="proxy-n01" hostname="localhost" http-port="8088"  />
        </nodes>

        <filters>
            <filter name="translation" configuration="translation-request.cfg.xml" uri-regex="/request/echobody"/>
            <filter name="translation" configuration="translation.cfg.xml" uri-regex="/response/echobody"/>
            <filter name="default-router" />
        </filters>

        <destinations>
            <endpoint id="mocks" protocol="http" hostname="50.57.189.15" port="8080" root-path="/" default="true" />
        </destinations>
    </repose-cluster>
</system-model>
translation.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>

<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0">
    <response-translations>
        <response-translation content-type="application/xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="response1a" href="identity.xsl" />
                <style id="response1b" href="remove-element.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/xhtml+xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="response2a" href="identity.xsl" />
                <style id="response2b" href="add-element.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/json" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="response3a" href="identity.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/json" accept="application/json" translated-content-type="application/json">
            <style-sheets>
                <style id="response4a" href="identity.xsl" />
                <style id="response4b" href="jsonx2json.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/xml" accept="application/json" translated-content-type="application/json">
            <style-sheets>
                <style id="respone5a" href="limits-json.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/xml" accept="application/atom+xml" translated-content-type="application/atom+xml">
            <style-sheets>
                <style id="response6a" href="version-atom.xsl" />
            </style-sheets>
        </response-translation>
        <response-translation content-type="application/xml" accept="application/xhtml+xml" translated-content-type="application/xhtml+xml">
            <style-sheets>
                <style id="response7a" href="version-html.xsl" />
            </style-sheets>
        </response-translation>
    </response-translations>
</translation>
translation-request.cfg.xml
 <?xml version="1.0" encoding="UTF-8"?>

<translation xmlns="http://docs.openrepose.org/repose/translation/v1.0">
    <request-translations>
        <request-translation content-type="application/xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="request1a" href="identity.xsl" />
                <style id="request1b" href="remove-element.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/xhtml+xml" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="request2a" href="identity.xsl" />
                <style id="request2b" href="add-element.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/json" accept="application/xml" translated-content-type="application/xml">
            <style-sheets>
                <style id="request3a" href="identity.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/json" accept="application/json" translated-content-type="application/json">
            <style-sheets>
                <style id="request4a" href="identity.xsl" />
                <style id="request4b" href="jsonx2json.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/xml" accept="application/json" translated-content-type="application/json">
            <style-sheets>
                <style id="respone5a" href="limits-json.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/xml" accept="application/atom+xml" translated-content-type="application/atom+xml">
            <style-sheets>
                <style id="request6a" href="version-atom.xsl" />
            </style-sheets>
        </request-translation>
        <request-translation content-type="application/xml" accept="application/xhtml+xml" translated-content-type="application/xhtml+xml">
            <style-sheets>
                <style id="request7a" href="version-html.xsl" />
            </style-sheets>
        </request-translation>
    </request-translations>
</translation>
version-atom.xsl
<?xml version="1.0" encoding="UTF-8"?>

<!-- Atom transfrom -->
<!--
    This transform converts the versions or version document.
    It doesn't make sense to convert a choices document.
-->

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               xmlns:ver="http://docs.openstack.org/common/api/v1.0"
               xmlns:atom="http://www.w3.org/2005/Atom"
               xmlns="http://www.w3.org/2005/Atom"
               exclude-result-prefixes="ver atom"
               version="1.0">
    <xsl:param name="authorName" select="'Rackspace'"/>
    <xsl:param name="authorURI" select="'http://www.rackspace.com/'"/>
    <xsl:output method="xml" version="1.0"
                indent="yes"
                encoding="UTF-8"
                media-type="application/atom+xml"
                omit-xml-declaration="no"/>
    <xsl:variable name="versions" select="//ver:version"/>
    <xsl:template match="/">
         <feed>
             <xsl:apply-templates/>
         </feed>
    </xsl:template>

    <xsl:template match="ver:versions | ver:version">
        <xsl:variable name="id">
            <xsl:call-template name="id">
                <xsl:with-param name="version" select="$versions[1]"/>
                <xsl:with-param name="base" select="local-name() != 'version'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="title">
            <xsl:choose>
                <xsl:when test="local-name() = 'versions'">
                    <xsl:text>Available API Versions</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:text>About This Version</xsl:text>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <title type="text"><xsl:value-of select="$title"/></title>
        <updated><xsl:call-template name="latest-time"/></updated>
        <id><xsl:value-of select="$id"/></id>
        <author>
            <name><xsl:value-of select="$authorName"/></name>
            <uri><xsl:value-of select="$authorURI"/></uri>
        </author>
        <link rel="self" href="{$id}"/>
        <xsl:apply-templates select="$versions" mode="multiple">
            <xsl:sort select="@updated" order="descending"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ver:version" mode="multiple">
        <entry>
            <id><xsl:call-template name="id"/></id>
            <title type="text">Version <xsl:value-of select="@id"/></title>
            <updated><xsl:value-of select="@updated"/></updated>
            <xsl:apply-templates />
            <content type="text">
                <xsl:text>Version </xsl:text>
                <xsl:value-of select="@id"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="@status"/>
                <xsl:text> (</xsl:text>
                <xsl:value-of select="@updated"/>
                <xsl:text>)</xsl:text>
            </content>
        </entry>
    </xsl:template>

    <xsl:template match="atom:link">
        <xsl:element name="link">
            <xsl:copy-of select="@*"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="atom:media-type">
        <xsl:element name="media-type">
            <xsl:copy-of select="@*"/>
        </xsl:element>
    </xsl:template>


    <xsl:template name="latest-time">
       <xsl:for-each select="$versions">
           <xsl:sort select="@updated" order="descending"/>
           <xsl:if test="position() = 1">
               <xsl:value-of select="@updated"/>
           </xsl:if>
       </xsl:for-each>
    </xsl:template>

    <xsl:template name="id">
        <xsl:param name="version" select="."/>
        <xsl:param name="base" select="false()"/>
        <xsl:variable name="href">
            <xsl:choose>
                <xsl:when test="$version/atom:link[@rel='alternate']">
                    <xsl:value-of select="$version/atom:link[@rel='alternate']/@href"/>
                </xsl:when>
                <xsl:when test="$version/atom:link[@rel='self']">
                    <xsl:value-of select="$version/atom:link[@rel='self']/@href"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:message>version-atom.xsl:  Expected link with rel=alternate or rel=self!</xsl:message>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="$base">
                <xsl:value-of select="substring-before ($href, string($version/@id))"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$href"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="text()">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>
</xsl:transform>
version-html.xsl
<?xml version="1.0" encoding="UTF-8"?>

<!-- XHTML5 Transform -->

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               xmlns:ver="http://docs.openstack.org/common/api/v1.0"
               xmlns:atom="http://www.w3.org/2005/Atom"
               xmlns="http://www.w3.org/1999/xhtml"
               exclude-result-prefixes="ver atom"
               version="1.0">
    <xsl:output method="xml" version="1.0"
                encoding="UTF-8"
                media-type="application/xhtml+xml"
                omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html>&#xa;</xsl:text>
        <html lang="en">
            <xsl:apply-templates/>
        </html>
    </xsl:template>

    <xsl:template match="ver:versions | ver:choices">
        <xsl:variable name="title">
            <xsl:choose>
                <xsl:when test="local-name() = 'versions'">
                    <xsl:text>Available API Versions</xsl:text>
                </xsl:when>
                <xsl:when test="local-name() = 'choices'">
                    <xsl:text>Multiple Choices Available</xsl:text>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>
        <xsl:call-template name="httpHead">
            <xsl:with-param name="title" select="$title"/>
        </xsl:call-template>
        <body>
            <table>
                <thead>
                    <tr>
                        <th colspan="4" class="heading"><xsl:value-of select="$title"/></th>
                    </tr>
                    <tr>
                        <th>Link</th>
                        <th>Version</th>
                        <th>Status</th>
                        <th class="last">Media-Types</th>
                    </tr>
                </thead>
                <tbody>
                    <xsl:apply-templates mode="multiple"/>
                </tbody>
            </table>
        </body>
    </xsl:template>

    <xsl:template match="ver:version">
        <xsl:variable name="title" select="'About This Version'"/>
        <xsl:call-template name="httpHead">
            <xsl:with-param name="title" select="$title"/>
        </xsl:call-template>
        <body>
            <table>
                <thead>
                    <tr>
                        <th colspan="4" class="heading"><xsl:value-of select="$title"/></th>
                    </tr>
                    <tr>
                        <th>Version</th>
                        <th>Status</th>
                        <th>Documentation</th>
                        <th class="last">Media-Types</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td class='center'><xsl:call-template name="version"/></td>
                        <td class='center'><xsl:value-of select="@status"/></td>
                        <td>
                            <ul>
                                <xsl:apply-templates select="atom:link[@rel='describedby']" mode="single"/>
                            </ul>
                        </td>
                        <td>
                            <ul>
                                <xsl:apply-templates select="ver:media-types/ver:media-type"/>
                            </ul>
                        </td>
                    </tr>
                </tbody>
            </table>
        </body>
    </xsl:template>

    <xsl:template name="httpHead">
        <xsl:param name="title"/>
        <head>
            <title><xsl:value-of select="$title"/></title>
            <meta charset="UTF-8" />
            <style type="text/css">
                body { background-color: #D3D3D3; }
                table {text-align: center; margin-left:auto; margin-right:auto;
                border: 1px solid; border-collapse:collapse;}
                h1 {text-align: center}
                thead {background-color: black; color: white}
                table,td { border: 1px solid black; background-color: white; }
                th {border-right: 1px solid white; border-left: 1px solid black;
                padding: 5px;}
                td { padding: 15px; text-align: left;}
                td.center { text-align: center; }
                th.last {border-right: 1px solid black;}
                td.last {text-align:left;}
                th.heading {border-right: 1px solid black;
                            border-bottom: 1px solid white;
                            font-size: xx-large;}
                a:link, a:visited, a:active {color:black; background-color:white;
                                             text-decoration:none;}
                a:hover {color:black; background-color:white; text-decoration:underline;}
            </style>
        </head>
    </xsl:template>

    <xsl:template match="ver:version" mode="multiple">
        <xsl:variable name="endpoint" select="atom:link[@rel='self']"/>
        <tr>
            <td>
                <xsl:if test="$endpoint">
                    <xsl:call-template name="link">
                        <xsl:with-param name="in">
                            <xsl:value-of select="$endpoint/@href" />
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:if>
            </td>
            <td class="center">
                <xsl:call-template name="version"/>
            </td>
            <td class="center"><xsl:value-of select="@status"/></td>
            <td class="last">
                <ul>
                    <xsl:apply-templates/>
                </ul>
            </td>
        </tr>
    </xsl:template>

    <xsl:template match="atom:link[@rel='describedby']" mode="single">
        <xsl:variable name="href" select="@href"/>
        <xsl:variable name="type" select="@type"/>
        <li><a href="{$href}">
        <xsl:choose>
            <xsl:when test="$type = 'application/pdf'">
                <xsl:text>Developer Guide</xsl:text>
            </xsl:when>
            <xsl:when test="$type = 'application/vnd.sun.wadl+xml'">
                <xsl:text>WADL</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>Other (</xsl:text>
                <xsl:value-of select="$type"/>
                <xsl:text>)</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
        </a></li>
    </xsl:template>

    <xsl:template name="version">
        <xsl:value-of select="@id"/>
        <xsl:if test="@updated">
            <br />
            <xsl:text> (</xsl:text>
            <xsl:choose>
                <xsl:when test="contains(string(@updated),'T')">
                    <xsl:value-of select="substring-before(string(@updated),'T')"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="@updated"/>
                </xsl:otherwise>
            </xsl:choose>
            <xsl:text>)</xsl:text>
        </xsl:if>
    </xsl:template>

    <xsl:template name="link">
        <xsl:param name="in"/>
        <a href="{$in}"><xsl:value-of select="$in"/></a>
    </xsl:template>

    <xsl:template match="ver:media-type">
        <li><xsl:value-of select="@base"/>, <xsl:value-of select="@type"/></li>
    </xsl:template>

    <xsl:template match="text()" mode="multiple">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>

    <xsl:template match="text()">
        <xsl:value-of select="normalize-space(.)"/>
    </xsl:template>
</xsl:transform> 
  • No labels

5 Comments

  1. On Example 1, it said:

    The following translation.cfg.xml will apply two style sheets (identity.xsl and remove-element.xsl) to responses with status code 2xx and content type of application/xml if the Accept is also application/xml. The output of the translation chain will be application/xml. Two parameters (my-param and my-param2) will be passed to the identity.xsl.

    But the actual example of the translation.cfg.xml does not show the 2 parameters: my-param and my-param2.

  2. Hi Shinta,

    We will get a proper example up soon. Thanks for pointing that out to us.

    Renée

  3. Hi, Renee,

    Can we also add http-methods into the "Configurable Parameters" table?

    thanks,

    -shinta

  4. I will add it today. (smile)

  5. Hi,

    I think there is one issue with the "TranslationHandler.java".  In method "handleResponse()"  the code is as below:  filterDirector.requestHeaderManager().putHeader("content-type", pool.getResultContentType()); ( https://github.com/rackerlabs/repose/blob/master/repose-aggregator/components/filters/translation/src/main/java/org/openrepose/filters/translation/TranslationHandler.java - line no 175 )

    I think it should be responseHeaderManager() instead. Please check on this.


    Regards,

     Suman