Selecting unique combinations from two node sets

Discussion in 'XML' started by johkar, Apr 12, 2009.

  1. johkar

    johkar Guest

    There are three unique loc/@id values and two unique coverageClass
    values. I need to figure out how to output all the unique
    combinations of the two (see example under original xml). Can anyone
    please help?

    <?xml version="1.0" encoding="UTF-8"?>
    <company>
    <company_bs>
    <company_info>
    <location>
    <loc id="1"/>
    </location>
    <location>
    <loc id="2"/>
    </location>
    <location>
    <loc id="3"/>
    </location>
    <business>
    <businessType>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    </businessType>
    </business>
    </company_info>
    </company_bs>
    </company>

    I would like to end up with all the unique location and class
    combinations like so:

    <company>
    <combo><loc>1</loc><class>Class1</class></combo>
    <combo><loc>1</loc><class>Class2</class></combo>
    <combo><loc>2</loc><class>Class1</class></combo>
    <combo><loc>2</loc><class>Class2</class></combo
    <combo><loc>3</loc><class>Class1</class></combo>
    <combo><loc>3</loc><class>Class2</class></combo>
    </company>
     
    johkar, Apr 12, 2009
    #1
    1. Advertising

  2. johkar wrote:

    > I would like to end up with all the unique location and class
    > combinations like so:
    >
    > <company>
    > <combo><loc>1</loc><class>Class1</class></combo>
    > <combo><loc>1</loc><class>Class2</class></combo>
    > <combo><loc>2</loc><class>Class1</class></combo>
    > <combo><loc>2</loc><class>Class2</class></combo
    > <combo><loc>3</loc><class>Class1</class></combo>
    > <combo><loc>3</loc><class>Class2</class></combo>
    > </company>


    With XSLT 2.0 (as supported by Saxon from http://saxon.sourceforge.net/
    and AltovaXML tools from http://www.altova.com/ and Gestalt from
    http://gestalt.sourceforge.net/) you can use

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

    <xsl:variable name="root" select="/"/>

    <xsl:template match="company">
    <xsl:copy>
    <xsl:for-each
    select="distinct-values(company_bs/company_info/location/loc/@id)">
    <xsl:variable name="id" select="."/>
    <xsl:for-each
    select="distinct-values($root/company/company_bs/company_info/business/businessType/businessClass/class/coverageClass)">
    <combo><loc><xsl:value-of
    select="$id"/></loc><class><xsl:value-of select="."/></class></combo>
    <xsl:value-of select="'
    '"/>
    </xsl:for-each>
    </xsl:for-each>
    </xsl:copy>
    </xsl:template>

    </xsl:stylesheet>

    With XSLT 1.0 you can apply Muenchian grouping:

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

    <xsl:key name="by-id" match="loc" use="@id"/>

    <xsl:key name="by-class" match="coverageClass" use="."/>

    <xsl:template match="company">
    <xsl:copy>
    <xsl:for-each
    select="company_bs/company_info/location/loc[generate-id() =
    generate-id(key('by-id', @id)[1])]">
    <xsl:variable name="id" select="@id"/>
    <xsl:for-each
    select="/company/company_bs/company_info/business/businessType/businessClass/class/coverageClass[generate-id()
    = generate-id(key('by-class', .)[1])]">
    <combo><loc><xsl:value-of
    select="$id"/></loc><class><xsl:value-of select="."/></class></combo>
    <xsl:value-of select="'
    '"/>
    </xsl:for-each>
    </xsl:for-each>
    </xsl:copy>
    </xsl:template>

    </xsl:stylesheet>

    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Apr 12, 2009
    #2
    1. Advertising

  3. in xslt2 something like the following. If you are stuck with xslt 1,
    then the usual technique is "muenchian grouping" (google for that).

    David


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

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

    <xsl:template match="/">
    <xsl:variable name="l"
    select="distinct-values(/company/company_bs/company_info/location/loc/@id)"/>
    <xsl:variable name="c"
    select="distinct-values(/company/company_bs/company_info/business/businessType/businessClass/class/coverageClass)"/>

    <company>
    <xsl:for-each select="$l">
    <xsl:variable name="loc" select="."/>
    <xsl:for-each select="$c">
    <combo><loc><xsl:value-of select="$loc"/></loc><class><xsl:value-of
    select="."/></class></combo>
    </xsl:for-each>
    </xsl:for-each>
    </company>
    </xsl:template>

    </xsl:stylesheet>
     
    David Carlisle, Apr 12, 2009
    #3
  4. johkar

    johkar Guest

    On Apr 12, 10:52 am, David Carlisle <>
    wrote:
    > in xslt2 something like the following. If you are stuck with xslt 1,
    > then the usual technique is "muenchian grouping" (google for that).
    >
    > David
    >
    > <xsl:stylesheet version="2.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    >
    > <xsl:eek:utput indent="yes"/>
    > <xsl:strip-space elements="*"/>
    >
    > <xsl:template match="/">
    > <xsl:variable name="l"
    > select="distinct-values(/company/company_bs/company_info/location/loc/@id)"­/>
    > <xsl:variable name="c"
    > select="distinct-values(/company/company_bs/company_info/business/businessT­ype/businessClass/class/coverageClass)"/>
    >
    > <company>
    > <xsl:for-each select="$l">
    > <xsl:variable name="loc" select="."/>
    > <xsl:for-each select="$c">
    > <combo><loc><xsl:value-of select="$loc"/></loc><class><xsl:value-of
    > select="."/></class></combo>
    > </xsl:for-each>
    > </xsl:for-each>
    > </company>
    > </xsl:template>
    >
    > </xsl:stylesheet>


    Thanks for the reply.
     
    johkar, Apr 12, 2009
    #4
  5. johkar

    johkar Guest

    On Apr 12, 5:03 am, Martin Honnen <> wrote:
    > johkar wrote:
    > > I would like to end up with all the unique location and class
    > > combinations like so:

    >
    > > <company>
    > > <combo><loc>1</loc><class>Class1</class></combo>
    > > <combo><loc>1</loc><class>Class2</class></combo>
    > > <combo><loc>2</loc><class>Class1</class></combo>
    > > <combo><loc>2</loc><class>Class2</class></combo
    > > <combo><loc>3</loc><class>Class1</class></combo>
    > > <combo><loc>3</loc><class>Class2</class></combo>
    > > </company>

    >
    > With XSLT 2.0 (as supported by Saxon fromhttp://saxon.sourceforge.net/
    > and AltovaXML tools fromhttp://www.altova.com/and Gestalt fromhttp://gestalt.sourceforge.net/) you can use
    >
    > <xsl:stylesheet
    >    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >    version="2.0">
    >
    >    <xsl:variable name="root" select="/"/>
    >
    >    <xsl:template match="company">
    >      <xsl:copy>
    >        <xsl:for-each
    > select="distinct-values(company_bs/company_info/location/loc/@id)">
    >          <xsl:variable name="id" select="."/>
    >          <xsl:for-each
    > select="distinct-values($root/company/company_bs/company_info/business/businessType/businessClass/class/coverageClass)">
    >            <combo><loc><xsl:value-of
    > select="$id"/></loc><class><xsl:value-of select="."/></class></combo>
    >            <xsl:value-of select="'
    '"/>
    >          </xsl:for-each>
    >        </xsl:for-each>
    >      </xsl:copy>
    >    </xsl:template>
    >
    > </xsl:stylesheet>
    >
    > With XSLT 1.0 you can apply Muenchian grouping:
    >
    > <xsl:stylesheet
    >    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >    version="1.0">
    >
    >    <xsl:key name="by-id" match="loc" use="@id"/>
    >
    >    <xsl:key name="by-class" match="coverageClass" use="."/>
    >
    >    <xsl:template match="company">
    >      <xsl:copy>
    >        <xsl:for-each
    > select="company_bs/company_info/location/loc[generate-id() =
    > generate-id(key('by-id', @id)[1])]">
    >          <xsl:variable name="id" select="@id"/>
    >          <xsl:for-each
    > select="/company/company_bs/company_info/business/businessType/businessClass/class/coverageClass[generate-id()
    > = generate-id(key('by-class', .)[1])]">
    >            <combo><loc><xsl:value-of
    > select="$id"/></loc><class><xsl:value-of select="."/></class></combo>
    >            <xsl:value-of select="'
    '"/>
    >          </xsl:for-each>
    >        </xsl:for-each>
    >      </xsl:copy>
    >    </xsl:template>
    >
    > </xsl:stylesheet>
    >
    > --
    >
    >         Martin Honnen
    >        http://JavaScript.FAQTs.com/


    Actually I have a slightly different scenario than I envisioned. loc/
    @id has its own businessType and I need to know the coverageClass's
    that are available to that location....they are no longer in the same
    nodeset.

    <?xml version="1.0" encoding="UTF-8"?>
    <company>
    <company_bs>
    <company_info>
    <location>
    <loc id="1"/>
    </location>
    <location>
    <loc id="2"/>
    </location>
    <location>
    <loc id="3"/>
    </location>
    <business>
    <businessType loc="1">
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    </businessType>
    <businessType loc="2">
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class3</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class3</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class4</coverageClass>
    </class>
    </businessClass>
    </businessType>
    <businessType loc="3">
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class2</coverageClass>
    </class>
    </businessClass>
    <businessClass>
    <class>
    <coverageClass>Class1</coverageClass>
    </class>
    </businessClass>
    </businessType>
    </business>
    </company_info>
    </company_bs>
    </company>

    I would like to end up with all the unique location and class
    combinations like so:

    <company>
    <combo><loc>1</loc><class>Class1</class></combo>
    <combo><loc>1</loc><class>Class2</class></combo>
    <combo><loc>2</loc><class>Class1</class></combo>
    <combo><loc>2</loc><class>Class3</class></combo>
    <combo><loc>2</loc><class>Class4</class></combo
    <combo><loc>3</loc><class>Class1</class></combo>
    <combo><loc>3</loc><class>Class2</class></combo>
    </company>
     
    johkar, Apr 13, 2009
    #5
  6. johkar wrote:

    > Actually I have a slightly different scenario than I envisioned. loc/
    > @id has its own businessType and I need to know the coverageClass's
    > that are available to that location....they are no longer in the same
    > nodeset.



    Here is an XSLT 2.0 solution:

    <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:key name="bt-by-loc" match="businessType" use="@loc"/>
    <xsl:variable name="root" select="/"/>

    <xsl:template match="company">
    <xsl:for-each
    select="distinct-values(company_bs/company_info/location/loc/@id)">
    <xsl:variable name="id" select="."/>
    <xsl:for-each select="distinct-values(key('bt-by-loc', $id,
    $root)/businessClass/class/coverageClass)">
    <combo>
    <loc>
    <xsl:value-of select="$id"/>
    </loc>
    <class>
    <xsl:value-of select="."/>
    </class>
    </combo>
    </xsl:for-each>
    </xsl:for-each>
    </xsl:template>

    </xsl:stylesheet>


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Apr 14, 2009
    #6
  7. johkar

    johkar Guest

    On Apr 14, 4:51 am, Martin Honnen <> wrote:
    > johkarwrote:
    > > Actually I have a slightly different scenario than I envisioned.  loc/
    > > @id has its own businessType and I need to know the coverageClass's
    > > that are available to that location....they are no longer in the same
    > > nodeset.

    >
    > Here is an XSLT 2.0 solution:
    >
    > <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:key name="bt-by-loc" match="businessType" use="@loc"/>
    >    <xsl:variable name="root" select="/"/>
    >
    >    <xsl:template match="company">
    >      <xsl:for-each
    > select="distinct-values(company_bs/company_info/location/loc/@id)">
    >        <xsl:variable name="id" select="."/>
    >        <xsl:for-each select="distinct-values(key('bt-by-loc', $id,
    > $root)/businessClass/class/coverageClass)">
    >          <combo>
    >            <loc>
    >              <xsl:value-of select="$id"/>
    >            </loc>
    >            <class>
    >              <xsl:value-of select="."/>
    >            </class>
    >          </combo>
    >        </xsl:for-each>
    >      </xsl:for-each>
    >    </xsl:template>
    >
    > </xsl:stylesheet>
    >
    > --
    >
    >         Martin Honnen
    >        http://JavaScript.FAQTs.com/


    Thanks Martin, I was called away and couldn't aknowledge your answer.
     
    johkar, Apr 19, 2009
    #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. Replies:
    0
    Views:
    1,470
  2. Tjerk Wolterink
    Replies:
    2
    Views:
    1,440
    Dimitre Novatchev
    Aug 24, 2006
  3. johkar
    Replies:
    2
    Views:
    612
    Peter Flynn
    Apr 12, 2009
  4. Srinivas Jonnalagadda

    Generating combinations from multiple sets

    Srinivas Jonnalagadda, Jan 16, 2006, in forum: Ruby
    Replies:
    1
    Views:
    143
    Srinivas Jonnalagadda
    Jan 16, 2006
  5. Replies:
    1
    Views:
    110
Loading...

Share This Page