Reputation: 15
I need some help here. I'm kinda new to XSLT.
I know in 2.0 you can use For-Each-Group which would solve my problem, but I'm limited to 1.0.
What I need to to group a flat XML using something like "group-starting-with" function.
This is only an example, but my real problem is very similar.
I have this XML:
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<xpto name="1">ABC</xpto>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
<xpto name="2">ABC</xpto>
<xpto name="1">ABC</xpto>
<title>Hide your heart</title>
<artist>Bob Dylan</artist>
<country>UK</country>
<company>CBS Records</company>
<price>9.90</price>
<year>1988</year>
<xpto name="2">ABC</xpto>
</catalog>
And I want it to be:
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<group>
<xpto name="1">ABC</xpto>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
<xpto name="2">ABC</xpto>
</group>
<group>
<xpto name="1">ABC</xpto>
<title>Hide your heart</title>
<artist>Bob Dylan</artist>
<country>UK</country>
<company>CBS Records</company>
<price>9.90</price>
<year>1988</year>
<xpto name="2">ABC</xpto>
</group>
</catalog>
So I want to group the elements every time the following appears:
<xpto name="1">ABC</xpto>
Is there any way to do this with XSLT 1.0?
Thank you very much!
Upvotes: 1
Views: 332
Reputation: 70628
Assuming you want to group the elements starting with <xpto name="1">
elements, you could define a key to group the other child elements by the first such element that precedes them:
<xsl:key name="start" match="*[not(self::xpto[@name='1'])]" use="generate-id(preceding-sibling::xpto[@name='1'][1])" />
Then, you can select all your starting elements, and get the other group items like so:
<xsl:apply-templates select=".|key('start', generate-id())" />
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="start" match="*[not(self::xpto[@name='1'])]" use="generate-id(preceding-sibling::xpto[@name='1'][1])" />
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="catalog">
<xsl:copy>
<xsl:for-each select="xpto[@name='1']">
<group>
<xsl:apply-templates select=".|key('start', generate-id())" />
</group>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2