如何仅对XML序列中部分指定元素进行相邻分组?
解决方案
要实现保留所有元素顺序,同时将相邻的、@style为Note/Warning/Caution的2个及以上<p>用<div>包裹分组,可通过XSLT的<xsl:for-each-group>结合group-adjacent属性实现,核心思路是对<section>下的所有子元素统一分组,而非仅选中<p>,具体如下:
核心思路
- 选中
<section>下的所有子元素(包括<title>和各类<p>),避免遗漏非目标元素; - 以“当前元素是否为符合样式要求的
<p>”作为分组依据,将相邻的目标<p>归为同一组,其他元素各自成组; - 对每个分组判断:若为包含2个及以上目标
<p>的组,用<div>包裹输出;否则直接输出组内元素。
代码示例
输入XML
<section> <title>章节标题</title> <p style="Normal">普通段落1</p> <p style="Note">注意段落1</p> <p style="Note">注意段落2</p> <p style="Warning">警告段落1</p> <p style="Warning">警告段落2</p> <p style="Warning">警告段落3</p> <p style="Normal">普通段落2</p> <title>另一标题</title> <p style="Caution">警示段落1</p> <p style="Normal">普通段落3</p> </section>
XSLT转换代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="section"> <xsl:copy> <!-- 对section下所有子元素按是否为目标p分组 --> <xsl:for-each-group select="*" group-adjacent="boolean(self::p and (@style = 'Note' or @style = 'Warning' or @style = 'Caution'))"> <xsl:choose> <!-- 目标p组且数量≥2时,用div包裹 --> <xsl:when test="current-grouping-key() and count(current-group()) >= 2"> <div> <xsl:copy-of select="current-group()"/> </div> </xsl:when> <!-- 其他情况直接输出元素 --> <xsl:otherwise> <xsl:copy-of select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
输出结果
<section> <title>章节标题</title> <p style="Normal">普通段落1</p> <div> <p style="Note">注意段落1</p> <p style="Note">注意段落2</p> </div> <div> <p style="Warning">警告段落1</p> <p style="Warning">警告段落2</p> <p style="Warning">警告段落3</p> </div> <p style="Normal">普通段落2</p> <title>另一标题</title> <p style="Caution">警示段落1</p> <p style="Normal">普通段落3</p> </section>
关键细节说明
select="*":确保选中<section>下所有子元素,包括<title>,不会遗漏任何元素;group-adjacent的判断逻辑:通过boolean()将条件转换为布尔值,相邻的符合条件的<p>会被分到同一组,非目标元素(如<title>、普通<p>)各自单独成组;- 分组后的判断:仅当分组是目标
<p>且数量≥2时,才用<div>包裹,避免单个目标<p>被错误包裹。
内容的提问来源于stack exchange,提问作者Hobbes
相关产品推荐
相关产品推荐

