2015-08-18 21 views
1

假设我有两个功能,一个简单,一个复杂的,这是我绑定到全局变量:在XSLT/XPath的使用条件,以避免计算

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

我想避免计算$ B,如果$ a真实的,以避免大量的处理时间。在测试下面的三个选项(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> 

是否有解决方法?

+0

请考虑告诉我们具体使用哪个Saxon版本,然后确定函数具有哪种返回类型,以及如何确定计算出“b”。 –

+0

XSLT显然使用懒惰的评估:http://stackoverflow.com/questions/1410057/xsl-does-evaluating-conditional-expressions-shortcut。但它可能不适用于函数,它的返回值分配给一个变量。你是否在'b'的xsl:variable'附近尝试了'if/then' /'xsl:choose'? – CoDEmanX

+0

我读了你的建议,把全局变量变成本地变量,导致失效。你能澄清吗? – jdk

回答

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> 

与撒克逊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> 
+0

我刚才运行了这个,对于你所有的三个样本,我都得到了f1和f2都被调用的消息。我在oXygen 17的Saxon HE/PE/EE 9.6.0.5上运行了这个。我没有看到任何会提示非懒惰评估的oXygen参数。我不确定为什么我们的结果会有所不同。 – jdk

+0

我不知道奥克森撒克逊的详细信息我担心,但我确定他们的支持知道是否要进行调试,或许他们会使用某些特殊设置阻止优化来运行撒克逊。 –

+0

我认为当启用跟踪时,全局变量会被急切地评估,并且oXygen启用跟踪(由调试器在内部使用)。通常,编写依赖懒惰评估的代码并不是一个好主意。 –

0

一种方法是使a和b备忘录功能而不是全局变量:

<function name="f:a" saxon:memo-function="yes"> 
<xsl:sequence select="eg:quick-func()"/> 
</function>