使用XSLT对一些XML元素进行分组

时间:2016-03-21 15:07:29

标签: xml xslt xslt-2.0

我在XSLT上挣扎了几个小时,我来到StackOverflow寻求帮助。我有一些像这样的输入文本:

<?xml version="1.0" encoding="UTF-8"?>
<div>
<p class="text">Some regular text</p>
<p class="first">The first part</p>
<p class="next">and then some text</p>
<p class="next">and some more</p>

<p class="regular">Some regular text</p>
<p class="text1">Some regular text</p>
<p class="text2">Some regular text</p>
<p class="first">Here some new text</p>
<p class="next">and some more</p>
<p class="next">and the end of this section</p>
<p class="text3">Some regular text</p>
</div>

我想结束这个

<?xml version="1.0" encoding="UTF-8"?>
<div>
<p>Some regular text</p>

<group>
    <p>The first part</p>
    <p>and then some text</p>
    <p>and some more</p>
</group>

<p>Some regular text</p>
<p>Some regular text</p>
<p>Some regular text</p>

<group>
    <p>Here some new text</p>
    <p>and some more</p>
    <p>and the end of this section</p>
</group>

<p>Some regular text</p>
</div>

我知道这并不是一件非常困难的事,但我不明白......我现在所拥有的XSLT是:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="/">
    <xsl:apply-templates select="*" />
</xsl:template>

<xsl:template match="*">
    <xsl:copy>
        <xsl:for-each select="@*">
            <xsl:copy />
        </xsl:for-each>
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

<xsl:template match="div">
    <lg>
        <xsl:apply-templates/>
    </lg>
</xsl:template>


<xsl:template match="/div">
    <xsl:for-each-group select="//p[@class='first']/following-sibling::p[@class='next']" group-by="text()">
        <group>
            <xsl:apply-templates/>
        </group>
    </xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>

这根本不起作用:(如果有人能帮助我,我将非常感激,因为我真的很难理解XSLT是如何工作的......

祝你好运, 何

1 个答案:

答案 0 :(得分:2)

您正尝试将p属性设置为“first”的class分组,然后将所有“下一个”属性分组。

对于您提供的XML,此XSLT可以解决这个问题:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

  <xsl:template match="/div">
    <xsl:for-each-group select="p" group-adjacent="@class = 'first' or @class='next'">
        <xsl:choose>
            <xsl:when test="@class = 'first' or @class='next'">
                <group>
                    <xsl:apply-templates select="current-group()" />
                </group>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="current-group()" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group>
</xsl:template>

<xsl:template match="@class" />
</xsl:stylesheet>

但是,在这种情况下这不起作用,因为它会将所有p个元素放在一个组中。

<div>
<p class="first">The first part</p>
<p class="next">and then some text</p>
<p class="first">Here some new text</p>
<p class="next">and some more</p>
</div>

如果这不是您想要的,请尝试使用此XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

  <xsl:template match="/div">
    <xsl:for-each-group select="p" group-starting-with="p[@class='first']">
      <xsl:for-each-group select="current-group()" group-adjacent="@class='first' or @class='next'">
        <xsl:choose>
            <xsl:when test="@class='first' or @class='next'">
                <group>
                    <xsl:apply-templates select="current-group()" />
                </group>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="current-group()" />
            </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:for-each-group>
</xsl:template>

<xsl:template match="@class" />
</xsl:stylesheet>