<Expression>
<description/>
<minus>
<plus>
<int value="2"/>
<int value="3"/>
<times>
<int value="5"/>
<minus>
<int value="6"/>
<int value="3"/>
</minus>
</times>
</plus>
<int value="4"/>
</minus>
</Expression>
我想要获得这样的表达式并输出结果:(2+3+(6-3)*5)-4=16
发布于 2021-10-25 07:54:54
这是高阶函数的一个很好的用例:
declare variable $evaluators := map {
'int' : function($e){xs:integer($e/@value)},
'plus' : function($e){sum($e/*/local:eval(.)},
'minus' : function($e){local:eval($e/*[1] - local:eval($e/*[2])},
'times' : function($e){local:eval($e/*[1] * local:eval($e/*[2])},
...
}
declare function local:eval($e as element(*)) {
$evaluators(name($e))($e)
}
local:eval(Expression/(* except description))
细节取决于您没有与我们分享的规范的一些方面,例如description
是否可以出现在任何地方,times
(像plus
)是否可以接受两个以上的操作数,等等。
致谢:1972年,我看到我已故的朋友兼同事Andrew Birrell (https://cacm.acm.org/news/210689-in-memoriam-andrew-birrell-1951-2016/fulltext)使用Algol 68解决了这个问题,正是这个问题和解决方案让我相信了将函数视为一级对象的价值。
发布于 2021-10-25 05:55:20
下面是一个可由来自Saxonica的SaxonCS运行的XSLT4示例:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="4.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:strip-space elements="*"/>
<xsl:param name="operator-map" as="map(xs:string, xs:string)"
select="map { 'minus' : ' - ',
'plus' : ' + ',
'times' : ' * ' }"/>
<xsl:template match="Expression">
<xsl:variable name="expression">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="result" as="xs:decimal">
<xsl:evaluate xpath="$expression"/>
</xsl:variable>
<xsl:value-of select="$expression, $result" separator=" = "/>
</xsl:template>
<xsl:template match="minus | plus | times">
<xsl:text>(</xsl:text>
<xsl:apply-templates separator="{$operator-map(local-name())}"/>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template match="int[@value]">
<xsl:value-of select="@value"/>
</xsl:template>
</xsl:stylesheet>
或者作为XSLT 3:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:strip-space elements="*"/>
<xsl:param name="operator-map" as="map(xs:string, xs:string)"
select="map { 'minus' : ' - ',
'plus' : ' + ',
'times' : ' * ' }"/>
<xsl:template match="Expression">
<xsl:variable name="expression">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="result" as="xs:decimal">
<xsl:evaluate xpath="$expression"/>
</xsl:variable>
<xsl:value-of select="$expression, $result" separator=" = "/>
</xsl:template>
<xsl:template match="minus | plus | times">
<xsl:if test="position() gt 1"> {$operator-map(local-name(..))} </xsl:if>
<xsl:text>(</xsl:text>
<xsl:apply-templates/>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template match="int[@value]">
<xsl:if test="position() gt 1"> {$operator-map(local-name(..))} </xsl:if>
<xsl:value-of select="@value"/>
</xsl:template>
</xsl:stylesheet>
在XQuery中单独求值(3)可能是这样的
declare function local:evaluate($expression)
{
local:evaluate-operator($expression/(* except description))
};
declare function local:evaluate-operator($operator)
{
typeswitch ($operator)
case element(minus)
return fold-left(tail($operator/*), local:evaluate-operator(head($operator/*)), function($a, $op) { $a - local:evaluate-operator($op) })
case element(plus)
return sum($operator/*!local:evaluate-operator(.))
case element(times)
return fold-left($operator/*, 1, function($a, $op) { $a * local:evaluate-operator($op) })
case element(int)
return xs:integer($operator/@value)
default return ()
};
local:evaluate(Expression)
https://stackoverflow.com/questions/69702495
复制相似问题