【问题标题】:Improving the performance of XSL提高 XSL 的性能
【发布时间】:2011-02-19 04:47:09
【问题描述】:

我正在使用下面的 XSL 2.0 代码来查找包含我作为输入提供的索引列表的文本节点的 ID。该代码运行良好,但就性能而言,大型文件需要很长时间。即使对于大文件,如果索引值很小,那么结果在几毫秒内很快。我正在使用 saxon9he Java 处理器来执行 XSL。

<xsl:variable name="insert-data" as="element(data)*"> 
  <xsl:for-each-group 
    select="doc($insert-file)/insert-data/data" 
    group-by="xsd:integer(@index)"> 
    <xsl:sort select="current-grouping-key()"/> 
    <data 
      index="{current-grouping-key()}" 
      text-id="{generate-id(
        $main-root/descendant::text()[
          sum((preceding::text(), .)/string-length(.)) ge current-grouping-key()
        ][1]
      )}"> 
      <xsl:copy-of select="current-group()/node()"/> 
    </data> 
  </xsl:for-each-group> 
</xsl:variable> 

在上述解决方案中,如果索引值太大,例如 270962,则 XSL 执行所需的时间为 83427 毫秒。在大文件中,如果索引值很大,例如 4605415、4605431,则需要几分钟才能执行。似乎变量“插入数据”的计算需要时间,尽管它是一个全局变量并且只计算一次。应该添加 XSL 还是处理器?如何提高 XSL 的性能。

【问题讨论】:

    标签: xslt-2.0 saxon xslt


    【解决方案1】:

    我猜问题是text-id的生成,即表达式

    生成ID( $主根/后代::text()[ sum((preceding::text(), .)/string-length(.)) ge current-grouping-key() ][1] )

    您可能会在这里重新计算很多总和。我认为这里最简单的方法是颠倒您的方法:递归文档中的文本节点,聚合到目前为止的字符串长度,并在每次到达新的 @index 时输出 data 元素。以下示例说明了该方法。请注意,每个唯一的@index 和每个文本节点仅被访问一次。

    <xsl:variable name="insert-doc" select="doc($insert-file)"/>
    
    <xsl:variable name="insert-data" as="element(data)*"> 
        <xsl:call-template name="calculate-data"/>
    </xsl:variable>
    
    <xsl:key name="index" match="data" use="xsd:integer(@index)"/>
    
    <xsl:template name="calculate-data">
        <xsl:param name="text-nodes" select="$main-root//text()"/>
        <xsl:param name="previous-lengths" select="0"/>
        <xsl:param name="indexes" as="xsd:integer*">
            <xsl:perform-sort 
                select="distinct-values(
                        $insert-doc/insert-data/data/@index/xsd:integer(.))">
                <xsl:sort/>
            </xsl:perform-sort>
        </xsl:param>
        <xsl:if test="$text-nodes">
            <xsl:variable name="total-lengths" 
                select="$previous-lengths + string-length($text-nodes[1])"/>
            <xsl:choose>
                <xsl:when test="$total-lengths ge number($indexes[1])">
                    <data 
                        index="{$indexes[1]}" 
                        text-id="{generate-id($text-nodes[1])}">
                        <xsl:copy-of select="key('index', $indexes[1], 
                                                 $insert-doc)"/> 
                    </data>
                    <!-- Recursively move to the next index. -->
                    <xsl:call-template name="calculate-data">
                        <xsl:with-param
                            name="text-nodes"
                            select="$text-nodes"/>
                        <xsl:with-param
                            name="previous-lengths" 
                            select="$previous-lengths"/>
                        <xsl:with-param
                            name="indexes" 
                            select="subsequence($indexes, 2)"/>
                    </xsl:call-template>                    
                </xsl:when>
                <xsl:otherwise>
                    <!-- Recursively move to the text node. -->
                    <xsl:call-template name="calculate-data">
                        <xsl:with-param 
                            name="text-nodes" 
                            select="subsequence($text-nodes, 2)"/>
                        <xsl:with-param
                            name="previous-lengths" 
                            select="$total-lengths"/>
                        <xsl:with-param 
                            name="indexes" 
                            select="$indexes"/>
                    </xsl:call-template>                    
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>
    

    【讨论】:

    • 太好了,响应在几毫秒内。它已从 82242 减少到 813。非常感谢!!仅“数据”节点的值不会出现在结果中。行: 从中读取,
    • @Rachel:很高兴听到您的响应时间有所改善。我原来的键定义有一个bug,你需要使用&lt;xsl:key name="index" match="data" use="xsd:integer(@index)"/&gt;才能得到正确的结果。
    • 在我的情况下,索引值可能不是唯一的,即 $insert-doc/insert-data/data/@index。在这种情况下,为同一个索引创建了多个数据标签。如何解决?请提供您的意见。
    • @Rachel:使用distinct-values。我编辑了我的答案以使用此功能,请参阅参数indexes 的新定义。实际上,我差不多一个小时前对我的答案进行了更新,但我猜你得到的是旧版本。 :-)
    • @Rachel:没问题。我希望distinct-values 解决了这个问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 2012-03-19
    • 1970-01-01
    • 2014-04-18
    • 2014-01-04
    • 2021-10-31
    • 1970-01-01
    相关资源
    最近更新 更多