使用XSL合并同类型且class属性相同的节点
合并XML中相邻冗余的
<span>标签解决方案 刚接触XSL就着手处理标签清理,这个方向很实用!针对你给出的XML里多个相邻span class="USous-article"需要合并的需求,我给你准备了两种XSLT方案,分别适配XSLT 2.0和1.0环境,你可以根据自己的工具版本选择:
先看你的XML示例:
<body><!-- userBodyTop goes here --> <div class="header" /> <div class="document"> <p class="text">...</p> <p class="Normal"> <span class="USous-article">§ 1er </span> <span class="USous-article">–</span> <span class="USous-article"> </span> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus condime... </p> </div> </body>
方案1:XSLT 2.0(推荐,语法更简洁)
利用XSLT 2.0的group-adjacent功能,可以轻松把相邻同class的span分组合并:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 身份模板:默认复制所有未被特殊匹配的节点/属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配目标p标签,处理内部的span合并 --> <xsl:template match="p[contains(@class, 'Normal')]"> <xsl:copy> <xsl:apply-templates select="@*"/> <!-- 按相邻节点类型分组:同class的span归为一组,其他节点各自成组 --> <xsl:for-each-group select="node()" group-adjacent="if (self::span[@class='USous-article']) then 'merge-span' else generate-id()"> <xsl:choose> <!-- 处理需要合并的span组 --> <xsl:when test="current-grouping-key()='merge-span'"> <span class="USous-article"> <!-- 拼接组内所有span的文本内容 --> <xsl:value-of select="current-group()/text()"/> </span> </xsl:when> <!-- 其他节点原样输出 --> <xsl:otherwise> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
说明:
- 身份模板保证XML里其他未涉及的内容(比如header、text类p标签)完全保留原样。
- 针对
p class="Normal"内部的节点,我们把相邻的USous-articlespan归为一组,合并成一个span并拼接所有文本,非目标span的内容正常输出。
方案2:XSLT 1.0(兼容旧环境)
如果你的工具只支持XSLT 1.0,可以用递归模板来实现相同效果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 身份模板:默认复制所有节点/属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配第一个未被合并的USous-article span --> <xsl:template match="span[@class='USous-article'][not(preceding-sibling::node()[1][self::span[@class='USous-article']])]"> <span class="USous-article"> <!-- 递归收集所有相邻同class span的文本 --> <xsl:call-template name="merge-adjacent"> <xsl:with-param name="current" select="."/> </xsl:call-template> </span> <!-- 跳过已合并的span,处理下一个非目标节点 --> <xsl:apply-templates select="following-sibling::node()[not(self::span[@class='USous-article'])][1]"/> </xsl:template> <!-- 跳过已经被合并的后续span --> <xsl:template match="span[@class='USous-article'][preceding-sibling::node()[1][self::span[@class='USous-article']]]"/> <!-- 递归模板:收集相邻同class span的文本 --> <xsl:template name="merge-adjacent"> <xsl:param name="current"/> <xsl:value-of select="$current/text()"/> <!-- 如果下一个节点还是同class span,继续递归 --> <xsl:if test="$current/following-sibling::node()[1][self::span[@class='USous-article']]"> <xsl:call-template name="merge-adjacent"> <xsl:with-param name="current" select="$current/following-sibling::node()[1][self::span[@class='USous-article']]"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
说明:
- 核心是通过递归找到所有连续的
USous-articlespan,把它们的文本拼接起来输出成一个span。 - 额外加了一个模板跳过已经被合并的后续span,避免重复输出。
内容的提问来源于stack exchange,提问作者R. BR
相关产品推荐
相关产品推荐

