我有一个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>
正如您所看到的,它为<ss_start/>
和<ss_end/>
分别添加了<p id="st_main">
和<p id="st_chap">
。但我需要从<p>
开始识别具有at id
的连续st
元素,并按<ss_start/>
和<ss_end/>
覆盖这些节点。
有人可以建议我如何修改我的代码以获得我的预期结果?
答案 0 :(得分:2)
如果您只是使用
<?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>
答案 1 :(得分:2)
这可能是您最简单的解决方案......
<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>