适配.NET编译器:无key函数的XSLT 1.0代码生成指定PremiumSplit
XSLT 1.0 无key函数分组聚合实现方案
针对.NET环境无法使用key()函数的限制,以下代码通过排序+相邻节点比较的方式替代Muenchian分组,满足所有需求:
实现逻辑
- 先将所有
Record节点按CoverageSection、CoverageCode、VehicleCategory排序,确保同组节点连续排列 - 遍历节点时,仅处理每组的第一个节点(通过对比当前节点与前一节点的分组键判断),避免重复输出
- 对每个分组,通过节点路径筛选计算对应保费总和及占比,同时处理除零异常
完整XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 主入口:排序所有Record节点 --> <xsl:template match="/"> <Result> <xsl:apply-templates select="/*/Record"> <xsl:sort select="CoverageSection" data-type="text"/> <xsl:sort select="CoverageCode" data-type="text"/> <xsl:sort select="VehicleCategory" data-type="text"/> </xsl:apply-templates> </Result> </xsl:template> <!-- 仅输出每组的第一个节点 --> <xsl:template match="Record"> <xsl:variable name="currentKey" select="concat(CoverageSection, '|', CoverageCode, '|', VehicleCategory)"/> <xsl:variable name="prevKey" select="preceding-sibling::Record[1]/concat(CoverageSection, '|', CoverageCode, '|', VehicleCategory)"/> <xsl:if test="not($prevKey = $currentKey)"> <xsl:call-template name="processGroup"> <xsl:with-param name="section" select="CoverageSection"/> <xsl:with-param name="code" select="CoverageCode"/> <xsl:with-param name="category" select="VehicleCategory"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- 分组统计与输出模板 --> <xsl:template name="processGroup"> <xsl:param name="section"/> <xsl:param name="code"/> <xsl:param name="category"/> <!-- 计算当前分类下的保费总和 --> <xsl:variable name="categoryPremium" select="sum(//Record[CoverageSection = $section and CoverageCode = $code and VehicleCategory = $category]/Premium)"/> <!-- 计算当前CoverageCode的总保费 --> <xsl:variable name="codeTotalPremium" select="sum(//Record[CoverageSection = $section and CoverageCode = $code]/Premium)"/> <!-- 计算保费占比,处理除零情况 --> <xsl:variable name="coveragePercent"> <xsl:choose> <xsl:when test="$codeTotalPremium = 0 or $codeTotalPremium = ''">0.00%</xsl:when> <xsl:otherwise> <xsl:value-of select="format-number($categoryPremium div $codeTotalPremium, '0.00%')"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <CoverageGroup> <CoverageSection><xsl:value-of select="$section"/></CoverageSection> <CoverageCode><xsl:value-of select="$code"/></CoverageCode> <VehicleCategory><xsl:value-of select="$category"/></VehicleCategory> <CategoryPremium><xsl:value-of select="$categoryPremium"/></CategoryPremium> <CodeTotalPremium><xsl:value-of select="$codeTotalPremium"/></CodeTotalPremium> <CoveragePercent><xsl:value-of select="$coveragePercent"/></CoveragePercent> </CoverageGroup> </xsl:template> <!-- 忽略无关文本节点 --> <xsl:template match="text()"/> </xsl:stylesheet>
关键细节说明
- 去重逻辑:通过拼接三个分组字段生成唯一键,对比当前节点与前一节点的键值,仅处理新组的第一个节点,确保每组只输出一次
- 保费统计:使用
sum()函数结合节点筛选路径,精准计算同Section下的分类保费和Code总保费 - 异常处理:通过
xsl:choose判断总保费是否为0,避免除法运算出现错误,将无穷大/NaN替换为0.00% - 性能优化:如果原XML中
Record有明确的父节点,建议将//Record替换为具体的相对路径(如../Record),减少全局遍历开销
内容的提问来源于stack exchange,提问作者user1635003
相关产品推荐
相关产品推荐

