Fighting with XSLT. Get unique node set.

There was an interesting problem today. How to use XSLT to get unique node set from xml document. I wemt throught google and didn't found answer that would satisfy the needs :(
Maybe you are XSLT expert? Please answer... I forgot to note XSLT 1.0, please.
The input is
<x>
 <y a="1" b="1" c="1" />
 <y a="1" b="1" c="2" />
 <y a="1" b="2" c="3" />
 <y a="1" b="2" c="1" />
 <y a="2" b="2" c="5" />
 <y a="3" b="1" c="6" />
</x>
and the output should be
<x>
 <y a="1" b="1" c="1, 2" />
 <y a="1" b="2" c="3, 1" />
 <y a="2" b="2" c="5" />
 <y a="3" b="1" c="6" />
</x>
It means I would like to group the input by a, b.
Any ideas?
Comments:

There's a reason you should use XSLT 2.0. If you must use 1.0, try
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="x">
        <x>
            <xsl:variable name="ab-pairs">
                <xsl:for-each select="y">
                    <xsl:sort data-type="number" order="ascending" select="@a"/>
                    <xsl:sort data-type="number" order="ascending" select="@b"/>
                    <xsl:value-of select="position()"/><xsl:text>!</xsl:text><xsl:value-of select="@a"/><xsl:text>,</xsl:text><xsl:value-of select="@b"/><xsl:text>!</xsl:text>
                </xsl:for-each>
            </xsl:variable>
            <xsl:for-each select="y">
                <xsl:sort data-type="number" order="ascending" select="@a"/>
                <xsl:sort data-type="number" order="ascending" select="@b"/>
                <xsl:variable name="this-pair" select="concat(@a, ',', @b)"/>
                <xsl:variable name="prev-pair" select="substring-after(substring-before($ab-pairs, concat('!', position(), '!')), concat(position() - 1, '!'))"/>
                <xsl:variable name="next-pair" select="substring-before(substring-after($ab-pairs, concat('!', position() + 1, '!')), '!')"/>
                <xsl:variable name="is-first" select="position() = 1 or $prev-pair != $this-pair"/>
                <xsl:variable name="is-last" select="position() = last() or $this-pair != $next-pair"/>
                <xsl:if test="$is-first">
                    <xsl:text disable-output-escaping="yes">&amp;#10;    &amp;lt;y a="</xsl:text><xsl:value-of select="@a"/>" b="<xsl:value-of select="@b"/><xsl:text>" c="</xsl:text>
                </xsl:if>
                <xsl:if test="not($is-first)">
                    <xsl:text>, </xsl:text>
                </xsl:if>
                <xsl:value-of select="@c"/>
                <xsl:if test="$is-last">
                    <xsl:text disable-output-escaping="yes">"/&amp;gt;</xsl:text>
                </xsl:if>
            </xsl:for-each>
            <xsl:text>&amp;#10;</xsl:text>
        </x>
    </xsl:template>
</xsl:stylesheet>

Posted by Jesse Glick on March 08, 2006 at 12:21 PM CET #

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="ab" match="y" use="concat(@a, @b)"/>
<xsl:output method = "xml"/>
<xsl:template match="/">
<xsl:for-each select="x/y[generate-id()=generate-id(key('ab', concat(@a, @b)))]">
	<y a="{@a}" b="{@b}">
		<xsl:attribute name="c">
			<xsl:for-each select="key('ab', concat(@a, @b))">
				<xsl:choose>
					<xsl:when test="position()=last()">
						<xsl:value-of select="@c"/>
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="concat(@c, ', ')"/>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:for-each>
		</xsl:attribute>
	</y>
</xsl:for-each> 
</xsl:template>
</xsl:transform>

Posted by Piotr Lipski on March 08, 2006 at 04:47 PM CET #

Jesse, Piotr, I have to say big THANK YOU, it really helps us. I finally chose Piotr's solution, it's easy to read and also maintain. Once more: thank to both of you ...

Posted by Marian on March 09, 2006 at 03:01 AM CET #

Thank you.

Posted by Lukas on March 09, 2006 at 10:22 AM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
About

This is the main channel to share news, tips and other stuff related to my work. Sometimes you can find even personal stuff. Enjoy your reading...

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
news
Blogroll

No bookmarks in folder

OldNews
MyTrash
NavBar
NetBeans
LinksToBeExpanded