XSLT - 通过分析属性值进行分组
XSLT - Grouping by analyzing attribute values
我有一个 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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<p id="main">ii</p>
<p id="main">cc</p>
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
我的要求是
1) 按 para 属性分组 <p>
并向每个 <p>
组添加单独的部分。
2) 识别 <p>
节点组,其 id 属性从 st
开始,将 <st_start>
和 <st_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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<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:if test="current-group()[1][not(@id='main')]">
<xsl:attribute name="type" select="current-group()[1]/@id"/>
</xsl:if>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="starts-with(current-grouping-key(),'st')">
<ss_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="starts-with(current-grouping-key(),'st')">
<ss_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
这个 xsl 给了我以下结果,
<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>
<ss_end/>
<ss_start/>
<p id="st_chap">ff</p>
<p id="st_chap">gg</p>
<ss_end/>
<ss_start/>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
如您所见,它分别为 <p id="st_main">
和 <p id="st_chap">
添加了 <ss_start/>
和 <ss_end/>
。但我需要从 st
开始识别具有 attr id
的连续 <p>
元素,并用 <ss_start/>
和 <ss_end/>
.
覆盖这些节点
任何人都可以建议我如何修改我的代码以获得预期的结果吗?
如果你只是使用
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:if test="current-group()[1][not(@id='main')]">
<xsl:attribute name="type" select="current-group()[1]/@id"/>
</xsl:if>
<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>
</section>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
然后你得到输出
<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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
这可能是您最简单的解决方案...
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes" encoding="utf-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:apply-templates select="current-group()[1]/@id" mode="section-type" />
<xsl:apply-templates select="current-group()" />
</section>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="@id[starts-with(., 'para')]" mode="section-type">
<xsl:attribute name="type" select="." />
</xsl:template>
<xsl:template match="@*" mode="section-type" />
<xsl:template match="p[starts-with(@id, 'st')]
[not(starts-with(preceding-sibling::p[1]/@id, 'st'))]">
<ss_start />
<xsl:next-match />
</xsl:template>
<xsl:template match="p[starts-with(@id, 'st')]
[not(starts-with(following-sibling::p[1]/@id, 'st'))]">
<xsl:next-match />
<ss_end/>
</xsl:template>
</xsl:stylesheet>
我有一个 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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<p id="main">ii</p>
<p id="main">cc</p>
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
我的要求是
1) 按 para 属性分组 <p>
并向每个 <p>
组添加单独的部分。
2) 识别 <p>
节点组,其 id 属性从 st
开始,将 <st_start>
和 <st_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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<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:if test="current-group()[1][not(@id='main')]">
<xsl:attribute name="type" select="current-group()[1]/@id"/>
</xsl:if>
<xsl:for-each-group select="current-group()" group-adjacent="@id">
<xsl:if test="starts-with(current-grouping-key(),'st')">
<ss_start/>
</xsl:if>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="starts-with(current-grouping-key(),'st')">
<ss_end/>
</xsl:if>
</xsl:for-each-group>
</section>
</xsl:for-each-group>
</xsl:template>
这个 xsl 给了我以下结果,
<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>
<ss_end/>
<ss_start/>
<p id="st_chap">ff</p>
<p id="st_chap">gg</p>
<ss_end/>
<ss_start/>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
如您所见,它分别为 <p id="st_main">
和 <p id="st_chap">
添加了 <ss_start/>
和 <ss_end/>
。但我需要从 st
开始识别具有 attr id
的连续 <p>
元素,并用 <ss_start/>
和 <ss_end/>
.
任何人都可以建议我如何修改我的代码以获得预期的结果吗?
如果你只是使用
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:if test="current-group()[1][not(@id='main')]">
<xsl:attribute name="type" select="current-group()[1]/@id"/>
</xsl:if>
<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>
</section>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
然后你得到输出
<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_chap">ff</p>
<p id="st_chap">gg</p>
<p id="st_main">hh</p>
<ss_end/>
<p id="main">ii</p>
<p id="main">cc</p>
</section>
<section type="para2">
<p id="para2">xx</p>
<p id="main">yy</p>
<p id="main">cc</p>
</section>
</doc>
这可能是您最简单的解决方案...
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes" encoding="utf-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="section">
<xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
<section>
<xsl:apply-templates select="current-group()[1]/@id" mode="section-type" />
<xsl:apply-templates select="current-group()" />
</section>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="@id[starts-with(., 'para')]" mode="section-type">
<xsl:attribute name="type" select="." />
</xsl:template>
<xsl:template match="@*" mode="section-type" />
<xsl:template match="p[starts-with(@id, 'st')]
[not(starts-with(preceding-sibling::p[1]/@id, 'st'))]">
<ss_start />
<xsl:next-match />
</xsl:template>
<xsl:template match="p[starts-with(@id, 'st')]
[not(starts-with(following-sibling::p[1]/@id, 'st'))]">
<xsl:next-match />
<ss_end/>
</xsl:template>
</xsl:stylesheet>