如何对XML元素值应用函数并输出保留属性的新XML文档?
解决XSLT处理XML时属性丢失与复杂公式应用问题
咱们先拆解你遇到的两个核心问题:row元素的name属性丢失,以及如何应用依赖元素值的复杂计算逻辑,一步步来解决:
一、为什么name属性会丢失?
你的自定义模板匹配test/row[@name='C/A'] | test/row[@name='C/B']时,只执行了<xsl:copy>复制元素本身,然后直接输出计算后的值,但<xsl:copy>并不会自动复制元素的属性。你需要在这个模板里显式处理属性节点,就像默认的identity模板那样。
修改后的模板如下:
<xsl:template match="test/row[@name='C/A'] | test/row[@name='C/B']"> <xsl:copy> <!-- 先复制当前元素的所有属性(包括name) --> <xsl:apply-templates select="@*"/> <!-- 再输出计算后的值 --> <xsl:value-of select=". * 1000"/> </xsl:copy> </xsl:template>
这样处理后,row元素的name属性就会被保留下来了。
二、如何应用依赖元素值的复杂公式?
如果你的计算逻辑需要根据当前row的值动态调整(比如根据数值正负、范围使用不同乘数),在XSLT 1.0里可以用<xsl:choose>实现条件判断,或者把复用逻辑封装成模板调用。
示例1:简单条件判断计算
比如实现“负数乘以2000,正数乘以1000”的逻辑:
<xsl:template match="test/row[@name='C/A'] | test/row[@name='C/B']"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:choose> <xsl:when test=". < 0"> <xsl:value-of select=". * 2000"/> </xsl:when> <xsl:otherwise> <xsl:value-of select=". * 1000"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template>
示例2:封装复杂计算为可复用模板
如果公式逻辑更复杂(比如多分支判断、多步骤计算),可以把计算逻辑封装成独立模板,方便复用:
<!-- 封装计算逻辑的模板 --> <xsl:template name="complex-calculate"> <xsl:param name="input-value"/> <xsl:choose> <xsl:when test="$input-value < -0.15"> <xsl:value-of select="$input-value * 1500"/> </xsl:when> <xsl:when test="$input-value < 0"> <xsl:value-of select="$input-value * 1000"/> </xsl:when> <xsl:when test="$input-value < 2"> <xsl:value-of select="$input-value * 900"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$input-value * 800"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 调用计算模板的row处理逻辑 --> <xsl:template match="test/row[@name='C/A'] | test/row[@name='C/B']"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:call-template name="complex-calculate"> <xsl:with-param name="input-value" select="."/> </xsl:call-template> </xsl:copy> </xsl:template>
完整的修改后XSLT样式表
把上面的逻辑整合起来,最终的样式表如下:
<?xml version="1.0" encoding="UTF-8"?> <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" /> <!-- Identity模板:默认复制所有未被自定义模板匹配的节点和属性 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()" /> </xsl:copy> </xsl:template> <!-- 处理C/A和C/B的row元素,保留属性并应用自定义计算 --> <xsl:template match="test/row[@name='C/A'] | test/row[@name='C/B']"> <xsl:copy> <xsl:apply-templates select="@*"/> <!-- 这里替换成你的复杂计算逻辑 --> <xsl:value-of select=". * 1000"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
使用这个样式表处理你的源XML,就能得到保留name属性且计算正确的输出了。
内容的提问来源于stack exchange,提问作者tosspot




