我是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 > '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> </xsl:text></xsl:template>
答案 0 :(得分: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 > 2) and (@rating < 6)]
或
[@rating > 2][@rating < 6]
...但我怀疑这样效率会降低,因为@rating必须被提取两次。
答案 1 :(得分: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 > '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="'	\N	\N	\N	\N	\N2011-01-01'"/>
或者,如果$tab
确实可能与	
不同,我只计算一次并将结果放在一个全局变量中:
<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
模板。
我相信在重构之后,代码可能会执行得更快。