我想提高xslt的性能

时间:2010-02-20 15:37:51

标签: java jsp xslt

我有一个基于HTTP请求和当前会话状态生成XML的框架。我可以用HTML进行测试,但是生产输出将是VXML - 可能出于不同的原因,可能只有一两种“风味”。

这是我的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);

目前需要约200毫秒。我希望它更快。也许< 10ms的?

  1. 缓存的建议? - 在整个部署过程中看到xsl文件保持不变,可以无限期地缓存Transformer对象。我正在考虑在会话级别缓存它,因此每个会话(1000个同时)都有自己的会话。有什么建议?我应该出于任何原因使用任何框架进行缓存吗?
  2. 是否有更快的方法将xml转换为响应流?
  3. 我应该废弃这个并走另一条路吗?如果您注意到了sb.toString,我使用StringBuilder来获取对象的XML表示(对象使用stringbuilder来创建XML字符串)。使用StringBuilders创建XML文档大约需要1毫秒,所以我现在不关心它。
  4. 编辑:

    这是XSL文档。 XML文档通常非常小。只是几个元素。 XML示例低于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>
    

    这是一些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>
    

3 个答案:

答案 0 :(得分:12)

如果不了解XSLT或了解XML和XSLT的大小/复杂程度,很难诊断性能问题。

您可能需要支付解析文件(XSLT或XML)的费用和/或您可能拥有效率非常低的XSLT样式表。

例如:

  1. 许多// XPATH语句,如果不需要,会损害非常大的XML文件的性能。
  2. 逻辑隐藏在模板中,可以移动到模板@match条件中,这为XSLT引擎提供了优化的机会。
  3. 您可以使用XSLT分析器来查看XSLT中的瓶颈所在。例如,oXygen有一个非常好的debugger/profileralt text alt text

    如果您将多次运行XSLT,那么您应该cache the transformer object 。这样,您只需支付加载和实例化一次的成本并重复使用多次。

    例如,将XSLT Template对象的实例化移动到您的服务器小程序init()

     TransformerFactory transFact = TransformerFactory.newInstance();
     Templates cachedXSLT = transFact.newTemplates(xsltSource);
    

    然后执行转换的位置,使用缓存的TransformerFactory obj:

    Transformer t= cachedXSLT.newTransformer();
    t.transform(xmlSource, result);
    

答案 1 :(得分:5)

即使使用缓存,性能不可接受的原因通常在XSLT代码本身 - 您根本没有显示。

根据我的经验,有些情况下,我能够以这样的方式更改低效的XSLT实现,使其加速数千次。

作者经常使用O(N ^ 2)算法,或者更糟糕的是,当存在O(N)或甚至O(log(N))算法时。

向我们指定要解决的问题并提供解决它的XSLT代码。然后,某人可能会为您提供性能更佳的解决方案

答案 2 :(得分:-1)

我遇到了一些将XSLT文件转换为java解析代码的工具,但现在找不到任何引用。很抱歉答案不全,但我也很有兴趣找到它。