如何在XSLT 2.0中计算简单移动平均(SMA)?附实例需求
在XSLT 2.0中计算简单移动平均(SMA)的解决方案
当然可以用XSLT 2.0计算简单移动平均!我结合你提到的三星每月价格的实例,一步步给你演示怎么实现,同时也覆盖你提到的“100个数值输出50个SMA结果”的场景。
一、针对你的具体实例:输出第5和第10个月的SMA
首先假设你的XML结构大概是这样的(存储每月价格):
<prices> <price month="1">1500</price> <price month="2">1520</price> <price month="3">1480</price> <price month="4">1550</price> <price month="5">1530</price> <price month="6">1560</price> <price month="7">1540</price> <price month="8">1570</price> <price month="9">1510</price> <price month="10">1580</price> <!-- 更多月份数据... --> </prices>
这里我默认你要计算的是5期简单移动平均(也就是连续5个月的价格平均值):第5个月的SMA是前5个月的平均,第10个月的SMA是第6-10个月的平均。对应的XSLT代码如下:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义移动平均的周期,可按需修改 --> <xsl:variable name="sma-period" select="5"/> <xsl:template match="/prices"> <sma-results> <!-- 计算并输出第5个月对应的SMA --> <xsl:call-template name="compute-sma"> <xsl:with-param name="target-month" select="5"/> </xsl:call-template> <!-- 计算并输出第10个月对应的SMA --> <xsl:call-template name="compute-sma"> <xsl:with-param name="target-month" select="10"/> </xsl:call-template> </sma-results> </xsl:template> <!-- 通用SMA计算模板 --> <xsl:template name="compute-sma"> <xsl:param name="target-month"/> <!-- 筛选出计算当前SMA所需的连续月份价格 --> <xsl:variable name="relevant-prices" select="price[@month >= ($target-month - $sma-period + 1) and @month <= $target-month]"/> <sma-entry> <target-month><xsl:value-of select="$target-month"/></target-month> <sma-period><xsl:value-of select="$sma-period"/></sma-period> <average-price> <!-- 计算平均值:总和除以数量 --> <xsl:value-of select="sum($relevant-prices) div count($relevant-prices)"/> </average-price> </sma-entry> </xsl:template> </xsl:stylesheet>
代码说明:
- 我们通过变量
sma-period定义移动平均的周期,后续要调整周期(比如改成10期)直接改这个值就行。 compute-sma模板负责核心计算:先筛选出目标月份及之前n-1个月的价格数据,再用sum()求和后除以count()得到平均值。- 最终会输出结构化的XML结果,清晰展示每个目标月份对应的SMA信息。
二、扩展场景:100个数值输出50个SMA结果
如果你的需求是把100个数值按每2个一组计算平均(刚好得到50个结果),可以用XSLT 2.0的分组功能来实现,代码如下:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 每组的大小,决定最终结果数量:100/2=50 --> <xsl:variable name="group-size" select="2"/> <xsl:template match="/prices"> <sma-results> <!-- 按位置分组,每$group-size个price为一组 --> <xsl:for-each-group select="price" group-by="(position() - 1) idiv $group-size"> <sma-entry> <group-number><xsl:value-of select="position()"/></group-number> <average-price> <xsl:value-of select="sum(current-group()) div count(current-group())"/> </average-price> </sma-entry> </xsl:for-each-group> </sma-results> </xsl:template> </xsl:stylesheet>
代码说明:
- 用
for-each-group结合(position()-1) idiv $group-size实现按位置分组,确保每2个数值为一组。 - 每组内直接计算平均值,最终输出50组的结果,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Jakub Oškera




