title: I want to improve performance of xslt
body: <p>I have a framework that generates the XML, based on the HTTP request and the current session state.  I may test in HTML, but production output will be VXML - perhaps one or two "flavors" for different reasons.</p>
  
  <p>Here's the slow part of my HttpServlet:</p>
  
  <pre><code>jsp InputStream ms = new java.io.ByteArrayInputStream(sb.toString().getBytes());
  Source xmlSource = new javax.xml.transform.stream.StreamSource(ms);
  String filePath = getServletContext().getRealPath(("/GetNextEvent-").
          concat(req.getSession().getAttribute("client").toString().toUpperCase()).concat(".xsl"));
  Source xsltSource = new javax.xml.transform.stream.StreamSource(filePath);
  Result result = new javax.xml.transform.stream.StreamResult(resp.getWriter());
  TransformerFactory tf = TransformerFactory.newInstance();
  Transformer t = tf.newTransformer(xsltSource);
  t.transform(xmlSource, result);
  </code></pre>
  
  <p>This currently takes ~ 200ms.  I'd like for it to be much quicker.  Perhaps &lt; 10ms?</p>
  
  <ol>
  <li>Suggestions for caching? - seeing that the xsl files stay the same throughout the deployment, the Transformer objects can be cached indefinitely.  I'm thinking of caching it in the Session level, so each session (1000's simultaneous) has their own.  Any suggestions?  Should I use any frameworks for caching, for any reason?  </li>
  <li>Is there a faster way to transform the xml to the response stream?</li>
  <li>Should I scrap this and go another route?  If you noticed the sb.toString, I am using a StringBuilder to get the XML representation of the objects (objects use a stringbuilder to create XML string).  It takes about 1 millisecond to create the XML document using the StringBuilders, so I'm not concerned about it at the moment.</li>
  </ol>
  
  <p>Edit:</p>
  
  <p>Here's the XSL document.  The XML document is usually very small.  Just a couple of elements.  XML sample is below XSL:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
  &lt;xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:regexp="http://exslt.org/regular-expressions"
      xmlns:str="http://exslt.org/strings" xmlns:twc="http://twc.com/2009/01/ivr/framework"
      exclude-result-prefixes="twc regexp str" extension-element-prefixes="str"&gt;
      &lt;xsl:output method="xml" encoding="ISO-8859-1" /&gt;
      &lt;xsl:template match="/"&gt;
          &lt;vxml xmlns="http://www.w3.org/2001/vxml" version="2.1" xml:lang="en-US"
              application="root.xml"&gt;
              &lt;xsl:attribute name="xml:lang"&gt;&lt;xsl:value-of
                  select="//twc:response/@language" /&gt;&lt;/xsl:attribute&gt;
              &lt;form id="ivrFramework"&gt;
                  &lt;var name="logDebug"&gt;
                      &lt;xsl:attribute name="expr"&gt;&lt;xsl:value-of
                          select="//twc:response/@debug" /&gt;&lt;/xsl:attribute&gt;
                  &lt;/var&gt;
                  &lt;var name="event" expr="'OK'" /&gt;
                  &lt;var name="lastResult" expr="''" /&gt;
                  &lt;var name="lastResultMode" expr="''" /&gt;
                  &lt;var name="lastResultValue" expr="''" /&gt;
                  &lt;var name="srConfidence" expr="'1000'" /&gt;
  
                  &lt;xsl:apply-templates select="//twc:command" /&gt;
                  &lt;xsl:if test="count(//twc:command)=0"&gt;
                      &lt;block&gt;
                          &lt;log cond="logDebug" expr="'No more commands.  Exiting.'" /&gt;
                          &lt;exit /&gt;
                      &lt;/block&gt;
                  &lt;/xsl:if&gt;
              &lt;/form&gt;
          &lt;/vxml&gt;
      &lt;/xsl:template&gt;
  
      &lt;xsl:template
          match="twc:command[@type='prompt' and contains(text(), 'TransferDialog')]"&gt;
          &lt;transfer name="quicktransfer"  type="consultation"&gt;
              &lt;xsl:attribute name="destexpr"&gt;&lt;xsl:choose&gt;
                  &lt;xsl:when test="//twc:parameter[twc:name='destination']"&gt;'&lt;xsl:value-of
                  select="//twc:parameter[twc:name='destination']/twc:value" /&gt;'&lt;/xsl:when&gt;
                  &lt;xsl:otherwise&gt;'tel:1136300'&lt;/xsl:otherwise&gt;
              &lt;/xsl:choose&gt;
              &lt;/xsl:attribute&gt;
              &lt;xsl:if test="//twc:parameter[twc:name='initial']"&gt;
                  &lt;prompt&gt;
                      &lt;xsl:call-template name="process_prompt"&gt;
                          &lt;xsl:with-param name="prompt_type" select="'initial'" /&gt;
                      &lt;/xsl:call-template&gt;
                  &lt;/prompt&gt;
              &lt;/xsl:if&gt;
          &lt;/transfer&gt;
      &lt;/xsl:template&gt;
  
      &lt;xsl:template
          match="twc:command[@type='prompt' and contains(text(), 'BasicDialog')]"&gt;
          &lt;xsl:choose&gt;
              &lt;xsl:when test="//twc:parameter[twc:name='grammar']/twc:value"&gt;
                  &lt;field&gt;
                      &lt;xsl:attribute name="name"&gt;&lt;xsl:value-of
                          select="//twc:parameter[twc:name='variable']/twc:value" /&gt;&lt;/xsl:attribute&gt;
                      &lt;noinput count="3"&gt;
                          &lt;assign name="event" expr="'noinput'" /&gt;
                          &lt;submit next="GetNextEvent2.jsp"
                              namelist="event lastResult lastResultMode lastResultValue srConfidence" /&gt;
                      &lt;/noinput&gt;
                      &lt;nomatch count="3"&gt;
                          &lt;assign name="event" expr="'invalid'" /&gt;
                          &lt;submit next="GetNextEvent2.jsp"
                              namelist="event lastResult lastResultMode lastResultValue srConfidence" /&gt;
                      &lt;/nomatch&gt;
  
                      &lt;xsl:for-each select="//twc:parameter[twc:name='grammar']/twc:value"&gt;
                          &lt;grammar&gt;
                              &lt;xsl:attribute name="src"&gt;&lt;xsl:if test="//twc:response/@base!=''"&gt;&lt;xsl:value-of select="//twc:response/@base" /&gt;&lt;/xsl:if&gt;&lt;xsl:value-of
                                  select="." /&gt;&lt;/xsl:attribute&gt;
                          &lt;/grammar&gt;
                      &lt;/xsl:for-each&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='help']"&gt;
                          &lt;help&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'help'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/help&gt;
                      &lt;/xsl:if&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='noinput1']"&gt;
                          &lt;noinput count="1"&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'noinput1'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/noinput&gt;
                      &lt;/xsl:if&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='noinput2']"&gt;
                          &lt;noinput count="2"&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'noinput2'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/noinput&gt;
                      &lt;/xsl:if&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='invalid1']"&gt;
                          &lt;nomatch count="1"&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'invalid1'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/nomatch&gt;
                      &lt;/xsl:if&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='invalid2']"&gt;
                          &lt;nomatch count="2"&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'invalid2'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/nomatch&gt;
                      &lt;/xsl:if&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='initial']"&gt;
                          &lt;prompt&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'initial'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/prompt&gt;
                      &lt;/xsl:if&gt;
                      &lt;filled&gt;
                          &lt;log cond="logDebug" expr="'Filled.'" /&gt;
                          &lt;assign name="event" expr="'OK'" /&gt;
                          &lt;assign name="lastResult" expr="application.lastresult$.utterance" /&gt;
                          &lt;assign name="lastResultMode" expr="application.lastresult$.inputmode" /&gt;
                          &lt;assign name="lastResultValue" expr="application.lastresult$.interpretation" /&gt;
                          &lt;assign name="srConfidence" expr="application.lastresult$.confidence " /&gt;
                          &lt;submit next="GetNextEvent2.jsp"
                              namelist="event lastResult lastResultMode lastResultValue srConfidence" /&gt;
                      &lt;/filled&gt;
  
                  &lt;/field&gt;
              &lt;/xsl:when&gt;
              &lt;xsl:when test="//twc:parameter[twc:name='initial']/twc:value"&gt;
                  &lt;block&gt;
                      &lt;xsl:if test="//twc:parameter[twc:name='initial']"&gt;
                          &lt;prompt&gt;
                              &lt;xsl:call-template name="process_prompt"&gt;
                                  &lt;xsl:with-param name="prompt_type" select="'initial'" /&gt;
                              &lt;/xsl:call-template&gt;
                          &lt;/prompt&gt;
                      &lt;/xsl:if&gt;
                      &lt;submit next="GetNextEvent2.jsp"
                          namelist="event lastResult lastResultMode lastResultValue srConfidence" /&gt;
                  &lt;/block&gt;
              &lt;/xsl:when&gt;
              &lt;xsl:otherwise&gt;
                  &lt;block&gt;
                      &lt;log cond="logDebug" expr="'Didn't find values for grammar or initial.  Exiting.'" /&gt;
                      &lt;exit /&gt;
                  &lt;/block&gt;
              &lt;/xsl:otherwise&gt;
          &lt;/xsl:choose&gt;
      &lt;/xsl:template&gt;
  
      &lt;xsl:template name="process_prompt"&gt;
          &lt;xsl:param name="prompt_type" /&gt;
          &lt;xsl:for-each select="//twc:parameter[twc:name=$prompt_type]/twc:value"&gt;
              &lt;xsl:if test="contains(., '::')"&gt;
                  &lt;audio&gt;
                      &lt;xsl:for-each select="str:split(., '::')"&gt;
                          &lt;xsl:if test="position()=1"&gt;
                              &lt;xsl:attribute name="src"&gt;&lt;xsl:if test="//twc:response/@base!=''"&gt;&lt;xsl:value-of select="//twc:response/@base" /&gt;&lt;/xsl:if&gt;&lt;xsl:value-of
                                  select="." /&gt;&lt;/xsl:attribute&gt;
                          &lt;/xsl:if&gt;
                          &lt;xsl:if test="position()=2"&gt;
                              &lt;xsl:value-of select="." /&gt;
                          &lt;/xsl:if&gt;
                      &lt;/xsl:for-each&gt;
                  &lt;/audio&gt;
              &lt;/xsl:if&gt;
              &lt;xsl:if test="contains(., 'Date:')"&gt;
                  &lt;say-as interpret-as="date" format="ymd"&gt;
                      &lt;xsl:for-each select="str:split(., ':')"&gt;
                          &lt;xsl:if test="position()=2"&gt;
                              &lt;xsl:value-of select="." /&gt;
                          &lt;/xsl:if&gt;
                      &lt;/xsl:for-each&gt;
                  &lt;/say-as&gt;
              &lt;/xsl:if&gt;
          &lt;/xsl:for-each&gt;
      &lt;/xsl:template&gt;
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>Here's some XML:</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;response xmlns="http://twc.com/2009/01/ivr/framework" language="en-us" debug="true"
      base="/IVRFrameworkResources/Outage/"&gt;
      &lt;command type="prompt"&gt; BasicDialog &lt;parameter&gt;
              &lt;name&gt;initial&lt;/name&gt;
              &lt;value&gt;en-us/prompts/OutageCleared.wav::Hello.  I'm letting you know the
                  incident that caused your outage has been fixed. &lt;/value&gt;
          &lt;/parameter&gt;
      &lt;/command&gt;
  &lt;/response&gt;
  </code></pre>