XSLT - 分组跟随 - 兄弟姐妹
XSLT - Grouping following- siblings
我有 xml 如下,
<doc>
<section>
<p id="main">aa</p>
<p id="main">bb</p>
<p id="main">cc</p>
<p id="para1">dd</p>
<p id="st_main">ee</p>
<p id="st_main">ff</p>
<p id="xy_main">cc</p>
<p id="xy_main">cc</p>
<p id="main">gg</p>
<p id="para2">hh</p>
<p id="main">ii</p>
<p id="st_main">jj</p>
<p id="xy_main">cc</p>
<p id="main">cc</p>
<p id="para1">xx</p>
<p id="main">yy</p>
<p id="xy_main">zz</p>
<p id="main">cc</p>
</section>
</doc>
我的要求是
1) 按参数属性对 <p>
进行分组,并向每个 <p>
组添加单独的部分。
2) 识别 <p>
节点组,其 id 属性从 st
开始,将 <st_start>
和 <st_end>
放在组的开始和结束处
3) 识别 <p>
节点组,其 id 属性从 xy
开始,将 <xy_start>
和 <xy_end>
放在组的开始和结束处
所以预期的输出是,
<doc>
<section>
<p id="main">aa</p>
<p id="main">bb</p>
<p id="main">cc</p>
</section>
<section type="para1">
<p id="para1">dd</p>
<ss_start/>
<p id="st_main">ee</p>
<p id="st_main">ff</p>
<ss_end/>
<xy_start/>
<p id="xy_main">cc</p>
<p id="xy_main">cc</p>
<xy_end/>
<p id="main">gg</p>
</section>
<section type="para2">
<p id="para2">hh</p>
<p id="main">ii</p>
<ss_start/>
<p id="st_main">jj</p>
<ss_end/>
<xy_start/>
<p id="xy_main">cc</p>
<xy_end/>
<p id="main">cc</p>
</section>
<section type="para1">
<p id="para1">xx</p>
<p id="main">yy</p>
<xy_start/>
<p id="xy_main">zz</p>
<xy_end/>
<p id="main">cc</p>
</section>
</doc>
我有以下 xsl 来完成此任务
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'st')">
<xsl:if test="current-grouping-key()">
<ss_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key()">
<ss_end/>
</xsl:if>
</xsl:for-each-group>
<xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'xy')">
<xsl:if test="current-grouping-key()">
<xy_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key()">
<xy_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
但是内容翻倍了?如何修改我的代码以获得预期的输出?
我认为当您按 id
属性对相邻节点进行分组时,这里只需要一个嵌套的 xsl:for-each-group
。然后,您可以通过将键分组等于 st_main
或 xy_main
来进行测试,如果是,则添加额外的节点。
试试这个模板
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="current-grouping-key() = 'st_main'">
<ss_start/>
</xsl:if>
<xsl:if test="current-grouping-key() = 'xy_main'">
<xy_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key() = 'st_main'">
<ss_end/>
</xsl:if>
<xsl:if test="current-grouping-key() = 'xy_main'">
<xy_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
或者,为了避免过多的硬编码,您可以只检查以“_main”结尾的 id
属性并创建动态元素名称。也试试这个:
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="ends-with(current-grouping-key(), '_main')">
<xsl:element name="{substring-before(current-grouping-key(), '_')}_start" />
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="ends-with(current-grouping-key(), '_main')">
<xsl:element name="{substring-before(current-grouping-key(), '_')}_end" />
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
我有 xml 如下,
<doc>
<section>
<p id="main">aa</p>
<p id="main">bb</p>
<p id="main">cc</p>
<p id="para1">dd</p>
<p id="st_main">ee</p>
<p id="st_main">ff</p>
<p id="xy_main">cc</p>
<p id="xy_main">cc</p>
<p id="main">gg</p>
<p id="para2">hh</p>
<p id="main">ii</p>
<p id="st_main">jj</p>
<p id="xy_main">cc</p>
<p id="main">cc</p>
<p id="para1">xx</p>
<p id="main">yy</p>
<p id="xy_main">zz</p>
<p id="main">cc</p>
</section>
</doc>
我的要求是
1) 按参数属性对 <p>
进行分组,并向每个 <p>
组添加单独的部分。
2) 识别 <p>
节点组,其 id 属性从 st
开始,将 <st_start>
和 <st_end>
放在组的开始和结束处
3) 识别 <p>
节点组,其 id 属性从 xy
开始,将 <xy_start>
和 <xy_end>
放在组的开始和结束处
所以预期的输出是,
<doc>
<section>
<p id="main">aa</p>
<p id="main">bb</p>
<p id="main">cc</p>
</section>
<section type="para1">
<p id="para1">dd</p>
<ss_start/>
<p id="st_main">ee</p>
<p id="st_main">ff</p>
<ss_end/>
<xy_start/>
<p id="xy_main">cc</p>
<p id="xy_main">cc</p>
<xy_end/>
<p id="main">gg</p>
</section>
<section type="para2">
<p id="para2">hh</p>
<p id="main">ii</p>
<ss_start/>
<p id="st_main">jj</p>
<ss_end/>
<xy_start/>
<p id="xy_main">cc</p>
<xy_end/>
<p id="main">cc</p>
</section>
<section type="para1">
<p id="para1">xx</p>
<p id="main">yy</p>
<xy_start/>
<p id="xy_main">zz</p>
<xy_end/>
<p id="main">cc</p>
</section>
</doc>
我有以下 xsl 来完成此任务
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'st')">
<xsl:if test="current-grouping-key()">
<ss_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key()">
<ss_end/>
</xsl:if>
</xsl:for-each-group>
<xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'xy')">
<xsl:if test="current-grouping-key()">
<xy_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key()">
<xy_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
但是内容翻倍了?如何修改我的代码以获得预期的输出?
我认为当您按 id
属性对相邻节点进行分组时,这里只需要一个嵌套的 xsl:for-each-group
。然后,您可以通过将键分组等于 st_main
或 xy_main
来进行测试,如果是,则添加额外的节点。
试试这个模板
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="current-grouping-key() = 'st_main'">
<ss_start/>
</xsl:if>
<xsl:if test="current-grouping-key() = 'xy_main'">
<xy_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="current-grouping-key() = 'st_main'">
<ss_end/>
</xsl:if>
<xsl:if test="current-grouping-key() = 'xy_main'">
<xy_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
或者,为了避免过多的硬编码,您可以只检查以“_main”结尾的 id
属性并创建动态元素名称。也试试这个:
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="ends-with(current-grouping-key(), '_main')">
<xsl:element name="{substring-before(current-grouping-key(), '_')}_start" />
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="ends-with(current-grouping-key(), '_main')">
<xsl:element name="{substring-before(current-grouping-key(), '_')}_end" />
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>