C# 是否可以让XSLT将字符串计算为数学函数?它包括+;s和*s

C# 是否可以让XSLT将字符串计算为数学函数?它包括+;s和*s,c#,xml,c#-4.0,xslt,C#,Xml,C# 4.0,Xslt,我正在使用concat动态构建一个XSLT字符串,包括加号和多应用程序符号。即: <xsl:value-of select="concat(' + ', number(@amount))"/> <xsl:value-of select="concat(' * ', number(@gc_own))"/> 可以告诉XSLT计算它吗?也就是说,我有一个字符串-864963*0.0963+269048*0.09+-22052*0.002+18777687*0.2+-132

我正在使用concat动态构建一个XSLT字符串,包括加号和多应用程序符号。即:

<xsl:value-of select="concat(' + ', number(@amount))"/>
<xsl:value-of select="concat(' * ', number(@gc_own))"/>

可以告诉XSLT计算它吗?也就是说,我有一个字符串
-864963*0.0963+269048*0.09+-22052*0.002+18777687*0.2+-132428*0.096+0*0.3+-2813*0.0966+-96*0.25+-1081*0.0001+-456*0.001+53473*0.0044+-580298*0.1
?

我可以让XSLT一次计算所有结果吗?或者我需要将每个值存储为数字变量并将它们相加吗


编辑:我不认为提及运算符优先级很重要

我想你可以这样做:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="string" select="'-864963 * 0.0963 + 269048 * 0.09 + -22052 * 0.002 + 18777687 * 0.2 + -132428 * 0.096 + 0 * 0.3 + -2813 * 0.0966 + -96 * 0.25 + -1081 * 0.0001 + -456 * 0.001 + 53473 * 0.0044 + -580298 * 0.1'" />

<xsl:template match="/">
    <output>
        <xsl:call-template name="calculate">
            <xsl:with-param name="formula" select="concat('+ ', normalize-space($string), ' ')"/>
        </xsl:call-template>
    </output>
</xsl:template>

<xsl:template name="calculate">
    <xsl:param name="formula"/>
    <xsl:param name="result" select="0"/>
    <xsl:choose>
        <xsl:when test="$formula">
            <xsl:variable name="operator" select="substring($formula, 1, 1)" />
            <xsl:variable name="operand" select="substring-before(substring-after($formula, ' '), ' ')" />
            <xsl:variable name="nextFormula" select="substring-after(substring-after($formula, ' '), ' ')" />
            <xsl:variable name="nextResult">
                <xsl:choose>
                    <xsl:when test="$operator = '+'">
                        <xsl:value-of select="$result + $operand"/>
                    </xsl:when>
                    <xsl:when test="$operator = '*'">
                        <xsl:value-of select="$result * $operand"/>
                    </xsl:when>
                </xsl:choose>
            </xsl:variable>
            <!-- recursive call -->
            <xsl:call-template name="calculate">
                <xsl:with-param name="formula" select="$nextFormula"/>
                <xsl:with-param name="result" select="number($nextResult)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$result"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>


编辑 如果只保持此运算符的优先级

作为概念证明,此解决方案依赖于EXSLT来标记字符串,而不是依赖于命名模板。操作顺序如下:

步骤1:获取+符号之间包含的所有表达式
步骤2:将这些表达式中包含的因子相乘
第3步:将结果相加

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="string" select="'-2 * 3 + 4 * 5 + -6 * 7'" />

<xsl:variable name="products">
    <xsl:for-each select="str:tokenize(translate($string, ' ', ''), '+')" >
        <xsl:call-template name="multiply">
            <xsl:with-param name="factors" select="str:tokenize(., '*')"/>
        </xsl:call-template>
    </xsl:for-each>
</xsl:variable>

<xsl:template match="/">
    <output>
        <xsl:value-of select="sum(exsl:node-set($products)/product)"/>
    </output>
</xsl:template>

<xsl:template name="multiply">
    <xsl:param name="factors"/>
    <xsl:param name="result" select="1"/>
    <xsl:choose>
        <xsl:when test="count($factors)">
            <xsl:call-template name="multiply">
                <xsl:with-param name="factors" select="$factors[position() > 1]"/>
                <xsl:with-param name="result" select="$result * $factors[1]"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <product><xsl:value-of select="$result"/></product>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>


假设表达式的语义与XPath语义相同,则可以使用处理器中可用的任何xx:evaluate()扩展。有些处理器支持这种扩展函数,Saxon支持XSLT 3.0 xsl:evaluate指令。

既然可以生成结果,为什么还要生成字符串?或者两者都有,如果你想要一个“计算器纸带”类型的结果。我想,这个解决方案假设没有运算符优先级?谁知道真正的要求是什么…@MichaelKay是的,这是非常正确的。我假设给定的字符串是一系列计算器按键,可以这么说。但我现在看到,它也可以理解为一系列乘法相加。如果只有该操作员维护,则将标记为应答precedence@Hoppe我想您可以在+符号上标记,将内容相乘,然后将标记相加。不过,我不确定这是否值得,我怀疑上游可以找到更好的解决方案。编辑是一个有效的例子吗?我似乎无法让它在VisualStudio的xsl引擎XMLSpy中运行,或者通过c#执行xsl来运行,我将使用什么语法?我不确定xx是什么。指许多处理器在其自己的命名空间中实现了某种evaluate()扩展。如果您告诉我们您使用的是什么XSLT处理器,那么我们可以更具体一些。我使用的是c#4.0的System.Xml.Xsl.XslTransform.Xsl.Transform()方法。看起来它只支持XSLT1.0规范。这能给你提供信息吗?我不是那个处理器的专家。据我所知,它不提供xx:evaluate扩展,但它可能允许您编写自己的扩展。在.NET环境中,可以使用提供XSLT 3.0 xsl:evaluate指令的Saxon。