如何加快XSLT处理时间

时间:2017-09-13 02:24:30

标签: xml xslt

我目前正在使用XSLT文件将XML文件(许多标记语言)传输到另一个XML文件(纯文本)。处理时间太长。

我想这是因为我在另一个for-each中使用了for-each,如下所示: element&attribute

<xsl:for-each select="/data/row">
  <xsl:variable name="ROW_">
    <xsl:value-of select="count(./preceding-sibling::*) + 1"/>
  </xsl:variable>
  <xsl:for-each select='/Header/*[starts-with (text(), 'Car')] '>
    <xsl:variable name="COLUMN_">
      <xsl:value-of select="count(./preceding-sibling::*) + 1"/>
    </xsl:variable>
    <xsl:value-of select="/data/row[position()=$ROW_]/@*[position()=$COLUMN_]"/>
    <xsl:value-of select ="$Delimiter"/>
  </xsl:for-each>
</xsl:for-each>

那么我该怎样做才能缩短处理时间呢?

1 个答案:

答案 0 :(得分:7)

此代码中存在许多低效率,我将从小代码开始。

<强> ONE

  <xsl:variable name="ROW_">
    <xsl:value-of select="count(./preceding-sibling::*) + 1"/>
  </xsl:variable>

除非您真的想要创建临时XML树结构,否则切勿使用包含xsl:value-of的xsl:变量。编写

效率更高
<xsl:variable name="ROW_" select="count(./preceding-sibling::*) + 1"/>

按照自己的方式行事,计算整数值(带count()),将其转换为字符串,将字符串转换为文本节点,创建文档节点,并将文本节点附加到文件节点;当您在谓词[position()=$ROW_]中使用变量时,您通过查找并连接其所有文本节点并将结果转换为整数来获取文档节点的字符串值。首先将变量绑定到整数更好!

<强> TWO

<xsl:for-each select='/Header/*[starts-with (text(), 'Car')] '>

这出现在外部xsl:for-each中,因此它重复执行,但/Header/*[starts-with (text(), 'Car')]的结果每次都相同,它不依赖于循环中的任何内容。智能优化器会将表达式移出循环(这不是一件容易的事,因为它依赖于识别&#34; /&#34;每次都会选择相同的根节点,这只是真的,因为外部for-each选择单文档节点集)。而不是依赖优化器那么聪明,将表达式/Header/*[starts-with (text(), 'Car')]绑定到变量。

<强>三

<xsl:value-of select="/data/row[position()=$ROW_]/@*[position()=$COLUMN_]"/>

这可能是关键的:在处理所有行的循环中,你有一个处理所有行的循环,所以你立刻得到了O(n ^ 2)性能:输入大小加倍,并且执行时间增加了四倍。

同样,像Saxon-EE中那样的智能优化器可能会对此进行排序(构造就像是SQL中的连接,并且连接的优化是一种成熟的艺术)。但是如果你使用的是开源处理器,那么它的优化器很可能不那么聪明,所以你必须手动优化它,这根本不难做到:它看起来很难我好像你正在选择的行将是外部for-each当前正在处理的行。

<强> FOUR

@*[position()=$COLUMN_]

您在这里遇到了问题,而且这不是性能问题。您依赖于以特定顺序交付的属性(与相应的HEADER元素的顺序相同),并且这是不安全的。你根本不能依赖属性的顺序,因此你将不得不在这里找到一些控制输出顺序的方法。

忽略该问题,我认为您的代码会缩减为:

<xsl:variable name="headers" 
    select='/Header/*[starts-with (text(), 'Car')] '/>
<xsl:for-each select="/data/row">
  <xsl:variable name="thisRow" select="."/>
  <xsl:for-each select='$headers'>
    <xsl:variable name="COLUMN_" 
         select="count(./preceding-sibling::*) + 1"/>
    <xsl:value-of select="$thisRow/@*[position()=$COLUMN_]"/>
    <xsl:value-of select ="$Delimiter"/>
  </xsl:for-each>
</xsl:for-each>

(变量名末尾的下划线的意义是什么?这种不必要的混淆让我感到非常烦恼......)