Skip to main content
Previous sectionNext section

Performing XSLT Transformations

XSLT (Extensible Stylesheet Language Transformations) is an XML-based language that you use to describe how to transform a given XML document into another XML or other “human-readable” document. You can use classes in the %XML.XSLT and %XML.XSLT2 packages to perform XSLT 1.0 and 2.0 transforms.

Note:

The XML declaration of any XML document that you use should indicate the character encoding of that document, and the document should be encoded as declared. If the character encoding is not declared, InterSystems IRIS uses the defaults described in “Character Encoding of Input and Output,” earlier in this book. If these defaults are not correct, modify the XML declaration so that it specifies the character set actually used.

Overview of Performing XSLT Transformations in InterSystems IRIS

InterSystems IRIS provides two XSLT processors, each with its own API:

  • The Xalan processor supports XSLT 1.0. The %XML.XSLT package provides the API for this processor.

  • The Saxon processor supports XSLT 2.0. The %XML.XSLT2 package provides the API for this processor.

    The %XML.XSLT2 API sends requests to Saxon over a connection to the XSLT 2.0 Gateway. The gateway allows multiple connections. This means that, for example, you could have two separate InterSystems IRIS processes connected to the gateway, each with its own set of compiled stylesheets, sending transform requests at the same time.

    With the Saxon processor, compiled stylesheets and the isc:evaluate cache are connection-specific; you must manage your own connection to take advantage of either feature. If you open a connection and create a compiled stylesheet or evaluate a transform that populates the isc:evaluate cache, all other transforms evaluated on that connection will have access to the compiled stylesheet and isc:evaluate cache entries. If you open a new connection, other connections (and their compiled stylesheets and caches) are ignored.

The APIs are similar for the two processors, except that methods in %XML.XSLT2 use an additional argument, to specify the gateway connection to use.

To perform XSLT transformations, do the following:

  1. If you are using the Saxon processor, configure the XSLT Gateway Server, as described in the next section. Or use the default configuration.

    The gateway is not needed if you are using the Xalan processor.

    The system automatically starts the gateway when needed. Or you can manually start it.

  2. If you are using the Saxon processor, optionally create an instance of %Net.Remote.Gateway, which represents a single connection to the XSLT Gateway.

    Note that this step is required to take advantage of compiled stylesheets and the isc:evaluate cache, when you are using the Saxon processor.

  3. Optionally create a compiled stylesheet and load it into memory. See “Creating a Compiled Stylesheet,” later in this chapter. If you are using the Saxon processor, be sure to specify the gateway argument when you create the compiled stylesheet.

    This step is useful if you intend to use the same stylesheet repeatedly. This step, however, also consumes memory. Be sure to remove the compiled stylesheet when you no longer need it.

  4. Call one of the transform methods of the applicable API. If you are using the Saxon processor, optionally specify the gateway argument when you call the transform method.

    See “Performing an XSLT Transform,” later in this chapter.

  5. Optionally call additional transform methods. If you are using the Saxon processor, optionally specify the gateway argument when you call the transform method; this enables you to evaluate another transform using the same connection. This transformation will have access to all compiled stylesheets and isc:evaluate cache entries associated with this connection. If you open a new connection, other connections (and their compiled stylesheets and caches) are ignored.

Studio also provides a wizard that you can use to test XSLT transformations; this is described later in this chapter.

Configuring, Starting, and Stopping the XSLT 2.0 Gateway

When you use the Saxon processor (to perform XSLT 2.0 transformations), InterSystems IRIS uses the XSLT 2.0 Gateway (which in turn uses Java). To configure this gateway:

  1. In the Management Portal, select System Administration > Configuration > Connectivity > XSLT 2.0 Gateway Server.

  2. Select Go.

    The system displays the XSLT Gateway Server page.

    The left area displays configuration details, and the right area displays recent activity.

  3. In the left area, optionally specify the following settings:

    • Port Number — TCP port number for exclusive use by the XSLT 2.0 Gateway. This port number must not conflict with any other local TCP port on the server.

      The default is the InterSystems IRIS superserver port number plus 3000. If this number is greater than 65535, then the system uses 54773.

    • Java Version — Java version to use.

    • Log File — File pathname for a log file. If you omit this setting, no logging is performed. If you specify a filename but omit the directory, the log file is written to the system manager’s directory.

    • Java Home Directory — Path of the directory that contains the Java bin directory. Specify this if there is no default Java on the server, or if you want to use a different Java.

      To see the default Java, execute the following command in a shell on the server:

      java -version
      Copy code to clipboard
    • JVM Arguments — Any additional arguments for the Java Virtual Machine to use.

    This area also displays the current value of the JAVA_HOME environment variable.

    Note that you cannot edit any of these values while the gateway is running.

  4. If you have made changes, select Save to save them. Or select Reset to discard them.

  5. Optionally select Test to test your changes.

On this page, you can also do the following:

  • Start the gateway. To do so, select Start in the right area.

    Note that InterSystems IRIS automatically starts the gateway when needed. It is not necessary to start the gateway manually.

  • Stop the gateway. To do so, select Stop in the right area.

Reusing an XSLT Gateway Server Connection (XSLT 2.0)

If you are using the Saxon processor, InterSystems IRIS uses the XSLT 2.0 Gateway, which you have previously configured. To communicate with this gateway, InterSystems IRIS internally creates an XSLT gateway connection (an instance of %Net.Remote.Gateway). By default, the system creates a connection, uses it for the transformation, and then discards the connection. There is overhead associated with opening a new connection, so maintaining a single connection for multiple transforms gives the best performance. Also, you must maintain your own connection in order to take advantage of compiled stylesheets and the isc:evaluate cache.

To reuse an XSLT gateway connection:

  1. Call the StartGateway() method of %XML.XSLT2.Transformer:

     set status=##class(%XML.XSLT2.Transformer).StartGateway(.gateway)
    Copy code to clipboard

    This method starts the XSLT 2.0 Gateway (if it is not already running) and returns, as output, an instance of %Net.Remote.Gateway. Note that the method also returns a status.

    The instance of %Net.Remote.Gateway represents the connection to the gateway.

    StartGateway() has an optional second argument, useSharedMemory. If this argument is true (the default), connections to localhost or to 127.0.0.1 will use shared memory, if that is possible. To force the connections to only use TCP/IP, set this argument to false.

  2. Check the status returned by the previous step:

     if $$$ISERR(status) {
         quit
     }
    Copy code to clipboard
  3. Create any compiled stylesheets. When you do so, specify the gateway argument as the instance of instance of %Net.Remote.Gateway that you created in step 1.

  4. Call the transform methods of %XML.XSLT2.Transformer as needed (TransformFile(), TransformFileWithCompiledXSL(), TransformStream(), and TransformStreamWithCompiledXSL()). When you do so, specify the gateway argument as the instance of %Net.Remote.Gateway that you created in step 1.

  5. When you no longer need a given compiled stylesheet, call the ReleaseFromServer() method of %XML.XSLT2.CompiledStyleSheet:

     Set status=##class(%XML.XSLT2.CompiledStyleSheet).ReleaseFromServer(compiledStyleSheet,,gateway) 
    Copy code to clipboard
    Important:

    Be sure to use this method when you no longer need the compiled stylesheet.

  6. When you no longer need the XSLT gateway connection, call the StopGateway() method of %XML.XSLT2.Transformer, passing the gateway connection as the argument:

     set status=##class(%XML.XSLT2.Transformer).StopGateway(gateway)
    Copy code to clipboard

    This method discards the connection and resets the current device. It does not stop the XSLT 2.0 Gateway.

    Important:

    Be sure to use this method when you no longer need the connection.

For an example, see the method Example10() in XSLT2.Examples in the SAMPLES namespace.

Troubleshooting an XSLT 2.0 Gateway Server Connection

While the XSLT 2.0 gateway is open, it is possible for a connection between InterSystems IRIS and the gateway server to become invalid. For example, if a network error occurs or the gateway server is restarted after InterSystems IRIS connects to it, a connection may not close properly. As a result, you may experience errors.

You can attempt to reconnect InterSystems IRIS to the gateway server by calling the %LostConnectionCleanup() method and %Reconnect methods of the XSLT gateway connection object in succession. For more information, see %Net.Remote.Gateway, which is the class that the XSLT gateway connection object inherits from.

If you prefer to automate the process of reconnecting to the gateway server in the event of a disconnection, set the AttemptReconnect property for the gateway connection object to true.

Creating a Compiled Stylesheet

If you intend to use the same style sheet repeatedly, you may want to compile it to improve speed. Note that this step consumes memory. Be sure to remove the compiled style sheet when you no longer need it.

To create a compiled style sheet:

For all these methods, the complete argument list is as follows, in order:

  1. source — The style sheet.

    For CreateFromFile(), this argument is the filename. For CreateFromStream(), this argument is a stream.

  2. compiledStyleSheet — The compiled style sheet, returned as an output parameter.

    This is an instance of the style sheet class (%XML.XSLT.CompiledStyleSheet or %XML.XSLT2.CompiledStyleSheet, as appropriate).

  3. errorHandler — An optional custom error handler to use when compiling the style sheet. See “Customizing the Error Handling,” later in this chapter.

    For methods in both classes, this is an instance of %XML.XSLT.ErrorHandler.

  4. (Only for %XML.XSLT2.CompiledStyleSheet) gateway — An instance of %Net.Remote.Gateway. See “Reusing an XSLT Gateway Server Connection (XSLT 2.0).”

The CreateFromFile() and CreateFromStream() methods return a status, which should be checked.

For example:

 //set tXSL equal to the OREF of a suitable stream
 Set tSC=##class(%XML.XSLT.CompiledStyleSheet).CreateFromStream(tXSL,.tCompiledStyleSheet)
 If $$$ISERR(tSC) Quit
Copy code to clipboard

Performing an XSLT Transform

To perform an XSLT transform:

  • If you are using the Xalan processor (for XSLT 1.0), use one of the following class methods of %XML.XSLT.Transformer:

    • TransformFile() — Transforms a file, given an XSLT style sheet.

    • TransformFileWithCompiledXSL() — Transforms a file, given a compiled XSLT style sheet.

    • TransformStream() — Transforms a stream, given an XSLT style sheet.

    • TransformStreamWithCompiledXSL() — Transforms a stream, given a compiled XSLT style sheet.

    • TransformStringWithCompiledXSL() — Transforms a string, given a compiled XSLT style sheet.

    For these methods, use an instance of %XML.XSLT.CompiledStyleSheet as the compiled stylesheet. See “Creating a Compiled Stylesheet.”

  • If you are using the Saxon processor (for XSLT 2.0), use one of the following class methods of %XML.XSLT2.Transformer:

    • TransformFile() — Transforms a file, given an XSLT style sheet.

    • TransformFileWithCompiledXSL() — Transforms a file, given a compiled XSLT style sheet.

    • TransformStream() — Transforms a stream, given an XSLT style sheet.

    • TransformStreamWithCompiledXSL() — Transforms a stream, given a compiled XSLT style sheet.

    For these methods, use an instance of %XML.XSLT2.CompiledStyleSheet as the compiled stylesheet. See “Creating a Compiled Stylesheet.”

These methods have similar signatures. The argument lists for these methods are as follows, in order:

  1. pSource — The source XML, which is to be transformed. See the table after this list.

  2. pXSL — The style sheet or compiled style sheet. See the table after this list.

  3. pOutput — The resulting XML, returned as an output parameter. See the table after this list.

  4. pErrorHandler — An optional custom error handler. See “Customizing the Error Handling,” later in this chapter. If you do not specify a custom error handler, the method uses a new instance of %XML.XSLT.ErrorHandler (for both classes).

  5. pParms — An optional InterSystems IRIS multidimensional array that contains parameters to be passed to the style sheet. See “Specifying Parameters for Use by the Stylesheet,” later in this chapter.

  6. pCallbackHandler — An optional callback handler that defines XSLT extension functions. See “Adding and Using XSLT Extension Functions,” later in this chapter.

  7. pResolver — An optional entity resolver. See “Performing Custom Entity Resolution,” later in this book.

  8. (Only for %XML.XSLT2.Transformer) gateway — An optional instance of %Net.Remote.Gateway. Specify this argument if you want to reuse an XSLT Gateway connection for better performance; see “Reusing an XSLT Gateway Server Connection (XSLT 2.0).”

For reference, the following table shows the first three arguments of these methods, compared side by side:

Comparison of XSLT Transform Methods
Method pSource (Input XML) pXSL (Stylesheet) pOutput(Output XML)
TransformFile() String that gives a file name String that gives a file name String that gives a file name
TransformFileWithCompiledXSL() String that gives a file name Compiled style sheet String that gives a file name
TransformStream() Stream Stream Stream, returned by reference
TransformStreamWithCompiledXSL() Stream Compiled style sheet Stream, returned by reference
TransformStringWithCompiledXSL() String Compiled style sheet String that gives a file name

Examples

This section shows a couple of transformations, using the following code (but different input files):

  Set in="c:\0test\xslt-example-input.xml"
  Set xsl="c:\0test\xslt-example-stylesheet.xsl"
  Set out="c:\0test\xslt-example-output.xml"
  Set tSC=##class(%XML.XSLT.Transformer).TransformFile(in,xsl,.out)
  Write tSC 
Copy code to clipboard

Example 1: Simple Substitution

In this example, we start with the following input XML:

<?xml version="1.0" ?>
<s1 title="s1 title attr">
  <s2 title="s2 title attr">
    <s3 title="s3 title attr">Content</s3>
  </s2>
</s1>
Copy code to clipboard

And we use the following style sheet:

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/>
 
<xsl:template match="//@* | //node()">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="/s1/s2/s3">
<xsl:apply-templates select="@*"/>
<xsl:copy>
Content Replaced
</xsl:copy>
</xsl:template>  

</xsl:stylesheet>
Copy code to clipboard

In this case, the output file would be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<s1 title="s1 title attr">
  <s2 title="s2 title attr">
    <s3>
Content Replaced
</s3>
  </s2>
</s1>
Copy code to clipboard

Example 2: Extraction of Contents

In this example, we start with the following input XML:

<?xml version="1.0" encoding="UTF-8"?>
<MyRoot>
   <MyElement No="13">Some text</MyElement>
   <MyElement No="14">Some more text</MyElement>
</MyRoot>
Copy code to clipboard

And we use the following style sheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"   
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"
            media-type="text/plain"/>
<xsl:strip-space elements="*"/>

<!-- utilities not associated with specific tags -->
<!-- emit a newline -->
<xsl:template name="NL">
    <xsl:text>&#xa;</xsl:text>
</xsl:template>

<!-- beginning of processing -->

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="MyElement">
    <xsl:value-of select="@No"/>
    <xsl:text>: </xsl:text>
    <xsl:value-of select="."/>
    <xsl:call-template name="NL"/>
</xsl:template>

</xsl:stylesheet>
Copy code to clipboard

In this case, the output file would be as follows:

13: Some text
14: Some more text
Copy code to clipboard

Additional Examples

InterSystems IRIS provides the following additional examples:

Customizing the Error Handling

When an error occurs, either XSLT processor (Xalan or Saxon) executes the error() method of the current error handler, sending a message as an argument to that method. Similarly, when a fatal error or warning occurs, the XSLT processor executes the fatalError() or warning() method, as appropriate.

For all three of these methods, the default behavior is to write the message to the current device.

To customize the error handling, you do the following:

  1. For either the Xalan or the Saxon processor, create a subclass of %XML.XSLT.ErrorHandler. In this subclass, implement the error(), fatalError(), and warning() methods as needed.

    Each of these methods accepts a single argument, a string that contains the message sent by the XSLT processor.

    These methods do not return values.

  2. Then:

    • To use this error handler when compiling a stylesheet, create an instance of your subclass and use it in the argument list when you compile the stylesheet. See “Creating a Compiled Stylesheet.”

    • To use this error handler when performing an XSLT transform, create an instance of your subclass and use it in the argument list of the transform method you use. See “Performing an XSLT Transform.”

Specifying Parameters for Use by the Stylesheet

To specify parameters for use by the stylesheet:

  1. Create an instance of %ArrayOfDataTypes.

  2. Call the SetAt() method of this instance to add parameters and their values to this instance. For SetAt(), specify the first argument as the parameter value and the second argument as the parameter name.

    Add as many parameters as needed.

    For example:

        Set tParameters=##class(%ArrayOfDataTypes).%New()
        Set tSC=tParameters.SetAt(1,"myparameter")
        Set tSC=tParameters.SetAt(2,"anotherparameter")
    
    Copy code to clipboard
  3. Use this instance as the pParms argument of the transform method.

Instead of an %ArrayOfDataTypes, you can use an InterSystems IRIS multidimensional array, which can have any number of nodes with following structure and value:

Node Value
arrayname("parameter_name") Value of the parameter named by parameter_name

Adding and Using XSLT Extension Functions

You can create XSLT extension functions in InterSystems IRIS and then use them within your stylesheet, as follows:

  • For XSLT 2.0 (the Saxon processor), you can use the evaluate function in the namespace com.intersystems.xsltgateway.XSLTGateway or the evaluate function in the namespace http://extension-functions.intersystems.com

  • For XSLT 1.0 (the Xalan processor), you can only use the evaluate function in the namespace http://extension-functions.intersystems.com

By default (and as an example), the latter function reverses the characters that it receives. Typically, however, the default behavior is not used, because you implement some other behavior. To simulate multiple separate functions, you pass a selector as the first argument and implement a switch that uses that value to choose the processing to perform.

Internally, the evaluate function is implemented as a method (evaluate()) in the XSLT callback handler.

To add and use XSLT extension functions, do the following:

  1. For either the Xalan or the Saxon processor, create a subclass of %XML.XSLT.CallbackHandler. In this subclass, implement the evaluate() method as needed. See the following subsection.

  2. In the style sheet, declare the namespace to which the evaluate function belongs and use the evaluate function as needed. See the following subsection.

  3. When performing an XSLT transform, create an instance of your subclass and use it in the argument list of the transform method you use. See “Performing an XSLT Transform.”

Implementing the evaluate() Method

Internally, the code that calls the XSLT processor can pass any number of positional arguments to the evaluate() method of the current callback handler, which receives them as an array that has the following structure:

Node Value
Args Number of arguments
Args(index) Value of the argument in the position index

The method has a single return value. The return value can be either:

  • A scalar variable (such as a string or number).

  • A stream object. This allows you to return an extremely long string, one that exceeds the string length limit. The stream has to be wrapped in an instance of %XML.XSLT.StreamAdapter which enables the XSLT processor to read the stream. The following shows a partial example:

    Method evaluate(Args...) As %String
    {
     //create stream
     ///...
    
     // create instance of %XML.XSLT.StreamAdapter to
     // contain the stream
     Set return=##class(%XML.XSLT.StreamAdapter).%New(tStream)
    
     Quit return
    
    }
    Copy code to clipboard

Using evaluate in a Stylesheet

To use XSLT extension functions in an XSLT, you must declare the namespace of the extension functions in the XSLT stylesheet. For the InterSystems evaluate function, this namespace is http://extension-functions.intersystems.com or com.intersystems.xsltgateway.XSLTGateway, as discussed previously.

The following example shows a style sheet that uses evaluate:

<?xml version="1.0"?>

<xsl:stylesheet 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
xmlns:isc="http://extension-functions.intersystems.com">

  <xsl:output method="xml" indent="yes"/>
 
  <xsl:template match="//@* | //node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/s1/s2/s3">
  <xsl:apply-templates select="@*"/>
  <xsl:choose>
  <xsl:when test="function-available('isc:evaluate')">
  <xsl:copy>
  <xsl:value-of select="isc:evaluate(.)" disable-output-escaping="yes"/>
  </xsl:copy>
  </xsl:when>
  <xsl:otherwise>
  <xsl:value-of select="."/>
  </xsl:otherwise>
  </xsl:choose>
  </xsl:template> 

</xsl:stylesheet>
Copy code to clipboard

For a closer look at this example, see the source code for the Example3() method of %XML.XSLT.Transformer.

Working with the isc:evaluate Cache

The XSLT 2.0 gateway caches evaluate function calls in the isc:evaluate cache. The default maximum size of the cache is 1000 items, but you can set the size to a different value. Also, you can clear the cache, you can dump the cache, and you can pre-populate the cache from a %List with the following format:

  • Total number of cache entries

  • For each entry:

    1. Total number of evaluate arguments

    2. All evaluate arguments

    3. Evaluate value

The cache also includes a filter list of function names that can be cached. Note the following:

  • Function names can be added to or removed from the filter list.

  • The filter list can be cleared.

  • The filter list can be overridden by setting a boolean that will cache every evaluate call.

Adding a function name to the filter list does not limit the size of the evaluate cache. There may be any number of calls to the same function, but with different arguments and return values. Each combination of function name and arguments is a separate entry in the evaluate cache.

You can use methods from the %XML.XSLT2.Transformer class to manipulate the evaluate cache. For details, see the class reference.

Using the XSL Transform Wizard

Studio provides a wizard that performs an XSLT transformation, which is useful when you want to quickly test a style sheet or your custom XSLT extension functions. To use this schema wizard:

  1. Select Tools > Add-Ins > XSLT Schema Wizard.

  2. Specify the following required details:

    • For XML File, select Browse to select the XML file to transform.

    • For XSL File, select Browse to select the XSL style sheet to use.

    • For Render As, select either Text or XML to control how the transformation is displayed.

  3. If you have created a subclass of %XML.XSLT.CallbackHandler that you want to use in this transformation, specify the following details:

    • For the first drop-down list in XSLT Helper Class, select a namespace.

    • For the second drop-down list in XSLT Helper Class, select that class.

    See “Adding and Using XSLT Extension Functions,” earlier in this chapter.

  4. Select Finish.

    The bottom of the dialog box displays the transformed file. You can copy and paste from this area.

  5. To close this dialog box, select Cancel.