如何用XSLT group-adjacent实现符合前置节点条件的节点分组?
XML节点分组需求及XSLT修正方案
需求描述
需要将目标XML中的<d>节点以及紧跟在<d>之后的<a>节点归入<GROUP>标签,其余节点保持原有结构不变。
输入XML
<doc> <a>blabla</a> <b>blabla</b> <c>text C</c> <d>text D</d> <a>bla</a> <d>text D</d> <a>bla</a> </doc>
期望输出XML
<doc> <a>blabla</a> <b>blabla</b> <c>text C</c> <GROUP> <d>text D</d> <a>bla</a> <d>text D</d> <a>bla</a> </GROUP> </doc>
原代码问题
尝试的XSLT代码会把所有<a>和<d>节点都归为一组,无法排除那些前一个节点不是<d>的<a>节点;同时使用<xsl:value-of>会丢失节点标签结构,只保留文本内容。
原代码:
<xsl:template match="doc"> <xsl:copy> <xsl:for-each-group select="*" group-adjacent="boolean(self::a | self::d)"> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:element name="GROUP"> <xsl:value-of select="current-group()"/> </xsl:element> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:copy> </xsl:template>
修正后的XSLT代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 处理doc节点 --> <xsl:template match="doc"> <xsl:copy> <!-- 输出不需要分组的节点:非d节点,且不是紧跟在d后面的a节点 --> <xsl:apply-templates select="*[not(self::d) and not(self::a and preceding-sibling::*[1][self::d])]"/> <!-- 包裹所有符合分组条件的节点 --> <xsl:if test="*[self::d or (self::a and preceding-sibling::*[1][self::d])]"> <GROUP> <xsl:apply-templates select="*[self::d or (self::a and preceding-sibling::*[1][self::d])]"/> </GROUP> </xsl:if> </xsl:copy> </xsl:template> <!-- 默认模板:复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
修正思路说明
- 筛选非分组节点:通过条件
not(self::d) and not(self::a and preceding-sibling::*[1][self::d]),精准排除需要分组的节点,只输出符合要求的原始节点。 - 包裹分组节点:收集所有
<d>节点,以及前一个兄弟节点是<d>的<a>节点,统一用<GROUP>标签包裹。 - 保留节点结构:使用默认模板复制节点,替代原代码的
<xsl:value-of>,确保节点的标签和内容完整保留。
内容的提问来源于stack exchange,提问作者jessika perignon
相关产品推荐
相关产品推荐

