使用多个<xsl:when> </xsl:when> </xsl:choose>优化<xsl:choose>

时间:2010-07-12 23:28:02

标签: optimization xslt

我有一系列中等大小的XML文档,主要是带有几个代表要扩展的宏的节点的文本,例如:

<foo>Some text <macro>A1</macro> ... <macro>B2</macro> ...etc...</foo>

我的目标是用相应的XML替换每个宏。通常它是一个具有不同属性的<img>标记,但它也可能是其他一些HTML。

样式表是以编程方式生成的,其中一种方法是为每个宏创建一个模板,例如

<xsl:template match="macro[.='A1']">
    <!-- content goes here -->
</xsl:template>
<xsl:template match="macro[.='A2']">
    <!-- other content goes here -->
</xsl:template>
<xsl:template match="macro[.='B2']">
    <!-- etc... -->
</xsl:template>

它工作得很好,但它可以有多达一百个宏并且它不是很高效(我使用的是libxslt。)我尝试了几个替代方案,例如:

<xsl:template match="macro">
    <xsl:choose>
        <xsl:when test=".='A1'">
            <!-- content goes here -->
        </xsl:when>
        <xsl:when test=".='A2'">
            <!-- other content goes here -->
        </xsl:when>
        <xsl:when test=".='B2'">
            <!-- etc... -->
        </xsl:when>
    </xsl:choose>
</xsl:template>

性能略高一些。我尝试添加另一级分支,例如:

<xsl:template match="macro">
    <xsl:choose>
        <xsl:when test="substring(.,1,1) = 'A'">
            <xsl:choose>
                <xsl:when test=".='A1'">
                    <!-- content goes here -->
                </xsl:when>
                <xsl:when test=".='A2'">
                    <!-- other content goes here -->
                </xsl:when>
            </xsl:choose>
        </xsl:when>
        <xsl:when test=".='B2'">
            <!-- etc... -->
        </xsl:when>
    </xsl:choose>
</xsl:template>

加载速度稍慢(XSL更大,更复杂)但执行速度稍快(每个分支可以消除几种情况。)

现在我想知道,有没有更好的方法呢?我有大约50-100个宏。通常,转换是使用libxslt执行的,但我不能使用其他XSLT引擎的专有扩展。

欢迎任何输入:)

3 个答案:

答案 0 :(得分:1)

如果您的宏是固定的XML,那么您可以使用macros.xml文档:

<?xml version="1.0"?>
<macros>
    <macro name="A1"><!-- content goes here --></macro>
    <macro name="A2"><!-- content goes here --></macro>
</macros>

然后你可以:

<xsl:template match="macro">
    <xsl:variable name="name" select="text()"/>
    <xsl:apply-templates select="document(macros.xml)/macros/macro[@name=$name]" mode="copy"/>
</xsl:template>

<xsl:template match="*" mode="copy">
    <xsl:copy><xsl:copy-of select="*"/>
        <xsl:apply-templates mode="copy"/>
    </xsl:copy>
</xsl:template>

这会改善表现吗?

答案 1 :(得分:1)

尝试将所有macro处理提取到单独的模板模式,并仅针对macro元素的内容运行它。即:

<xsl:template match="macro">
   <xsl:apply-templates mode="macro"/>
</xsl:template>

<xsl:temlate match="text()[. = 'A1']" mode="macro">
   ...
</xsl:template>

我怀疑你的情况减慢是因为你的规则会逐一检查输入中的每个节点。通过这种方式,您可以检查一下它是否为macro,并且只有在内容得到进一步匹配时才会进行检查。

答案 2 :(得分:1)

这将是另一种方式:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
    <xsl:variable name="dummy">
            <mac id="A1">success</mac>
            <mac id="A2">fail</mac>
            <mac id="B1">This <b>fail</b></mac>
            <mac id="B2">This <b>success</b></mac>
    </xsl:variable>
    <xsl:key name="macro" match="mac" use="@id"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="macro">
        <xsl:variable name="me" select="."/>
        <xsl:for-each select="document('')">
            <xsl:copy-of select="key('macro',$me)/node()"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

注意:这是性能:XML解析1,805ms,XSL解析0,483ms,转换0,215ms