首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用xquery在xml节点上执行四种算术运算

如何使用xquery在xml节点上执行四种算术运算
EN

Stack Overflow用户
提问于 2021-10-25 03:14:43
回答 2查看 58关注 0票数 0
代码语言:javascript
运行
复制
<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

EN

回答 2

Stack Overflow用户

发布于 2021-10-25 07:54:54

这是高阶函数的一个很好的用例:

代码语言:javascript
运行
复制
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解决了这个问题,正是这个问题和解决方案让我相信了将函数视为一级对象的价值。

票数 2
EN

Stack Overflow用户

发布于 2021-10-25 05:55:20

下面是一个可由来自Saxonica的SaxonCS运行的XSLT4示例:

代码语言:javascript
运行
复制
<?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:

代码语言:javascript
运行
复制
<?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)可能是这样的

代码语言:javascript
运行
复制
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)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69702495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档