Reputation: 1836
I have the following XML:
<items>
<item x="1" y="3"/>
<item x="2" y="4"/>
<item x="3" y="4"/>
<item x="4" y="2"/>
<item x="5" y="1"/>
</items>
I want to ultimately put them into an HTML table (the x
and y
are coordinates of cells in that table), and to make it easier I want to put the items into rows, like this:
<items>
<row y="1">
<item x="1" y="1"/>
</row>
<row y="2">
<item x="2" y="2"/>
</row>
<row y="3">
<item x="5" y="3"/>
</row>
<row y="4">
<item x="3" y="4"/>
<item x="4" y="4"/>
</row>
</items>
But the only transform I can come up with not only doesn't work, but also doesn't allow me to annotate the rows with row number.
<xsl:template match="/items">
<items>
<row>
<xsl:for-each select="item">
<xsl:sort select="@y"/>
<xsl:sort select="@x"/>
<xsl:if test="preceding-sibling::item[1]/@y != @y">
<xsl:text>"</row>"</xsl:text>
<xsl:text>"<row>"</xsl:text>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</row>
</items>
</xsl:template>
How can I accomplish this?
Upvotes: 1
Views: 205
Reputation: 21661
Your posted XSLT isn't valid - a proper processor won't let you start and end tags like that in a way that could end up being invalid XML.
You need to group these - if you're using XSLT 1.0 you can use Muenchian grouping like so, although I'm not quite sure how to make sense of your expected output given your input:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" indent="yes" />
<xsl:key name="items-by-y" match="item" use="@y" />
<xsl:template match="/items">
<items>
<xsl:for-each select="item[count(. | key('items-by-y', @y)[1]) =1]">
<xsl:sort select="@y" />
<xsl:sort select="@x" />
<row y="{@y}">
<xsl:for-each select="key('items-by-y', @y)">
<xsl:copy-of select="." />
</xsl:for-each>
</row>
</xsl:for-each>
</items>
</xsl:template>
</xsl:stylesheet>
results in:
<items>
<row y="1">
<item x="5" y="1"/>
</row>
<row y="2">
<item x="4" y="2"/>
</row>
<row y="3">
<item x="1" y="3"/>
</row>
<row y="4">
<item x="2" y="4"/>
<item x="3" y="4"/>
</row>
</items>
If you're using XSLT 2.0, you could do something like <xsl:for-each-group>
, see How to use for each group in XSL for more information.
Upvotes: 2