XSL实现:将指定兄弟标签包裹进section标签并避免内容重复
问题原因
你遇到的内容重复问题,本质是同一批后续兄弟元素被输出了两次:
- 第一次是在
<p outputclass="Endofclause">的模板里,你主动调用<xsl:apply-templates select="following-sibling::*"/>把这些元素塞进了<section>; - 第二次是因为默认的
<xsl:mode on-no-match="shallow-copy"/>会遍历所有未被特殊模板匹配的元素,这些后续兄弟元素又被浅拷贝输出了一遍。
解决办法
核心是让这些后续兄弟元素只被输出一次——要么只在<section>里输出,要么阻止默认模板输出它们。下面给两种实用的修改方案:
方案1:用模板模式区分处理逻辑
给需要包裹进<section>的元素单独定义一个处理模式,同时写一个空模板阻止默认输出这些元素,只有在指定模式下才输出它们:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 默认浅拷贝所有未匹配的元素 --> <xsl:mode on-no-match="shallow-copy"/> <!-- 处理Endofclause的p元素 --> <xsl:template match="p[@outputclass='Endofclause']"> <xsl:copy> <xsl:apply-templates select="@*, node()"/> </xsl:copy> <!-- 判断第一个后续兄弟是否符合条件 --> <xsl:if test="following-sibling::*[1][self::p[starts-with(normalize-space(), 'Alternate')]]"> <section> <!-- 用wrap模式处理后续兄弟,避免和默认模板冲突 --> <xsl:apply-templates select="following-sibling::*" mode="wrap"/> </section> </xsl:if> </xsl:template> <!-- 默认情况下,不输出Endofclause的后续兄弟 --> <xsl:template match="p[@outputclass='Endofclause']/following-sibling::*"/> <!-- 在wrap模式下,正常输出这些元素 --> <xsl:template match="*" mode="wrap"> <xsl:copy> <xsl:apply-templates select="@*, node()" mode="wrap"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案2:用分组简化逻辑(XSLT 3.0专属)
利用xsl:for-each-group把<p outputclass="Endofclause">和前面的元素归为一组,直接处理分组后的内容,同时跳过后续兄弟的默认输出:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:mode on-no-match="shallow-copy"/> <!-- 对conbody的子元素分组,以Endofclause的p为分组结尾 --> <xsl:template match="conbody"> <xsl:copy> <xsl:for-each-group select="*" group-ending-with="p[@outputclass='Endofclause']"> <!-- 输出当前组的所有内容 --> <xsl:apply-templates select="current-group()"/> <!-- 检查是否需要包裹后续兄弟 --> <xsl:if test="current-group()[last()][following-sibling::*[1][self::p[starts-with(normalize-space(), 'Alternate')]]]"> <section> <xsl:apply-templates select="current-group()[last()]/following-sibling::*"/> </section> </xsl:if> </xsl:for-each-group> </xsl:copy> </xsl:template> <!-- 阻止后续兄弟被默认模板重复输出 --> <xsl:template match="p[@outputclass='Endofclause']/following-sibling::*"/> </xsl:stylesheet>
最终效果
修改后的XSL处理你提供的输入XML,会得到没有重复内容的正确输出:
<?xml version="1.0" encoding="UTF-8"?><dita> <concept> <title> <ph>Page 5</ph> TEST XML</title> <conbody> <p>As prescribed in <ph> <xref href="test2.dita#1234">2 TEST</xref>(a)</ph>, insert the following clause:</p> <p class="- topic/p " id="d3235e15" outputclass="Ctr_SmCaps">Shipment and Payment</p> <p class="- topic/p " outputclass="Endofclause">(End of clause)</p><section><p class="- topic/p " id="d3238e514"> <i class="+ topic/ph hi-d/i ">Alternate I</i> </p><p class="- topic/p "> A2</p><p class="- topic/p "> A3</p></section> </conbody> </concept> </dita>
内容的提问来源于stack exchange,提问作者Jino John Devasia
相关产品推荐
相关产品推荐

