我需要一个信息来优化我的xslt。
在我的模板中,我多次访问一个孩子,例如:
<xsl:template match="user">
<h1><xsl:value-of select="address/country"/></h1>
<p><xsl:value-of select="address/country"/></p>
<p><xsl:value-of select="address/country"/></p>
... more and more...
<p><xsl:value-of select="address/country"/></p>
</xsl:template>
将子元素的内容存储在变量中并直接调用变量以避免每次都解析树是否更好:
<xsl:template match="user">
<xsl:variable name="country" select="address/country"/>
<h1><xsl:value-of select="$country"/></h1>
<p><xsl:value-of select="$country"/></p>
<p><xsl:value-of select="$country"/></p>
... more and more...
<p><xsl:value-of select="$country"/></p>
</xsl:template>
或者,使用变量会比多次解析树消耗更多资源吗?
答案 0 :(得分:4)
通常,XML文件作为一个整体进行解析,并作为XDM保存在内存中。所以,我想通过
多次解析树
您实际上是指多次访问XML输入的内部表示。下图说明了这一点,我们讨论的是源代码树:
(摘自Michael Kay的 XSLT 2.0和XPath 2.0程序员参考,第43页)
同样,xsl:variable
创建一个节点(或者更确切地说,一个临时文档),该节点保存在内存中并且也需要访问。
现在,您的优化究竟是什么意思?你的意思是执行转换或CPU和内存使用所花费的时间(正如你在问题中提到“资源”)?
此外,性能取决于您的XSLT处理器的实现。找到答案的唯一可靠方法是实际测试。
编写两个仅在这方面不同的样式表,也就是说,它们是相同的。然后,让它们转换相同的输入XML并测量它们所花费的时间。
我的猜测是,访问变量更快,重复变量名称比编写代码时重复完整路径更方便(这有时称为“便利变量”)。
编辑:替换为更恰当的内容,作为对您评论的回复。
如果您真的对此进行了测试,请编写两个样式表:
带变量的样式表
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:variable name="var" select="node/subnode"/>
<subnode nr="1">
<xsl:value-of select="$var"/>
</subnode>
<subnode nr="2">
<xsl:value-of select="$var"/>
</subnode>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
没有变量的样式表
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<subnode nr="1">
<xsl:value-of select="node/subnode"/>
</subnode>
<subnode nr="2">
<xsl:value-of select="node/subnode"/>
</subnode>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于以下输入XML:
<root>
<node>
<subnode>helloworld</subnode>
</node>
</root>
编辑:正如@Michael Kay建议的那样,我测量了100次运行所需的平均时间(“-t和-repeat:Saxon命令行上的100”):
with variable: 9 ms
without variable: 9 ms
这并不意味着结果与您的XSLT处理器相同。
答案 1 :(得分:2)
对于所有表现问题,答案是:它取决于。
这取决于您使用的是哪种XSLT处理器,以及它所执行的优化。
很可能取决于需要搜索多少孩子才能找到您要找的孩子。
找出答案的唯一方法是测量它,并非常仔细地测量它。
就个人而言,如果涉及复杂的谓词,我会使用变量,但如果我只是按姓名寻找孩子,则不会。
几乎在所有情况下,即使它有所作为,也不太可能对您业务的底线产生影响。如果您有兴趣提高业务的底线,那么可能有更好的方法来运用您的智慧。
答案 2 :(得分:1)
编辑:受邀重新评估我的答案,我了解到您自己的建议可能非常适合您的目标。除非您将变量的selection
值封装在其他单引号中[使其成为字符串常量],否则它将包含所选元素。 [如果您愿意,您甚至可以使用 <xsl:copy-of select="$country"/>
复制所选元素的整个子树,而不是插入所述元素的文本内容。]
对于更少重复的源,为什么不为相关元素应用自己的模板:
<xsl:apply-template select="address/country"/>
[...]
<xsl:template match="address/country">
<h1><xsl:value-of select="."/></h1>
<p><xsl:value-of select="."/></p>
[...]
</xsl:template>
就像@Mathias_Müllersuggested一样,还有一些方法可以表达你的' ...越来越多...... '的行为,而不必复制'n'有关线路和过度。 XSLT 2.0解释for-each
语句中的数值范围:
<xsl:for-each select="1 to 100">
<p><xsl:value-of select="."/></p>
</xsl:for-each>
如果版本&gt; = 2.0中没有XSLT,稍微复杂一点的解决方案是在传递参数并实现分而治之call-template显式调用模板>接近[以保护堆栈]:
<xsl:call-template name="ntimes">
<xsl:with-param name="counter" select="100"/>
</xsl:call-template>
[...]
<xsl:template name="ntimes">
<xsl:param name="counter" select="0"/>
<xsl:if test="$counter > 0">
<xsl:choose>
<xsl:when test="$counter = 1">
<xsl:apply-template select="address/country"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="half" select="floor($counter div 2)"/>
<xsl:call-template name="ntimes">
<xsl:with-param name="counter" select="$half"/>
</xsl:call-template>
<xsl:call-template name="ntimes">
<xsl:with-param name="counter" select="$counter - $half"/>
</xsl:call-template>
[...]
老实说,我对XSLT中的性能和优化一无所知。考虑到大多数时候我使用的是用Java编写的XSLT处理器,并且它有什么用途可以获得很好的输入文件,而我仍然是一个完整的,几百MB的RAM消耗JVM来启动,我从来没有认为值得付出努力。向上..?