我想提高xslt的性能

eri*_*icp 9 java xslt jsp

我有一个框架,可以根据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);
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

这是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>
Run Code Online (Sandbox Code Playgroud)

这是一些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>
Run Code Online (Sandbox Code Playgroud)

Mad*_*sen 12

如果没有看到XSLT或知道XML和XSLT有多大/多复杂,就很难诊断性能问题.

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

例如:

  1. 许多//XPATH语句,如果不需要,可能会损害非常大的XML文件的性能.
  2. 逻辑埋藏在模板中,可以移动到模板@match标准中,这为XSLT引擎提供了优化的机会.

您可以使用XSLT分析器来查看XSLT中的瓶颈所在.例如,oXygen有一个非常好的调试器/分析器: 替代文字 替代文字

如果您将多次运行XSLT,那么您应该缓存转换器对象.这样,您只需支付加载和实例化一次并重复使用多次的成本.

例如,将XSLT Template对象的实例化移动到您的severlet中init()

 TransformerFactory transFact = TransformerFactory.newInstance();
 Templates cachedXSLT = transFact.newTemplates(xsltSource);
Run Code Online (Sandbox Code Playgroud)

然后在执行转换的位置使用缓存的TransformerFactoryobj:

Transformer t= cachedXSLT.newTransformer();
t.transform(xmlSource, result);
Run Code Online (Sandbox Code Playgroud)

  • 使用模板+1.如果使用Xalan作为XSLT转换器,请尝试使用编译样式表的XSLTC版本,并且速度更快.请参阅http://xml.apache.org/xalan-j/xsltc_usage.html#api如果使用Xalan我会检查使用的DOM,在某些情况下,TinyTree比普通的Java DOM有一些主要优势(结果可能会有所不同,但是TinyTree的内存使用情况要好得多. (3认同)

Dim*_*hev 5

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

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

当存在O(N)或甚至O(log(N))算法时,作者通常实现O(N ^ 2)算法或更糟.

向我们指定要解决的问题并提供解决它的XSLT代码.那么有人可能会给你一个更好的解决方案.