XSLT整数求值器,如何实现n-ary求和乘法?
XSLT integer evaluator, how to implement n-ary sum and multiplication?
我正在尝试实现一个小整数求值器。实际上,它处理的 xml 个文档有一个表达式,以及一个包含可能变量值的 varDef
列表。
XSLT 将该 XML 文档转换为另一个文档以及结果。
这是 XML 文档的 XML 架构:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ej3="http://procesadores.ejemplo.com/Ej3"
targetNamespace="http://procesadores.ejemplo.com/Ej3"
elementFormDefault="qualified">
<element name="documento">
<complexType>
<sequence>
<element ref="ej3:expr"/>
<element ref="ej3:varDef" maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</complexType>
</element>
<element name="expr" abstract="true"/>
<element name="suma" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="resta" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="mult" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="div" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="mod" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="opuesto" type="ej3:expUnaria" substitutionGroup="ej3:expr"/>
<element name="abs" type="ej3:expUnaria" substitutionGroup="ej3:expr"/>
<element name="var" type="ej3:tipoNombreVar" substitutionGroup="ej3:expr"/>
<element name="cons" type="integer" substitutionGroup="ej3:expr"/>
<element name="varDef">
<complexType>
<simpleContent>
<extension base="int">
<attribute name="nombre" type="ej3:tipoNombreVar"/>
</extension>
</simpleContent>
</complexType>
</element>
<complexType name="expUnaria">
<sequence>
<element ref="ej3:expr" minOccurs="1" maxOccurs="1"/>
</sequence>
</complexType>
<complexType name="expBinaria">
<sequence>
<element ref="ej3:expr" minOccurs="2" maxOccurs="2"/>
</sequence>
</complexType>
<complexType name="expNaria">
<sequence>
<element ref="ej3:expr" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<simpleType name="tipoNombreVar">
<restriction base="string">
<pattern value="[a-zA-Z][a-zA-Z0-9]*"/>
</restriction>
</simpleType>
</schema>
这是 XSLT 文档:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ej3="http://procesadores.ejemplo.com/Ej3"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="ej3:*"/>
<xsl:output
method="xml"
indent="yes"
encoding="utf-8"/>
<xsl:key name="defVariables" match="ej3:varDef" use="@nombre"/>
<xsl:template match="/ej3:documento">
<cons><xsl:apply-templates select="*[not(local-name()='varDef')]"/></cons>
</xsl:template>
<xsl:template match="ej3:suma">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 + $s2"/>
</xsl:template>
<xsl:template match="ej3:resta">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 - $s2"/>
</xsl:template>
<xsl:template match="ej3:mult">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 * $s2"/>
</xsl:template>
<xsl:template match="ej3:div">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$s2 = 0">
<xsl:value-of select="$s1 div $s2"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="xs:integer($s1 div $s2)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ej3:mod">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 mod $s2"/>
</xsl:template>
<xsl:template match="ej3:opuesto">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:value-of select="- $s1"/>
</xsl:template>
<xsl:template match="ej3:abs">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:value-of select="abs($s1)"/>
</xsl:template>
<xsl:template match="ej3:var">
<xsl:value-of select="key('defVariables',.)"/>
</xsl:template>
<xsl:template match="ej3:cons">
<test><xsl:value-of select="."/></test>
</xsl:template>
</xsl:stylesheet>
一切如我所料。但我想制作 suma
(sum) 和 mult
n-ary 运算符。也就是说,像这样:
<suma>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
</suma>
应该可以评价。为了让它工作,我必须修改 suma
xsl:template,但我不太清楚该怎么做。我已经尝试了很多东西,但我必须在将它们相加之前以某种方式评估 children,这让我很难找到解决方案。
你能建议如何实现这个目标吗?
请注意,我希望 sum
和 mult
操作数都以这种方式工作,因此基于 xpath 函数 sum()
的解决方案不适用于 mult
.
我会确保您的模板 returns xs:integer
序列,例如变化
<xsl:template match="ej3:cons">
<test><xsl:value-of select="."/></test>
</xsl:template>
至
<xsl:template match="ej3:cons">
<xsl:sequence select="xs:integer(.)"/>
</xsl:template>
那么你可以使用
<xsl:template match="suma">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="sum($operands)"/>
</xsl:template>
对于乘法你可以使用一个函数(需要声明一个前缀 mf
绑定到一些命名空间)
<xsl:function name="mf:multiply" as="xs:integer">
<xsl:param name="operands" as="xs:integer+"/>
<xsl:sequence select="if (not(exists($operands[2])))
then $operands[1]
else $operands[1] * mf:multiply($operands[position() gt 1])"/>
</xsl:function>
然后在
中使用它
<xsl:template match="multa">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="mf:multiply($operands)"/>
</xsl:template>
这是一个例子:
<xsl:stylesheet version="3.0" 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 mf">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:function name="mf:multiply" as="xs:integer">
<xsl:param name="operands" as="xs:integer+"/>
<xsl:sequence select="if (not(exists($operands[2])))
then $operands[1]
else $operands[1] * mf:multiply($operands[position() gt 1])"/>
</xsl:function>
<xsl:template match="expression">
<result>
<xsl:apply-templates/>
</result>
</xsl:template>
<xsl:template match="cons">
<xsl:sequence select="xs:integer(.)"/>
</xsl:template>
<xsl:template match="suma">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="sum($operands)"/>
</xsl:template>
<xsl:template match="multa">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="mf:multiply($operands)"/>
</xsl:template>
</xsl:stylesheet>
示例输入为
<expression>
<suma>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
<multa>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
</multa>
</suma>
</expression>
我得到输出 <result>12</result>
。
我正在尝试实现一个小整数求值器。实际上,它处理的 xml 个文档有一个表达式,以及一个包含可能变量值的 varDef
列表。
XSLT 将该 XML 文档转换为另一个文档以及结果。
这是 XML 文档的 XML 架构:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ej3="http://procesadores.ejemplo.com/Ej3"
targetNamespace="http://procesadores.ejemplo.com/Ej3"
elementFormDefault="qualified">
<element name="documento">
<complexType>
<sequence>
<element ref="ej3:expr"/>
<element ref="ej3:varDef" maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</complexType>
</element>
<element name="expr" abstract="true"/>
<element name="suma" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="resta" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="mult" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="div" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="mod" type="ej3:expBinaria" substitutionGroup="ej3:expr"/>
<element name="opuesto" type="ej3:expUnaria" substitutionGroup="ej3:expr"/>
<element name="abs" type="ej3:expUnaria" substitutionGroup="ej3:expr"/>
<element name="var" type="ej3:tipoNombreVar" substitutionGroup="ej3:expr"/>
<element name="cons" type="integer" substitutionGroup="ej3:expr"/>
<element name="varDef">
<complexType>
<simpleContent>
<extension base="int">
<attribute name="nombre" type="ej3:tipoNombreVar"/>
</extension>
</simpleContent>
</complexType>
</element>
<complexType name="expUnaria">
<sequence>
<element ref="ej3:expr" minOccurs="1" maxOccurs="1"/>
</sequence>
</complexType>
<complexType name="expBinaria">
<sequence>
<element ref="ej3:expr" minOccurs="2" maxOccurs="2"/>
</sequence>
</complexType>
<complexType name="expNaria">
<sequence>
<element ref="ej3:expr" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<simpleType name="tipoNombreVar">
<restriction base="string">
<pattern value="[a-zA-Z][a-zA-Z0-9]*"/>
</restriction>
</simpleType>
</schema>
这是 XSLT 文档:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ej3="http://procesadores.ejemplo.com/Ej3"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="ej3:*"/>
<xsl:output
method="xml"
indent="yes"
encoding="utf-8"/>
<xsl:key name="defVariables" match="ej3:varDef" use="@nombre"/>
<xsl:template match="/ej3:documento">
<cons><xsl:apply-templates select="*[not(local-name()='varDef')]"/></cons>
</xsl:template>
<xsl:template match="ej3:suma">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 + $s2"/>
</xsl:template>
<xsl:template match="ej3:resta">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 - $s2"/>
</xsl:template>
<xsl:template match="ej3:mult">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 * $s2"/>
</xsl:template>
<xsl:template match="ej3:div">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$s2 = 0">
<xsl:value-of select="$s1 div $s2"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="xs:integer($s1 div $s2)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ej3:mod">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:variable name="s2">
<xsl:apply-templates select="child::node()[2]"/>
</xsl:variable>
<xsl:value-of select="$s1 mod $s2"/>
</xsl:template>
<xsl:template match="ej3:opuesto">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:value-of select="- $s1"/>
</xsl:template>
<xsl:template match="ej3:abs">
<xsl:variable name="s1">
<xsl:apply-templates select="child::node()[1]"/>
</xsl:variable>
<xsl:value-of select="abs($s1)"/>
</xsl:template>
<xsl:template match="ej3:var">
<xsl:value-of select="key('defVariables',.)"/>
</xsl:template>
<xsl:template match="ej3:cons">
<test><xsl:value-of select="."/></test>
</xsl:template>
</xsl:stylesheet>
一切如我所料。但我想制作 suma
(sum) 和 mult
n-ary 运算符。也就是说,像这样:
<suma>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
</suma>
应该可以评价。为了让它工作,我必须修改 suma
xsl:template,但我不太清楚该怎么做。我已经尝试了很多东西,但我必须在将它们相加之前以某种方式评估 children,这让我很难找到解决方案。
你能建议如何实现这个目标吗?
请注意,我希望 sum
和 mult
操作数都以这种方式工作,因此基于 xpath 函数 sum()
的解决方案不适用于 mult
.
我会确保您的模板 returns xs:integer
序列,例如变化
<xsl:template match="ej3:cons">
<test><xsl:value-of select="."/></test>
</xsl:template>
至
<xsl:template match="ej3:cons">
<xsl:sequence select="xs:integer(.)"/>
</xsl:template>
那么你可以使用
<xsl:template match="suma">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="sum($operands)"/>
</xsl:template>
对于乘法你可以使用一个函数(需要声明一个前缀 mf
绑定到一些命名空间)
<xsl:function name="mf:multiply" as="xs:integer">
<xsl:param name="operands" as="xs:integer+"/>
<xsl:sequence select="if (not(exists($operands[2])))
then $operands[1]
else $operands[1] * mf:multiply($operands[position() gt 1])"/>
</xsl:function>
然后在
中使用它<xsl:template match="multa">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="mf:multiply($operands)"/>
</xsl:template>
这是一个例子:
<xsl:stylesheet version="3.0" 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 mf">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:function name="mf:multiply" as="xs:integer">
<xsl:param name="operands" as="xs:integer+"/>
<xsl:sequence select="if (not(exists($operands[2])))
then $operands[1]
else $operands[1] * mf:multiply($operands[position() gt 1])"/>
</xsl:function>
<xsl:template match="expression">
<result>
<xsl:apply-templates/>
</result>
</xsl:template>
<xsl:template match="cons">
<xsl:sequence select="xs:integer(.)"/>
</xsl:template>
<xsl:template match="suma">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="sum($operands)"/>
</xsl:template>
<xsl:template match="multa">
<xsl:variable name="operands" as="xs:integer+">
<xsl:apply-templates select="*"/>
</xsl:variable>
<xsl:sequence select="mf:multiply($operands)"/>
</xsl:template>
</xsl:stylesheet>
示例输入为
<expression>
<suma>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
<multa>
<cons>1</cons>
<cons>2</cons>
<cons>3</cons>
</multa>
</suma>
</expression>
我得到输出 <result>12</result>
。