XSLT - 对兄弟姐妹进行分组

时间:2015-09-22 12:01:53

标签: xml xslt xslt-2.0

我有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)按para属性对<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>

但是内容翻了一番?如何修改我的代码以获得预期的输出?

1 个答案:

答案 0 :(得分:1)

当您按照xsl:for-each-group属性对相邻节点进行分组时,我认为您只需要一个嵌套id。然后,您可以通过将密钥分组等于st_mainxy_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>