1

假设我有两个函数,一个简单的,一个复杂的,我绑定到全局变量:

<xsl:variable name="a" select="eg:quick-func()"/>
<xsl:variable name="b" select="e.g.:very-long-func()"/>

如果 $a 为真,我想避免计算 $b,以避免大量处理时间。在测试以下三个选项(Saxon 9)时,我发现即使 $a 为真,也会计算 $b。

<xsl:copy-of select="if ($a) then $a else $b"/>

<xsl:copy-of select="($a,$b)[1]"/>

<xsl:choose>
  <xsl:when test="$a">
    <xsl:copy-of select="$a"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:copy-of select="$b"/>
  </xsl:otherwise>
</xsl:choose>

有解决办法吗?

4

2 回答 2

1

我已经测试了样式表

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs"
  version="2.0">

<xsl:function name="mf:f1" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="bar"/>
  <xsl:message select="'f1 called'"/>
  <xsl:sequence select="$input//foo[bar = $bar]"/>
</xsl:function>

<xsl:function name="mf:f2" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="baz"/>
  <xsl:message select="'f2 called'"/>
  <xsl:sequence select="$input//foo[baz = $baz]"/>
</xsl:function>

<xsl:variable name="a" select="mf:f1(/, 'bar 1')"/>
<xsl:variable name="b" select="mf:f2(/, 'baz 1')"/>

<xsl:template match="/">
  <xsl:sequence select="if ($a) then $a else $b"/>
</xsl:template>

</xsl:stylesheet>

与输入

<root>
  <foo>
    <bar>bar 1</bar>
    <baz>baz a</baz>
  </foo>
  <foo>
    <bar>bar 2</bar>
    <baz>baz 1</baz>
  </foo>
</root>

使用 Saxon 9.6 HE,输出为

f1 called
<?xml version="1.0" encoding="UTF-8"?><foo>
    <bar>bar 1</bar>
    <baz>baz a</baz>
  </foo>

使用样式表

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs"
  version="2.0">

<xsl:function name="mf:f1" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="bar"/>
  <xsl:message select="'f1 called'"/>
  <xsl:sequence select="$input//foo[bar = $bar]"/>
</xsl:function>

<xsl:function name="mf:f2" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="baz"/>
  <xsl:message select="'f2 called'"/>
  <xsl:sequence select="$input//foo[baz = $baz]"/>
</xsl:function>

<xsl:variable name="a" select="mf:f1(/, 'bar 1')"/>
<xsl:variable name="b" select="mf:f2(/, 'baz 1')"/>

<xsl:template match="/">
  <xsl:sequence select="if ($b) then $b else $a"/>
</xsl:template>

</xsl:stylesheet>

输出是

f2 called
<?xml version="1.0" encoding="UTF-8"?><foo>
    <bar>bar 2</bar>
    <baz>baz 1</baz>
  </foo>

当我将代码更改为

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs"
  version="2.0">

<xsl:function name="mf:f1" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="bar"/>
  <xsl:message select="'f1 called'"/>
  <xsl:sequence select="$input//foo[bar = $bar]"/>
</xsl:function>

<xsl:function name="mf:f2" as="node()*">
  <xsl:param name="input"/>
  <xsl:param name="baz"/>
  <xsl:message select="'f2 called'"/>
  <xsl:sequence select="$input//foo[baz = $baz]"/>
</xsl:function>

<xsl:variable name="a" select="mf:f1(/, 'bar x')"/>
<xsl:variable name="b" select="mf:f2(/, 'baz 1')"/>

<xsl:template match="/">
  <xsl:sequence select="if ($a) then $a else $b"/>
</xsl:template>

</xsl:stylesheet>

然后调用这两个函数:

f1 called
f2 called
<?xml version="1.0" encoding="UTF-8"?><foo>
    <bar>bar 2</bar>
    <baz>baz 1</baz>
  </foo>
于 2015-08-18T17:29:03.860 回答
0

一种方法是制作 a 和 b 备忘录函数而不是全局变量:

<function name="f:a" saxon:memo-function="yes">
 <xsl:sequence select="eg:quick-func()"/>
</function>
于 2015-08-19T07:20:37.697 回答