Help on xslt - grouping

Discussion in 'XML' started by Per Jørgen Vigdal, May 19, 2005.

  1. I have a XML that I need to map.
    The XML goes like:

    <Children>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="1.dat"/>
    <Reference name="invoicenr" value="1111111"/>
    <Reference name="invoicer_name" value="Bill"/>
    <Reference name="invoiceref" value="bbbbbb"/>
    </External>
    </References>
    </Child>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="2.dat"/>
    <Reference name="invoicenr" value="222222"/>
    <Reference name="invoicer_name" value="Bill"/>
    <Reference name="invoiceref" value="bbbbbb"/>
    </External>
    </References>
    </Child>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="3.dat"/>
    <Reference name="invoicenr" value="33333"/>
    <Reference name="invoicer_name" value="Clinton"/>
    <Reference name="invoiceref" value="ccccc"/>
    </External>
    </References>
    </Child>
    </Children>

    I want the structure to map to:

    <Senders>
    <Sender>
    <invoicer_name>Bill</invoicer_name>
    <invoiceref>bbbbbb</invoiceref>
    <Items TotalItems="2"/>
    </Sender>
    <Sender>
    <invoicer_name>Clinton</invoicer_name>
    <invoiceref>ccccc</invoiceref>
    <Items TotalItems="1"/>
    </Sender>
    </Senders>

    I have tried to use the "Muenchian Grouping" method, but am not able to
    obtain both
    <invoicer_name> and <invoiceref> under the <Sender> tag

    Here is my xsl :

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" indent="yes"/>
    <xsl:eek:utput encoding="ISO-8859-1"/>
    <xsl:key name="kDistinctSender"
    match="Children/Child/References/External/Reference[@name='invoicer_name']/@
    value" use="."/>
    <xsl:template match="/">
    <Senders>
    <!-- go through distinct InvoicerName -->
    <xsl:for-each
    select="/Children/Child/References/External/Reference[@name='invoicer_name']
    /@value[generate-id()=generate-id(key('kDistinctSender',.))]">
    <!-- sort by InvoicerName -->
    <xsl:sort select="."/>
    <Sender>
    <xsl:variable name="InvoicerName">
    <xsl:value-of select="."/>
    </xsl:variable>
    <InvoicerName>
    <xsl:value-of select="$InvoicerName"/>
    </InvoicerName>
    <Items TotalItems="{count(key('kDistinctSender',.))}">
    </Items>
    </Sender>
    </xsl:for-each>
    </Senders>
    </xsl:template>
    </xsl:stylesheet>
    Per Jørgen Vigdal, May 19, 2005
    #1
    1. Advertising

  2. Specify for the "use" attribute of xsl:key the concatenation of the values
    of "invoicer_name" and "invoiceref".


    Cheers,
    Dimitre Novatchev


    "Per Jørgen Vigdal" <> wrote in message
    news:...
    >I have a XML that I need to map.
    > The XML goes like:
    >
    > <Children>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="1.dat"/>
    > <Reference name="invoicenr" value="1111111"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="2.dat"/>
    > <Reference name="invoicenr" value="222222"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="3.dat"/>
    > <Reference name="invoicenr" value="33333"/>
    > <Reference name="invoicer_name" value="Clinton"/>
    > <Reference name="invoiceref" value="ccccc"/>
    > </External>
    > </References>
    > </Child>
    > </Children>
    >
    > I want the structure to map to:
    >
    > <Senders>
    > <Sender>
    > <invoicer_name>Bill</invoicer_name>
    > <invoiceref>bbbbbb</invoiceref>
    > <Items TotalItems="2"/>
    > </Sender>
    > <Sender>
    > <invoicer_name>Clinton</invoicer_name>
    > <invoiceref>ccccc</invoiceref>
    > <Items TotalItems="1"/>
    > </Sender>
    > </Senders>
    >
    > I have tried to use the "Muenchian Grouping" method, but am not able to
    > obtain both
    > <invoicer_name> and <invoiceref> under the <Sender> tag
    >
    > Here is my xsl :
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput method="xml" indent="yes"/>
    > <xsl:eek:utput encoding="ISO-8859-1"/>
    > <xsl:key name="kDistinctSender"
    > match="Children/Child/References/External/Reference[@name='invoicer_name']/@
    > value" use="."/>
    > <xsl:template match="/">
    > <Senders>
    > <!-- go through distinct InvoicerName -->
    > <xsl:for-each
    > select="/Children/Child/References/External/Reference[@name='invoicer_name']
    > /@value[generate-id()=generate-id(key('kDistinctSender',.))]">
    > <!-- sort by InvoicerName -->
    > <xsl:sort select="."/>
    > <Sender>
    > <xsl:variable name="InvoicerName">
    > <xsl:value-of select="."/>
    > </xsl:variable>
    > <InvoicerName>
    > <xsl:value-of select="$InvoicerName"/>
    > </InvoicerName>
    > <Items TotalItems="{count(key('kDistinctSender',.))}">
    > </Items>
    > </Sender>
    > </xsl:for-each>
    > </Senders>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    >
    Dimitre Novatchev, May 19, 2005
    #2
    1. Advertising

  3. Thanks
    I have tried to play around with concatenation and cant get it right, her is
    the result :

    <Senders>
    <Sender>
    <InvoicerName>Bill</InvoicerName>
    <Items TotalItems="3"/>
    </Sender>
    </Senders>


    Using xsl :

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" indent="yes"/>
    <xsl:eek:utput encoding="ISO-8859-1"/>
    <xsl:key name="kDistinctSender"
    match="Children/Child/References/External/Reference[@name='invoicer_name']/@
    value" use="concat(@name,'||',@value)"/>
    <xsl:template match="/">
    <Senders>

    <xsl:for-each
    select="/Children/Child/References/External/Reference[@name='invoicer_name']
    /@value[generate-id()=generate-id(key('kDistinctSender',concat(@name,'||',@v
    alue)))]">

    <xsl:sort select="."/>
    <Sender>
    <xsl:variable name="InvoicerName">
    <xsl:value-of select="."/>
    </xsl:variable>
    <InvoicerName>
    <xsl:value-of select="$InvoicerName"/>
    </InvoicerName>
    <Items
    TotalItems="{count(key('kDistinctSender',concat(@name,'||',@value)))}">
    </Items>
    </Sender>
    </xsl:for-each>
    </Senders>
    </xsl:template>
    </xsl:stylesheet>
    "Dimitre Novatchev" <> wrote in message
    news:428cf388$0$73807$...
    > Specify for the "use" attribute of xsl:key the concatenation of the values
    > of "invoicer_name" and "invoiceref".
    >
    >
    > Cheers,
    > Dimitre Novatchev
    >
    >
    > "Per Jørgen Vigdal" <> wrote in message
    > news:...
    > >I have a XML that I need to map.
    > > The XML goes like:
    > >
    > > <Children>
    > > <Child>
    > > <References>
    > > <External>
    > > <Reference name="filename" value="1.dat"/>
    > > <Reference name="invoicenr" value="1111111"/>
    > > <Reference name="invoicer_name" value="Bill"/>
    > > <Reference name="invoiceref" value="bbbbbb"/>
    > > </External>
    > > </References>
    > > </Child>
    > > <Child>
    > > <References>
    > > <External>
    > > <Reference name="filename" value="2.dat"/>
    > > <Reference name="invoicenr" value="222222"/>
    > > <Reference name="invoicer_name" value="Bill"/>
    > > <Reference name="invoiceref" value="bbbbbb"/>
    > > </External>
    > > </References>
    > > </Child>
    > > <Child>
    > > <References>
    > > <External>
    > > <Reference name="filename" value="3.dat"/>
    > > <Reference name="invoicenr" value="33333"/>
    > > <Reference name="invoicer_name" value="Clinton"/>
    > > <Reference name="invoiceref" value="ccccc"/>
    > > </External>
    > > </References>
    > > </Child>
    > > </Children>
    > >
    > > I want the structure to map to:
    > >
    > > <Senders>
    > > <Sender>
    > > <invoicer_name>Bill</invoicer_name>
    > > <invoiceref>bbbbbb</invoiceref>
    > > <Items TotalItems="2"/>
    > > </Sender>
    > > <Sender>
    > > <invoicer_name>Clinton</invoicer_name>
    > > <invoiceref>ccccc</invoiceref>
    > > <Items TotalItems="1"/>
    > > </Sender>
    > > </Senders>
    > >
    > > I have tried to use the "Muenchian Grouping" method, but am not able to
    > > obtain both
    > > <invoicer_name> and <invoiceref> under the <Sender> tag
    > >
    > > Here is my xsl :
    > >
    > > <xsl:stylesheet version="1.0"
    > > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > > <xsl:eek:utput method="xml" indent="yes"/>
    > > <xsl:eek:utput encoding="ISO-8859-1"/>
    > > <xsl:key name="kDistinctSender"
    > >

    match="Children/Child/References/External/Reference[@name='invoicer_name']/@
    > > value" use="."/>
    > > <xsl:template match="/">
    > > <Senders>
    > > <!-- go through distinct InvoicerName -->
    > > <xsl:for-each
    > >

    select="/Children/Child/References/External/Reference[@name='invoicer_name']
    > > /@value[generate-id()=generate-id(key('kDistinctSender',.))]">
    > > <!-- sort by InvoicerName -->
    > > <xsl:sort select="."/>
    > > <Sender>
    > > <xsl:variable name="InvoicerName">
    > > <xsl:value-of select="."/>
    > > </xsl:variable>
    > > <InvoicerName>
    > > <xsl:value-of select="$InvoicerName"/>
    > > </InvoicerName>
    > > <Items TotalItems="{count(key('kDistinctSender',.))}">
    > > </Items>
    > > </Sender>
    > > </xsl:for-each>
    > > </Senders>
    > > </xsl:template>
    > > </xsl:stylesheet>
    > >
    > >

    >
    >
    Per Jørgen Vigdal, May 19, 2005
    #3
  4. Per Jørgen Vigdal

    Volkm@r Guest

    Per Jørgen Vigdal wrote:
    > I have a XML that I need to map.
    > The XML goes like:
    >
    > <Children>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="1.dat"/>
    > <Reference name="invoicenr" value="1111111"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="2.dat"/>
    > <Reference name="invoicenr" value="222222"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="3.dat"/>
    > <Reference name="invoicenr" value="33333"/>
    > <Reference name="invoicer_name" value="Clinton"/>
    > <Reference name="invoiceref" value="ccccc"/>
    > </External>
    > </References>
    > </Child>
    > </Children>
    >
    > I want the structure to map to:
    >
    > <Senders>
    > <Sender>
    > <invoicer_name>Bill</invoicer_name>
    > <invoiceref>bbbbbb</invoiceref>
    > <Items TotalItems="2"/>
    > </Sender>
    > <Sender>
    > <invoicer_name>Clinton</invoicer_name>
    > <invoiceref>ccccc</invoiceref>
    > <Items TotalItems="1"/>
    > </Sender>
    > </Senders>
    >
    > I have tried to use the "Muenchian Grouping" method, but am not able to
    > obtain both
    > <invoicer_name> and <invoiceref> under the <Sender> tag
    >
    > Here is my xsl :
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput method="xml" indent="yes"/>
    > <xsl:eek:utput encoding="ISO-8859-1"/>
    > <xsl:key name="kDistinctSender"
    > match="Children/Child/References/External/Reference[@name='invoicer_name']/@
    > value" use="."/>
    > <xsl:template match="/">
    > <Senders>
    > <!-- go through distinct InvoicerName -->
    > <xsl:for-each
    > select="/Children/Child/References/External/Reference[@name='invoicer_name']
    > /@value[generate-id()=generate-id(key('kDistinctSender',.))]">
    > <!-- sort by InvoicerName -->
    > <xsl:sort select="."/>
    > <Sender>
    > <xsl:variable name="InvoicerName">
    > <xsl:value-of select="."/>
    > </xsl:variable>
    > <InvoicerName>
    > <xsl:value-of select="$InvoicerName"/>
    > </InvoicerName>
    > <Items TotalItems="{count(key('kDistinctSender',.))}">
    > </Items>
    > </Sender>
    > </xsl:for-each>
    > </Senders>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    >


    Did you try to simply put them in the right order?


    <xsl:template match="/">
    <Senders>
    <!-- go through distinct InvoicerName -->
    <xsl:apply-templates select="-XPath expression-">
    </Senders>
    </xsl:template>

    <xsl:template match="-expression from above-">
    <Sender>
    <xsl:apply-templates select=".[@name='invoicer_name']"/>
    <xsl:apply-templates select=".[@name='invoiceref']"/>
    <xsl:apply-templates select=".[@name='otherArtributeName']"/>
    <xsl:apply-templates select=".[@name='............']"/>
    <xsl:apply-templates select=".[@name='-one more line-']"/>
    </Sender>
    </xsl:apply-templates>
    </xsl:template>

    <xsl:........... - And Some More Templates - ........./>
    Volkm@r, May 20, 2005
    #4
  5. "Per Jørgen Vigdal" <> wrote in message
    news:...
    > Thanks
    > I have tried to play around with concatenation and cant get it right, her
    > is
    > the result :
    >
    > <Senders>
    > <Sender>
    > <InvoicerName>Bill</InvoicerName>
    > <Items TotalItems="3"/>
    > </Sender>
    > </Senders>



    This transformation:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>

    <xsl:strip-space elements="*"/>

    <xsl:key name="kExtNameRef" match="External"
    use="concat(Reference[@name='invoicer_name']/@value,
    '+',
    Reference[@name='invoiceref']/@value
    )"/>
    <xsl:template match="/">
    <Senders>
    <xsl:for-each select=
    "/*/*/*/External
    [generate-id()
    =
    generate-id(
    key('kExtNameRef',
    concat(Reference[@name='invoicer_name']/@value,
    '+',
    Reference[@name='invoiceref']/@value
    )
    )[1]
    )
    ]">
    <Sender>
    <invoicer_name>
    <xsl:value-of select=
    "Reference[@name='invoicer_name']/@value"/>
    </invoicer_name>
    <invoiceref>
    <xsl:value-of select=
    "Reference[@name='invoiceref']/@value"/>
    </invoiceref>
    <Items TotalItems="{
    count(
    key('kExtNameRef',
    concat(Reference[@name='invoicer_name']/@value,
    '+',
    Reference[@name='invoiceref']/@value
    )
    )
    )
    }"/>
    </Sender>
    </xsl:for-each>
    </Senders>

    </xsl:template>
    </xsl:stylesheet>

    when applied on your source.xml:

    <Children>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="1.dat"/>
    <Reference name="invoicenr" value="1111111"/>
    <Reference name="invoicer_name" value="Bill"/>
    <Reference name="invoiceref" value="bbbbbb"/>
    </External>
    </References>
    </Child>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="2.dat"/>
    <Reference name="invoicenr" value="222222"/>
    <Reference name="invoicer_name" value="Bill"/>
    <Reference name="invoiceref" value="bbbbbb"/>
    </External>
    </References>
    </Child>
    <Child>
    <References>
    <External>
    <Reference name="filename" value="3.dat"/>
    <Reference name="invoicenr" value="33333"/>
    <Reference name="invoicer_name" value="Clinton"/>
    <Reference name="invoiceref" value="ccccc"/>
    </External>
    </References>
    </Child>
    </Children>

    produces the wanted result:

    <Senders>
    <Sender>
    <invoicer_name>Bill</invoicer_name>
    <invoiceref>bbbbbb</invoiceref>
    <Items TotalItems="2" />
    </Sender>
    <Sender>
    <invoicer_name>Clinton</invoicer_name>
    <invoiceref>ccccc</invoiceref>
    <Items TotalItems="1" />
    </Sender>
    </Senders>


    Hope this helped.

    Cheers,
    Dimitre Novatchev
    Dimitre Novatchev, May 20, 2005
    #5
  6. This is great, exactly what I want. Thank you.
    This is goanna be tested in QA 22. Mai and if successful, put into
    production on 25. Mai where the
    xsl will do transformation on files that are as big as 100MB with thousands
    of items






    "Dimitre Novatchev" <> wrote in message
    news:428db6ed$0$75094$...
    >
    > "Per Jørgen Vigdal" <> wrote in message
    > news:...
    > > Thanks
    > > I have tried to play around with concatenation and cant get it right,

    her
    > > is
    > > the result :
    > >
    > > <Senders>
    > > <Sender>
    > > <InvoicerName>Bill</InvoicerName>
    > > <Items TotalItems="3"/>
    > > </Sender>
    > > </Senders>

    >
    >
    > This transformation:
    >
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
    >
    > <xsl:strip-space elements="*"/>
    >
    > <xsl:key name="kExtNameRef" match="External"
    > use="concat(Reference[@name='invoicer_name']/@value,
    > '+',
    > Reference[@name='invoiceref']/@value
    > )"/>
    > <xsl:template match="/">
    > <Senders>
    > <xsl:for-each select=
    > "/*/*/*/External
    > [generate-id()
    > =
    > generate-id(
    > key('kExtNameRef',
    > concat(Reference[@name='invoicer_name']/@value,
    > '+',
    > Reference[@name='invoiceref']/@value
    > )
    > )[1]
    > )
    > ]">
    > <Sender>
    > <invoicer_name>
    > <xsl:value-of select=
    > "Reference[@name='invoicer_name']/@value"/>
    > </invoicer_name>
    > <invoiceref>
    > <xsl:value-of select=
    > "Reference[@name='invoiceref']/@value"/>
    > </invoiceref>
    > <Items TotalItems="{
    > count(
    > key('kExtNameRef',
    > concat(Reference[@name='invoicer_name']/@value,
    > '+',
    > Reference[@name='invoiceref']/@value
    > )
    > )
    > )
    > }"/>
    > </Sender>
    > </xsl:for-each>
    > </Senders>
    >
    > </xsl:template>
    > </xsl:stylesheet>
    >
    > when applied on your source.xml:
    >
    > <Children>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="1.dat"/>
    > <Reference name="invoicenr" value="1111111"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="2.dat"/>
    > <Reference name="invoicenr" value="222222"/>
    > <Reference name="invoicer_name" value="Bill"/>
    > <Reference name="invoiceref" value="bbbbbb"/>
    > </External>
    > </References>
    > </Child>
    > <Child>
    > <References>
    > <External>
    > <Reference name="filename" value="3.dat"/>
    > <Reference name="invoicenr" value="33333"/>
    > <Reference name="invoicer_name" value="Clinton"/>
    > <Reference name="invoiceref" value="ccccc"/>
    > </External>
    > </References>
    > </Child>
    > </Children>
    >
    > produces the wanted result:
    >
    > <Senders>
    > <Sender>
    > <invoicer_name>Bill</invoicer_name>
    > <invoiceref>bbbbbb</invoiceref>
    > <Items TotalItems="2" />
    > </Sender>
    > <Sender>
    > <invoicer_name>Clinton</invoicer_name>
    > <invoiceref>ccccc</invoiceref>
    > <Items TotalItems="1" />
    > </Sender>
    > </Senders>
    >
    >
    > Hope this helped.
    >
    > Cheers,
    > Dimitre Novatchev
    >
    >
    Per Jørgen Vigdal, May 20, 2005
    #6
  7. "Per Jørgen Vigdal" <> wrote in message
    news:...
    > This is great, exactly what I want. Thank you.
    > This is goanna be tested in QA 22. Mai and if successful, put into
    > production on 25. Mai where the
    > xsl will do transformation on files that are as big as 100MB with
    > thousands
    > of items


    Good luck, and it would be interesting if you share your experience (or if
    you have any problems -- just signal) to the newsgroups (and the xsl-list).


    Cheers,
    Dimitre Novatchev
    Dimitre Novatchev, May 20, 2005
    #7
    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. Christian Ludwig

    XSLT: sorting and grouping

    Christian Ludwig, Nov 24, 2003, in forum: XML
    Replies:
    2
    Views:
    597
    Christian Ludwig
    Nov 26, 2003
  2. Kevin Brown
    Replies:
    3
    Views:
    538
    Kevin Brown
    Aug 28, 2004
  3. Graham

    Help Grouping/Counting XSLT

    Graham, Sep 17, 2004, in forum: XML
    Replies:
    3
    Views:
    556
    =?ISO-8859-1?Q?J=FCrgen_Kahrs?=
    Sep 17, 2004
  4. Jody Greening
    Replies:
    5
    Views:
    668
    Jody Greening
    Jan 6, 2005
  5. Mark
    Replies:
    1
    Views:
    399
    Janwillem Borleffs
    Aug 18, 2005
Loading...

Share This Page