XSLT 2.0分组转换XML时元素重复问题的解决诉求
解决XSLT分组转换中元素重复输出的问题
我来帮你搞定这个重复输出的问题~你遇到的核心问题是当前的节点选择逻辑存在重叠,导致同一批<p>元素被多次处理输出。
问题根源
你原来的XSLT中,处理heading-01时会选中它之后所有直到下一个heading-01的节点,其中包含heading-02和对应的paratext;而单独的heading-02模板又会处理自身和后续的paratext,把它们包装成<sec>,但同时这些paratext又会被默认的身份模板再输出一次,最终造成重复。
修改后的XSLT代码
推荐使用XSLT 2.0原生的xsl:for-each-group分组功能,通过group-starting-with明确划分层级,确保每个节点只被归属到一个分组,避免重复处理:
<?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" exclude-result-prefixes="xs" version="2.0"> <!-- 默认身份模板:复制未被其他模板匹配的节点 --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="body"> <body> <!-- 第一层分组:以每个heading-01作为分组起始 --> <xsl:for-each-group select="node()" group-starting-with="p[@content-type='heading-01']"> <xsl:if test="self::p[@content-type='heading-01']"> <sec sec-type="{@content-type}"> <title><xsl:value-of select="."/></title> <!-- 第二层分组:在当前heading-01组内,以heading-02作为分组起始 --> <xsl:for-each-group select="current-group() except ." group-starting-with="p[@content-type='heading-02']"> <xsl:choose> <xsl:when test="self::p[@content-type='heading-02']"> <sec sec-type="{@content-type}"> <title><xsl:value-of select="."/></title> <!-- 输出当前heading-02组内的所有paratext --> <xsl:apply-templates select="current-group() except ."/> </sec> </xsl:when> <xsl:otherwise> <!-- 输出heading-01直接对应的paratext --> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </sec> </xsl:if> </xsl:for-each-group> </body> </xsl:template> </xsl:stylesheet>
代码逻辑说明
- 第一层分组:在
<body>内,将所有节点以p[@content-type='heading-01']为起始分组,每个分组对应一个heading-01及其后续内容,直到下一个heading-01出现。 - 第二层分组:在每个
heading-01的分组内,再以p[@content-type='heading-02']为起始划分子分组,确保每个heading-02和对应的paratext被单独包裹进子<sec>。 - 避免重复:每个节点只会属于一个分组,
heading-02对应的paratext只会在子<sec>内输出一次,而heading-01直接对应的paratext也仅输出一次,彻底解决重复问题。
用这个代码处理你的输入XML,就能得到你期望的输出结果啦~
内容的提问来源于stack exchange,提问作者Amrendra Kumar
相关产品推荐
相关产品推荐

