如何用XSLT包装XML文档中的特定块



我有一个XML文档,看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
<p>One</p>
<p>Two</p>
<p>Three</p>
<p type="start" />
<p>A</p>
<p><id>1</id>B</p>
<p type="end" />
<p>Four</p>
<p>Five</p>
<p type="start" />
<p>C</p>
<p><id>3</id>D</p>
<p type="end" />
<p>Six</p>
</doc>

我需要包装p[@type ='start']p[@type ='end']元素之间的所有内容,同时保留文档的其余部分。因此输出应该是:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
<p>One</p>
<p>Two</p>
<p>Three</p>
<group>
<p>A</p>
<p><id>1</id>B</p>
</group>
<p>Four</p>
<p>Five</p>
<group>
<p>C</p>
<p><id>3</id>D</p>
</group>
<p>Six</p>
</doc>

基于xslt:选择两个节点之间的所有特定节点,但在特定节点处停止我尝试:

<xsl:template match="doc">
<xsl:for-each-group select="*" group-starting-with="p[@type = 'start']">
<xsl:if test="self::p[@type = 'start']">
<group>
<xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@type = 'end']">
<xsl:if test="position() eq 1">
<xsl:apply-templates select="current-group()[not(self::p[@type = 'end'])]" />
</xsl:if>
</xsl:for-each-group>
</group>
</xsl:if>
</xsl:for-each-group>
</xsl:template>

不幸的是,这完全排除了不在p[@type ='start']p[@type ='end']元素之间的所有元素。因此,我如何得到相同的结果,但保留(通过其他模板)文档的其余部分。

使用xsl:choose代替xsl:if,并且这样做两次,也只在找到开始和结束时插入group包装器:

<xsl:template match="doc">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="p[@type = 'start']">
<xsl:choose>
<xsl:when test="self::p[@type = 'start']">
<xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@type = 'end']">                <xsl:choose>
<xsl:when test="current-group()[last()][self::p[@type = 'end']]">
<group>
<xsl:apply-templates select="current-group()[not(position() = last())]"/>
</group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>

这假设您已经将恒等转换设置为复制节点的基本模板。

最新更新