xslt 2.0 xsl:number递归计数器-更有效的方法?

时间:2018-06-29 00:11:05

标签: xslt xslt-2.0

我想用递增的计数器值填充名称为“ order”的所有属性/值元素。

...
<attribute>
    <name>order</name>
    <value></value>
</attribute>
...

“订单”属性可以出现在文档中的任何位置,任何深度。订单值不必准确无误,但是文档中每个较低的订单属性必须具有比所有先前的订单属性更高的值。

我正在使用多遍处理。第一遍生成内容,第二遍通过计数器值填充value标签。计数代码如下:

<xsl:template match="node() | @*" mode="postprocess">   
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" mode="postprocess" />
    </xsl:copy>
</xsl:template>
<xsl:template match="*[self::n:value and parent::n:attribute[n:name = 'order']]" mode="postprocess">        
    <value>
        <xsl:number level="any" count="*"/>
    </value>
</xsl:template> 

此方法有效,但表现不佳。我正在处理相对较大的文件-大约20MB-上面的计数代码使我的处理时间增加了大约50%。

我在这里找到了类似的问题: high-performance alternative to xsl:number 但是对我来说没有好的答案。

有更好的方法吗?

我正在使用Saxon HE 9.7.0。

3 个答案:

答案 0 :(得分:1)

这是另一种方法,尽管我不知道它是否会提高性能。

首先,创建一个变量,该变量可以有效地用于将value元素映射到其位置

<xsl:variable name="attributes">
    <xsl:for-each select="//n:attribute[n:name = 'order']/n:value">
        <n:value key="{generate-id()}" pos="{position()}" />
    </xsl:for-each>
</xsl:variable>

然后,创建一个密钥以查找这些值

<xsl:key name="attributes" match="n:value" use="@key" />

然后,不使用xsl:number,而是这样获得职位:

<xsl:value-of select="key('attributes', generate-id(), $attributes)/@pos" />

例如,给定此XML

<root xmlns="n">
<attribute>
    <name>order</name>
    <value></value>
</attribute>
<attribute>
    <name>order</name>
    <value></value>
</attribute>
<children>
    <attribute>
        <name>order</name>
        <value></value>
    </attribute>
</children>
</root>

这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:n="n" exclude-result-prefixes="n">

<xsl:key name="attributes" match="n:value" use="@key" />

<xsl:variable name="attributes">
    <xsl:for-each select="//n:attribute[n:name = 'order']/n:value">
        <n:value key="{generate-id()}" pos="{position()}" />
    </xsl:for-each>
</xsl:variable>

<xsl:template match="node() | @*">   
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
</xsl:template>

<xsl:template match="n:attribute[n:name = 'order']/n:value">
    <value xmlns="n">
        <xsl:value-of select="key('attributes', generate-id(), $attributes)/@pos" />
    </value>
</xsl:template> 
</xsl:stylesheet>

结果是这样的:

<attribute>
    <name>order</name>
    <value>1</value>
</attribute>
<attribute>
    <name>order</name>
    <value>2</value>
</attribute>
<children>
    <attribute>
        <name>order</name>
        <value>3</value>
    </attribute>
</children>
</root>

答案 1 :(得分:1)

您可以使用此代码,可能会帮助您:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xpath-default-namespace="n"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output method="xml" indent="yes" />

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

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="value[../name = 'order']">
        <xsl:copy>
            <xsl:value-of select="count(preceding::value[../name = 'order'])+1"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:0)

您可以重写或更改模板的匹配模式以及计数模式,以尝试是否提高性能:

<xsl:template match="n:attribute[n:name = 'order']/n:value" mode="postprocess">        
    <value>
        <xsl:number level="any" count="n:attribute[n:name = 'order']/n:value"/>
    </value>
</xsl:template> 

您的评论表明这些更改为您提高了性能,因此我将其发布为答案。