XPATH equivalent of SELECT DISTINCT

Discussion in 'XML' started by andrewmrichards, Dec 2, 2010.

  1. Hi all

    I have a document which looks like this:

    <catalog>
    <item>
    <label>Label 1</label>
    <title>Title 1</title>
    <artist>Artist 1</artist>
    <format>cd</format>
    </item>
    <item>
    <label>Label 1</label>
    <title>Title 1</title>
    <artist>Artist 1</artist>
    <format>download</format>
    </item>
    <item>
    <label>Label 1</label>
    <title>Title 2</title>
    <artist>Artist 2</artist>
    <format>cd</format>
    </item>
    <item>
    <label>Label 2</label>
    <title>Title 3</title>
    <artist>Artist 3</artist>
    <format>cd</format>
    </item>
    </catalog>

    What I'd like to do is use an XSL stylesheet to transform this into:

    <catalog>
    <label>
    <labelName>Label 1</labelName>
    <items>
    <item>
    Title 1 CD
    </item>
    <item>
    Title 1 Download
    </item>
    Title 2 CD
    </item
    </items>
    </label>
    <label>
    <labelName>Label 2</labelName>
    <items>
    <item>
    Title 3 CD
    </item>
    </items>
    </label>
    </catalog>

    I've tried loads of approaches, generally centered around using
    position()=1 as a test, or variations of this, and they don't work - I
    always end up with everything repeated for EVERY item, and I can't get
    a structure where there's only one <label> structure for each label,
    no matter how many items they have. I can see why they don't work -
    but I can't find an approach which will.

    What I want is something akin to <xsl:for-each
    select="distint(label)"> in the way that the SQL SELECT DISTINCT
    keyword works.

    Can anyone point me in the right direction?

    Many thanks

    Andrew Richards
    andrewmrichards, Dec 2, 2010
    #1
    1. Advertising

  2. andrewmrichards <> writes:

    > Hi all
    >
    > I have a document which looks like this:
    >
    > <catalog>
    > <item>
    > <label>Label 1</label>
    > <title>Title 1</title>
    > <artist>Artist 1</artist>
    > <format>cd</format>
    > </item>
    > <item>
    > <label>Label 1</label>
    > <title>Title 1</title>
    > <artist>Artist 1</artist>
    > <format>download</format>
    > </item>
    > <item>
    > <label>Label 1</label>
    > <title>Title 2</title>
    > <artist>Artist 2</artist>
    > <format>cd</format>
    > </item>
    > <item>
    > <label>Label 2</label>
    > <title>Title 3</title>
    > <artist>Artist 3</artist>
    > <format>cd</format>
    > </item>
    > </catalog>
    >
    > What I'd like to do is use an XSL stylesheet to transform this into:
    >
    > <catalog>
    > <label>
    > <labelName>Label 1</labelName>
    > <items>
    > <item>
    > Title 1 CD
    > </item>
    > <item>
    > Title 1 Download
    > </item>
    > Title 2 CD
    > </item
    > </items>
    > </label>
    > <label>
    > <labelName>Label 2</labelName>
    > <items>
    > <item>
    > Title 3 CD
    > </item>
    > </items>
    > </label>
    > </catalog>
    >
    > I've tried loads of approaches, generally centered around using
    > position()=1 as a test, or variations of this, and they don't work - I
    > always end up with everything repeated for EVERY item, and I can't get
    > a structure where there's only one <label> structure for each label,
    > no matter how many items they have. I can see why they don't work -
    > but I can't find an approach which will.
    >
    > What I want is something akin to <xsl:for-each
    > select="distint(label)"> in the way that the SQL SELECT DISTINCT
    > keyword works.
    >
    > Can anyone point me in the right direction?
    >

    In XSLT/XPath 2.0 there is a distinct-values function. But you probably would use for-each-group to collect the items that belong to the same label. In XSLT/XPath 1.0 you could use the Muench method with a key on the labels.
    --
    Piet van Oostrum <>
    WWW: http://pietvanoostrum.com/
    PGP key: [8DAE142BE17999C4]
    Nu Fair Trade woonartikelen op http://www.zylja.com
    Piet van Oostrum, Dec 3, 2010
    #2
    1. Advertising

  3. andrewmrichards wrote:

    > <catalog>
    > <item>
    > <label>Label 1</label>
    > <title>Title 1</title>
    > <artist>Artist 1</artist>
    > <format>cd</format>
    > </item>
    > <item>
    > <label>Label 1</label>
    > <title>Title 1</title>
    > <artist>Artist 1</artist>
    > <format>download</format>
    > </item>
    > <item>
    > <label>Label 1</label>
    > <title>Title 2</title>
    > <artist>Artist 2</artist>
    > <format>cd</format>
    > </item>
    > <item>
    > <label>Label 2</label>
    > <title>Title 3</title>
    > <artist>Artist 3</artist>
    > <format>cd</format>
    > </item>
    > </catalog>
    >
    > What I'd like to do is use an XSL stylesheet to transform this into:
    >
    > <catalog>
    > <label>
    > <labelName>Label 1</labelName>
    > <items>
    > <item>
    > Title 1 CD
    > </item>
    > <item>
    > Title 1 Download
    > </item>
    > Title 2 CD
    > </item
    > </items>
    > </label>
    > <label>
    > <labelName>Label 2</labelName>
    > <items>
    > <item>
    > Title 3 CD
    > </item>
    > </items>
    > </label>
    > </catalog>


    With XSLT 2.0 (as implemented by Saxon 9 http://saxon.sourceforge.net/,
    AltovaXML Tools http://www.altova.com/altovaxml.html, XQSharp
    http://www.xqsharp.com/) you can use for-each-group select="item"
    group-by="label" as follows:

    <xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:strip-space elements="*"/>
    <xsl:eek:utput method="xml" indent="yes"/>

    <xsl:template match="catalog">
    <xsl:copy>
    <xsl:for-each-group select="item" group-by="label">
    <label>
    <labelName><xsl:value-of
    select="current-grouping-key()"/></labelName>
    <items>
    <xsl:apply-templates select="current-group()"/>
    </items>
    </label>
    </xsl:for-each-group>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="item">
    <xsl:copy><xsl:value-of select="title, format"/></xsl:copy>
    </xsl:template>

    </xsl:stylesheet>

    With XSLT 1.0 you can use Muenchian grouping
    http://www.jenitennison.com/xslt/grouping/index.xml.

    --

    Martin Honnen
    http://msmvps.com/blogs/martin_honnen/
    Martin Honnen, Dec 3, 2010
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?YmVub2l0?=

    Select Distinct DataGrid

    =?Utf-8?B?YmVub2l0?=, Oct 14, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    2,132
    =?Utf-8?B?YmVub2l0?=
    Oct 14, 2005
  2. will
    Replies:
    1
    Views:
    1,143
    Pavel Lepin
    Aug 15, 2007
  3. Hicham Mouline
    Replies:
    1
    Views:
    389
    Kai-Uwe Bux
    Apr 11, 2010
  4. Marco Alting

    SELECT DISTINCT from two tables

    Marco Alting, Jul 30, 2003, in forum: ASP General
    Replies:
    4
    Views:
    159
    Phill. W
    Jul 31, 2003
  5. mianiro

    Distinct and Top in Select

    mianiro, Jan 2, 2007, in forum: ASP General
    Replies:
    1
    Views:
    146
    Bob Barrows [MVP]
    Jan 2, 2007
Loading...

Share This Page