1

我是 XSLT 的新手,我在使用以下 for-each 语句时遇到了一些速度问题。我希望有人能给我一些关于如何优化这个的建议吗?

下面的 for-each 循环通过大约 4mb 的 XML。它正在测试以确保每个酒店节点都有描述和目的地。它还在测试每家酒店的评分是否大于 2 但不是 6。XML 中评分的可能值为 0、1、2、3、4、5 或 6。理想情况下,我希望它只选择评分3、4或5,忽略其他。

<for-each select="response/results/hotel[
    not(@description = '') and
    @rating &gt; '2' and
    not(@rating = '6') and
    not(@destination = '')              ]">
  <call-template name="hotelparams"/>
  <call-template name="upropdata"/>
  <call-template name="request"/>
  <call-template name="Newline"/>
</for-each>

作为请求,我添加了下面调用的模板。输出是创建制表符分隔的文本文件,然后将其导入 mySQL。顺便说一下,请忽略 upropdata 模板,它很快就会被删除...

<xsl:template name="hotelparams">
<xsl:value-of select="@itemcode"/><xsl:value-of select="$tab"/>
<xsl:value-of  select="@cheapestcurrency"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@cheapestprice"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@checkin"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@checkout"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@description"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destair"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destination"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destinationid"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@engine"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@hotelname"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@image"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@nights"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@rating"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@resultkey"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@resultno"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@supplierdestination"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@type"/></xsl:template>

<xsl:template name="upropdata">
<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>2011-01-01</xsl:template>

<xsl:template name="request">
<xsl:for-each select="/response/request/method"><xsl:value-of select="$tab"/><xsl:value-of select="./@sessionkey"/></xsl:for-each></xsl:template>
<xsl:template name="Newline">
<xsl:text>&#13;</xsl:text></xsl:template>
4

2 回答 2

0

怎么样 ...

<xsl:for-each select="response/results/hotel
      [not(@description = '')]
      [@rating = (3,4,5)]">
  <xsl:call-template name="hotelparams"/>
  <xsl:call-template name="upropdata"/>
  <xsl:call-template name="request"/>
  <xsl:call-template name="Newline"/>
</xsl:for-each>

注意:我没有包括目的地检查,因为您没有指定其节点名称。

另外,如果你能消除空描述属性的可能性(也就是说酒店将有一个非空描述或根本没有描述属性),那么你可以使用这种稍微缩写的形式......

<xsl:for-each select="response/results/hotel
      [not(@description)]
      [@rating = (3,4,5)]">
  <xsl:call-template name="hotelparams"/>
  etc...
</xsl:for-each>

另请注意,第二个谓词的另一种形式是...

      [@rating = (3 to 5)]

一个人可以写...

      [(@rating &gt; 2) and (@rating &lt; 6)]

或者

      [@rating &gt; 2][@rating &lt; 6]

...但我怀疑这会降低效率,因为 @rating 必须被提取两次。

于 2012-08-15T12:12:28.007 回答
0

下面的 for-each 循环通过大约 4mb 的 XML。它正在测试以确保每个酒店节点都有描述和目的地。它还在测试每家酒店的评分是否大于 2 但不是 6。XML 中评分的可能值为 0、1、2、3、4、5 或 6。理想情况下,我希望它只选择评分3、4或5,忽略其他。

<for-each select="response/results/hotel[
    not(@description = '') and
    @rating &gt; '2' and
    not(@rating = '6') and
    not(@destination = '')              ]">
  <call-template name="hotelparams"/>
  <call-template name="upropdata"/>
  <call-template name="request"/>
  <call-template name="Newline"/>
</for-each>

我相信性能问题的原因在于被调用的模板(问题中没有提供)——而不是模板xsl:for-each本身。

它可以用不同的替代方式重写,但性能提升将是最小的(毫秒),如果有的话。

请注意,提供的代码根本不检查@destination属性的存在。任何hotel满足其他条件但没有destination属性的元素都会选中。

description属性也是如此。

指定的一种正确方法xsl:for-each

<xsl:for-each select="response/results/hotel[
     string(@description)
    and
     @rating > 2
    and
     not(@rating > 5)
    and
     string(@destination)
    ]">
  <xsl:call-template name="hotelparams"/>
  <xsl:call-template name="upropdata"/>
  <xsl:call-template name="request"/>
  <xsl:call-template name="Newline"/>
</xsl:for-each>

更新

OP 现在已经提供了被调用模板的代码。

我将使用以下hotelparams模板:

<xsl:sequence select=
 "string-join
  (
   (@itemcode,
    @cheapestcurrency,
    @cheapestprice,
    @checkin,
    @checkout,
    @description,
    @destair,
    @destination,
    @destinationid,
    @engine,
    @hotelname,
    @image,
    @nights,
    @rating,
    @resultkey,
    @resultno,
    @supplierdestination,
    @type),
   $tab
  )
 "/>

我会将模板替换为upropdata

这段代码:

 <xsl:sequence select="'&#9;\N&#9;\N&#9;\N&#9;\N&#9;\N2011-01-01'"/>

或者,如果$tab真的可以不同于&#9;,我将只计算一次并将结果放入全局变量中:

<xsl:variable name="vUPropData" select=
"concat($tab,'\N',$tab,'\N',$tab,'\N'$tab,'\N',$tab,'\N2011-01-01')"/>

然后只需:

 <xsl:sequence select="$vUPropData"/>

我会将request模板替换为:

这段代码:

<xsl:sequence select=
  "concat($tab,string-join(/response/request/method/@sessionkey, $tab))"/>

由于这不依赖于任何上下文节点(是一个绝对表达式),我将只计算一次并将其放入一个全局变量中(如前一种情况)并且只引用这个全局变量。

最后,在命名模板中生成相同的单个字符是没有意义的。我将用Newline全局变量或全局参数替换模板。

我相信在这次重构之后,代码可能会执行得更快

于 2012-08-15T13:03:37.900 回答