5.1.12 XSL Extension

For those situations where you would like to augment the functionality of XSLT with calls to a procedural language, Apache Xalan supports the creation and use of extension elements and extension functions.

Refer to xml.apache.org/xalan-j/extensions.html

Xalan-Java extensions

Compiled transformation style sheets (XSLTC) support the use of extension functions implemented in external Java classes.

The following example illustrates how to create and use an extension function.

XML source:

 

<?xml version="1.0" encoding="UTF-8"?>
 
<Orders>
  <SalesOrder SONumber="">
    <Customer CustNumber="543">
      <CustName>ABC Industries</CustName>
      <Street>123 Main St</Street>
      <City>Chicago</City>
      <State>IL</State>
      <PostCode>60609</PostCode>
    </Customer>
  </SalesOrder>
</Orders>

 

Transformation style sheet:

 

<?xml version="1.0" encoding="UTF-8"?>
 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:rdml="http://www.acme.com/2000/XML/Function"
    xmlns:xalan="http://xml.apache.org/xalan"
    xmlns:java="http://xml.apache.org/xalan/java"
    exclude-result-prefixes="xalan java">
 
<xsl:output method="xml" indent="yes" xalan:indent-amount="2"/>
 
<xsl:template match="/">
 
<rdml:function>
 
<rdml:fields>
    <xsl:call-template name="function-level"/>
</rdml:fields>
 
</rdml:function>
 
</xsl:template>
 
<xsl:template name="function-level">
 
<rdml:field name="DELIVERY" value="{java:com.acme.xsl.Extension.getValue(/Orders/SalesOrder/@Delivery,'MISSING')}"/>
 
<rdml:field name="ORDER" value="{java:com.acme.xsl.Extension.getValue(/Orders/SalesOrder/@SONumber,'MISSING','BLANK')}"/>
 
<rdml:field name="STATEDESC" value="{java:com.acme.xsl.Extension.getDescription(/Orders/SalesOrder/Customer/State)}"/>
 
<rdml:field name="CUSTNUM" value="{/Orders/SalesOrder/Customer/@CustNumber}"/>
<rdml:field name="NAME" value="{/Orders/SalesOrder/Customer/CustName}"/>
<rdml:field name="STREET" value="{/Orders/SalesOrder/Customer/Street}"/>
<rdml:field name="CITY" value="{/Orders/SalesOrder/Customer/City}"/>
<rdml:field name="STATE" value="{/Orders/SalesOrder/Customer/State}"/>
<rdml:field name="ZIP" value="{/Orders/SalesOrder/Customer/PostCode}"/>
 
</xsl:template>
 
</xsl:transform>

 

XML transformation:

 

<?xml version="1.0" encoding="UTF-8"?>
<rdml:function xmlns:rdml="http://www.acme.com/2000/XML/Function">
  <rdml:fields>
    <rdml:field value="MISSING" name="DELIVERY"/>
    <rdml:field value="BLANK" name="ORDER"/>
    <rdml:field value="Illinois" name="STATEDESC"/>
    <rdml:field value="543" name="CUSTNUM"/>
    <rdml:field value="ABC Industries" name="NAME"/>
    <rdml:field value="123 Main St" name="STREET"/>
    <rdml:field value="Chicago" name="CITY"/>
    <rdml:field value="IL" name="STATE"/>
    <rdml:field value="60609" name="ZIP"/>
  </rdml:fields>
</rdml:function>

 

Java extension:

 

package com.acme.xsl ;
 
import org.w3c.dom.* ;
 
public class Extension
{
 
    public static String getDescription ( String code )
    {
        if ( code.equalsIgnoreCase ( "IL" ) )
        {
            return "Illinois" ;
        }
 
        return "?" ;
    }
 
    public static String getValue ( NodeList nodeList, String missingValue )
    {
        return getValue ( nodeList, missingValue, "" ) ;
    }
 
    public static String getValue ( NodeList nodeList, String missingValue, String blankValue )
    {
        int length = nodeList.getLength () ;
 
        if ( length == 0 )
        {
            return missingValue ;
        }
 
        Node node = nodeList.item ( 0 ) ;
 
        String nodeValue = node.getNodeValue () ;
 
        if ( nodeValue == null )
        {
            return blankValue ;
        }
 
        if ( nodeValue.trim().equals ( "" ) )
        {
            return blankValue ;
        }
 
        return nodeValue ;
    }
}