[an error occurred while processing this directive]
> developer > web app development
XSLT Performance Considerations
by Mike Foley, Quality Assurance, Novell
Date Created: 2001-05-09 17:52:00.000
  Introduction
  Overview
  Performance Implications
  Doctor, Doctor...
  Tips to Improve XSLT Performance
introduction
XML is becoming ubiquitous. If you look at J2EE, web services, B2B, or ePortals, you're almost sure to see XML. And along with the popularity of XML comes XSL-the ability to transform XML documents into something else, be it HTML or another XML document. However, XSL transformations can be a performance pitfall. This document takes a look at XSL transformations from a performance perspective with an intended goal of increasing your understanding of the performance implications.
overview
Let's start by looking at how the transformation works. An XSL transformation contains the following pieces:
  1. an XML document containing some data;
  2. an XSL stylesheet containing formatting information;
  3. an XSLT processor;
  4. and the resulting XML or HTML document.



Following is an example of an XML file:


<?xml version = "1.0"?>



<menu>

<entree>

	<item>Soup</item>

	<item>Prawn cocktail</item>

	<item>Garlic mushroom</item>

	<item>Pate and toast</item>

	<item>Melon</item>

</entree>

<main-course>

	<item>Duck</item>

	<item>Steak</item>

	<item>Lamb cutlets</item>

	<item>Pheasant</item>

	<item>Sea bass</item>

</main-course>

<desert>

	<item>Spotted dick</item>

	<item>Sorbet</item>

	<item>Ice cream</item>

	<item>Gateau</item>

	<item>Banana split</item>

	<item>Basils Sticky-Pudding Special</item>

</desert>

</menu>



A sample XSL file is as follows:


<?xml version = "1.0"?>

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

<xsl:template match = "/">

<HTML>

<HEAD>

<TITLE>Menu Example</TITLE>

</HEAD>

<BODY>

<P><font size="6" face="Comic Sans MS">Fawlty Towers </font></P>

<P align="center">

	<font size="4" face="Haettenschweiler">Gourmet Menu for Tonight</font></P>

<table border="0" width="100%" cellpadding="4">

  <tr>

    <td width="24%" align = "right" valign="top">

    		<font face="Monotype Corsiva" size="4">Starters</font></td>

    <td width="76%" align = "left">

         <xsl:apply-templates select = "*/entree/item"/>

         <P/>

    </td>

   </tr>

   <tr>

    <td width="24%" align = "right" valign="top">

    		<font face="Monotype Corsiva" size="4">Main Course</font></td>

    <td width="76%" align = "left">

         <xsl:apply-templates select = "*/main-course/item"/>

         <P/>

    </td>

    </tr>

    <tr>

    <td width="34%" align = "right" valign="top">

    		<font face="Monotype Corsiva" size="4">Desert</font></td>

    <td width="76%" align = "left">

          <xsl:apply-templates select = "*/desert/item"/>

          <P/>

      </td>

    </tr>

</table>

</BODY>

</HTML>

</xsl:template>

<xsl:template match = "item">

		<font face="Arial"><xsl:value-of select = "."/></font><BR/>

</xsl:template>

</xsl:stylesheet>



The XML file is transformed using the following code:


            XSLTProcessor processor = XSLTProcessorFactory.getProcessor(new XercesLiaison());

            XSLTInputSource xmlSource = new XSLTInputSource(xml);

            XSLTInputSource xslSheet = new XSLTInputSource(xsl);

            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();

            XSLTResultTarget xmlResult = new XSLTResultTarget(byteOut);

            processor.process(xmlSource, xslSheet, xmlResult);

performance implications
For a single XSL transformation, thousands of objects are created. Not only do these objects need to be created, but they also need to be garbage collected, which is a time-consuming process. The following OptimizeIt screenshot illustrates the object instantiation involved in a single XSL transformation:



The call stacks to perform the transformation can be rather deep, as the following screen shot from JProbe shows:



These object instantiations and deep call stacks are the makings of a performance pitfall. What's more, if you perform your XSL transformations in the context of a web application server, then the problem can be downright troublesome. In a web application server context, instead of creating thousands of new objects, you could potentially create hundreds of thousands of new objects (# of users * thousands of objects), and you could have hundreds of CPU-hungry threads nibbling away at your CPU capacity. Ouch!

With Xalan 1.1, the performance problem can be even worse. In addition to the aforementioned performance issues, there can be synchronization issues blocking XSLT throughput. Take a look at this portion of a call stack of XSL transformation occurring in the context of the SilverStream Application Server as it performs many XSL transformations:


"client23" (TID:0x3ac5a08, sys_thread_t:0x15210a70, state:MW, native ID:0xeb)

prio=5

        at java.util.Vector.elementAt(Vector.java, Compiled Code)

        at org.apache.xalan.xslt.ElemLiteralResult.execute(ElemLiteralResult.java, Compile

d Code)

        at org.apache.xalan.xslt.ElemTemplateElement.executeChildren(ElemTemplateElement.j

ava, Compiled Code)

        at org.apache.xalan.xslt.ElemTemplate.execute(ElemTemplate.java, Compiled Code)

        at org.apache.xalan.xslt.StylesheetRoot.process(StylesheetRoot.java, Compiled Code

)

        at org.apache.xalan.xslt.XSLTEngineImpl.process(XSLTEngineImpl.java, Compiled Code

)



Notice the thread state, MW, which stands for Monitor Wait. The thread is waiting on the synchronized java.util.Vector object. Xalan 1.1 doesn't seem to scale that well, and seems to have some synchronization issues.
doctor, doctor...
With synchronization issues and CPU-intensive characteristics, you might initially think this is something to be avoided. To a certain extent, that's understandable. It reminds me of the story of the guy who goes to a doctor and says "Doctor, it hurts when I do this...", and the doctor replies "Then don't do that." Certainly, if you don't perform XSL transformations at all, then you will avoid this potential performance pitfall. But there are ways to effectively deal with this situation in a high-performance environment.
tips to improve XSLT performance
  • The first tip is an intelligent variation on avoiding XSLT performance. With the SilverStream ePortal, caching of the generated document greatly reduces the number of times this expensive operation needs to be performed.
  • Setting large initial and max heap sizes for the JVM greatly reduces the performance impact of the object instantiation. For example, try starting the SilverStream server with the JVM options, Xms500m or Xmx2000m.
  • Clean up your XSL. The XSL controls the transformation process, and innocuous tags may have significant performance implications. Instead consider the following suggestions:
    • More clearly specify nodes, as follows: <xsl:value-of select="//ACTIVATELINK"/> should be <xsl:value-of select="/MANUALS/ACTIVATELINK"/>. This will tell the XSLT processor not to follow non-productive branches.
    • Eliminate unnecessary for-each tags, <xsl:for-each select= ...>. Sometimes you can get the intended result, but in an unnecessarily expensive way.
    • Try condensing and reducing the number of nodes by moving sub-nodes up to their parents' as attributes. For example,



		   <a>

                <xsl:attribute name="href">

                        <xsl:value-of select="HREFVALUE"/>

                </xsl:attribute>

                <xsl:attribute name="onmouseover">

                        popUp('ABel<xsl:value-of select="MENUNAME"/>',event)

                </xsl:attribute>

                <xsl:attribute name="onmouseout">

                        popDown('ABel<xsl:value-of select="MENUNAME"/>')

                </xsl:attribute>

                <xsl:value-of select="DISPLAYVALUE"/>

        </a>



Should be written like this:


        <a href="{HREFVALUE}" onmouseover="popUp('ABel{MENUNAME}',event)"

onmouseout="popDown('ABel{MENUNAME}')">

                <xsl:value-of select="DISPLAYVALUE"/>

        </a>

  • Switch to the Xalan 2.01, which seems to address many of the synchronization issues.
  • Finally, some additional performance tips from www.apache.org are as follows:
    • Don't use "//" (descendant axes) patterns near the root of a large document.
    • Use xsl:key elements and the key() function as an efficient way to retrieve node sets.
    • Where possible, use pattern matching rather than xsl:if or xsl:when statements.
    • Use compiled stylesheets for multiple transformations.
    • For the ultimate in server-side scalability, perform transform operations on the client.