Reputation: 611
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.
Here's the slow part of my HttpServlet:
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);
This currently takes ~ 200ms. I'd like for it to be much quicker. Perhaps < 10ms?
Edit:
Here's the XSL document. The XML document is usually very small. Just a couple of elements. XML sample is below XSL:
<?xml version="1.0" encoding="UTF-8" ?>
<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">
<xsl:output method="xml" encoding="ISO-8859-1" />
<xsl:template match="/">
<vxml xmlns="http://www.w3.org/2001/vxml" version="2.1" xml:lang="en-US"
application="root.xml">
<xsl:attribute name="xml:lang"><xsl:value-of
select="//twc:response/@language" /></xsl:attribute>
<form id="ivrFramework">
<var name="logDebug">
<xsl:attribute name="expr"><xsl:value-of
select="//twc:response/@debug" /></xsl:attribute>
</var>
<var name="event" expr="'OK'" />
<var name="lastResult" expr="''" />
<var name="lastResultMode" expr="''" />
<var name="lastResultValue" expr="''" />
<var name="srConfidence" expr="'1000'" />
<xsl:apply-templates select="//twc:command" />
<xsl:if test="count(//twc:command)=0">
<block>
<log cond="logDebug" expr="'No more commands. Exiting.'" />
<exit />
</block>
</xsl:if>
</form>
</vxml>
</xsl:template>
<xsl:template
match="twc:command[@type='prompt' and contains(text(), 'TransferDialog')]">
<transfer name="quicktransfer" type="consultation">
<xsl:attribute name="destexpr"><xsl:choose>
<xsl:when test="//twc:parameter[twc:name='destination']">'<xsl:value-of
select="//twc:parameter[twc:name='destination']/twc:value" />'</xsl:when>
<xsl:otherwise>'tel:1136300'</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="//twc:parameter[twc:name='initial']">
<prompt>
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'initial'" />
</xsl:call-template>
</prompt>
</xsl:if>
</transfer>
</xsl:template>
<xsl:template
match="twc:command[@type='prompt' and contains(text(), 'BasicDialog')]">
<xsl:choose>
<xsl:when test="//twc:parameter[twc:name='grammar']/twc:value">
<field>
<xsl:attribute name="name"><xsl:value-of
select="//twc:parameter[twc:name='variable']/twc:value" /></xsl:attribute>
<noinput count="3">
<assign name="event" expr="'noinput'" />
<submit next="GetNextEvent2.jsp"
namelist="event lastResult lastResultMode lastResultValue srConfidence" />
</noinput>
<nomatch count="3">
<assign name="event" expr="'invalid'" />
<submit next="GetNextEvent2.jsp"
namelist="event lastResult lastResultMode lastResultValue srConfidence" />
</nomatch>
<xsl:for-each select="//twc:parameter[twc:name='grammar']/twc:value">
<grammar>
<xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of
select="." /></xsl:attribute>
</grammar>
</xsl:for-each>
<xsl:if test="//twc:parameter[twc:name='help']">
<help>
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'help'" />
</xsl:call-template>
</help>
</xsl:if>
<xsl:if test="//twc:parameter[twc:name='noinput1']">
<noinput count="1">
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'noinput1'" />
</xsl:call-template>
</noinput>
</xsl:if>
<xsl:if test="//twc:parameter[twc:name='noinput2']">
<noinput count="2">
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'noinput2'" />
</xsl:call-template>
</noinput>
</xsl:if>
<xsl:if test="//twc:parameter[twc:name='invalid1']">
<nomatch count="1">
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'invalid1'" />
</xsl:call-template>
</nomatch>
</xsl:if>
<xsl:if test="//twc:parameter[twc:name='invalid2']">
<nomatch count="2">
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'invalid2'" />
</xsl:call-template>
</nomatch>
</xsl:if>
<xsl:if test="//twc:parameter[twc:name='initial']">
<prompt>
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'initial'" />
</xsl:call-template>
</prompt>
</xsl:if>
<filled>
<log cond="logDebug" expr="'Filled.'" />
<assign name="event" expr="'OK'" />
<assign name="lastResult" expr="application.lastresult$.utterance" />
<assign name="lastResultMode" expr="application.lastresult$.inputmode" />
<assign name="lastResultValue" expr="application.lastresult$.interpretation" />
<assign name="srConfidence" expr="application.lastresult$.confidence " />
<submit next="GetNextEvent2.jsp"
namelist="event lastResult lastResultMode lastResultValue srConfidence" />
</filled>
</field>
</xsl:when>
<xsl:when test="//twc:parameter[twc:name='initial']/twc:value">
<block>
<xsl:if test="//twc:parameter[twc:name='initial']">
<prompt>
<xsl:call-template name="process_prompt">
<xsl:with-param name="prompt_type" select="'initial'" />
</xsl:call-template>
</prompt>
</xsl:if>
<submit next="GetNextEvent2.jsp"
namelist="event lastResult lastResultMode lastResultValue srConfidence" />
</block>
</xsl:when>
<xsl:otherwise>
<block>
<log cond="logDebug" expr="'Didn't find values for grammar or initial. Exiting.'" />
<exit />
</block>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="process_prompt">
<xsl:param name="prompt_type" />
<xsl:for-each select="//twc:parameter[twc:name=$prompt_type]/twc:value">
<xsl:if test="contains(., '::')">
<audio>
<xsl:for-each select="str:split(., '::')">
<xsl:if test="position()=1">
<xsl:attribute name="src"><xsl:if test="//twc:response/@base!=''"><xsl:value-of select="//twc:response/@base" /></xsl:if><xsl:value-of
select="." /></xsl:attribute>
</xsl:if>
<xsl:if test="position()=2">
<xsl:value-of select="." />
</xsl:if>
</xsl:for-each>
</audio>
</xsl:if>
<xsl:if test="contains(., 'Date:')">
<say-as interpret-as="date" format="ymd">
<xsl:for-each select="str:split(., ':')">
<xsl:if test="position()=2">
<xsl:value-of select="." />
</xsl:if>
</xsl:for-each>
</say-as>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here's some XML:
<?xml version="1.0"?>
<response xmlns="http://twc.com/2009/01/ivr/framework" language="en-us" debug="true"
base="/IVRFrameworkResources/Outage/">
<command type="prompt"> BasicDialog <parameter>
<name>initial</name>
<value>en-us/prompts/OutageCleared.wav::Hello. I'm letting you know the
incident that caused your outage has been fixed. </value>
</parameter>
</command>
</response>
Upvotes: 10
Views: 10773
Reputation: 66783
It is difficult to diagnose performance issues without seeing the XSLT or knowing how large/complex the XML and XSLT are.
You could be paying the cost of parsing the file(s), either the XSLT or the XML and/or you could have a very inefficient XSLT stylesheet.
For instance:
//
XPATH statements, which if not needed can hurt performance for very large XML files.@match
criteria, which provides the opportunity for XSLT engines to optimize.There are XSLT profilers that you can use to see where the bottlenecks are in your XSLT. For instance, oXygen has a very nice debugger/profiler:
If you will be running the XSLT many times, then you should cache the transformer object . That way, you only pay the cost to load and instantiate it once and re-use many times.
For instance, move the instantiation of your XSLT Template
object into your severlet init()
TransformerFactory transFact = TransformerFactory.newInstance();
Templates cachedXSLT = transFact.newTemplates(xsltSource);
and then where you perform the transform, use the cached TransformerFactory
obj:
Transformer t= cachedXSLT.newTransformer();
t.transform(xmlSource, result);
Upvotes: 13
Reputation: 243529
Even with caching, the reason for unacceptable performance is often in the XSLT code itself -- which you haven't shown at all.
In my experience there have been cases when I was able to change an inefficient XSLT implementation in such a way that it was speeded up thousands of times.
Quite often the author implements an O(N^2) algorithm or worse, when an O(N) or even O(log(N)) algorithms exist.
Specify to us the problem being solved and provide the XSLT code that solves it. Then it might be possible for someone to give you a better performing solution.
Upvotes: 6