XSLT reduce or count number of matching output elements

Discussion in 'XML' started by Marcel Akkerman, Feb 21, 2004.

  1. Hi,

    Does anyone have a clue how to reduce the number of nodes using XSLT?
    When outputing all nodes in order I could just use
    <xsl:for-each select="name[position & $someNumber]">

    But what if I, besides sorting and grouping, I also output
    conditionally?

    <xsl:for-each
    select="//name[generate-id(.)=generate-id(key('names',city))]">
    <strong><xsl:value-of select="city"/></strong>
    <xsl:for-each select="key('names',city)">
    <xsl:sort select="date" order="ascending"/>
    <xsl:if test="translate(date, '-', '') &gt; translate($afterDate, '-',
    '')">
    <xsl:value-of select="name"/><br>
    </xsl:if>
    </xsl:for-each>
    </xsl:for-each>


    With this transformation I can get the names of people who's birthday
    is after a given date. The names are sorted by date and grouped by the
    city.

    What to do if I only want a total of $maximum result??

    gratefull for anyhelp.

    Marcel.
     
    Marcel Akkerman, Feb 21, 2004
    #1
    1. Advertising

  2. "Marcel Akkerman" <> wrote in message
    news:...
    >
    > Hi,
    >
    > Does anyone have a clue how to reduce the number of nodes using XSLT?


    Yes, you can reduce it completely by having:

    <xsl:template match="/" />


    > When outputing all nodes in order I could just use
    > <xsl:for-each select="name[position & $someNumber]">


    This is not well-formed xml -- what do you want to say?


    >
    > But what if I, besides sorting and grouping, I also output
    > conditionally?
    >
    > <xsl:for-each
    > select="//name[generate-id(.)=generate-id(key('names',city))]">
    > <strong><xsl:value-of select="city"/></strong>
    > <xsl:for-each select="key('names',city)">
    > <xsl:sort select="date" order="ascending"/>
    > <xsl:if test="translate(date, '-', '') &gt; translate($afterDate, '-',
    > '')">
    > <xsl:value-of select="name"/><br>
    > </xsl:if>
    > </xsl:for-each>
    > </xsl:for-each>
    >
    >
    > With this transformation I can get the names of people who's birthday
    > is after a given date. The names are sorted by date and grouped by the
    > city.


    No, what would be output as result depends completely on the source xnl
    document, which you haven't shown to us.


    >
    > What to do if I only want a total of $maximum result??


    What does "a total of $maximum result" mean?

    Please, alawys formulate well your problem if you really want to be
    understood so that somebody could help.

    A well-formulated problem includes the source xml document, the wanted
    result of the transformation, (these two should completely describe the
    problem, but be with minimal possible length and well indented so that they
    are readable and understandable), a description of the desired properties of
    the transformation.


    Cheers,

    Dimitre Novatchev [XML MVP],
    FXSL developer, XML Insider,

    http://fxsl.sourceforge.net/ -- the home of FXSL
    Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
     
    Dimitre Novatchev [MVP XML], Feb 22, 2004
    #2
    1. Advertising

  3. On Sun, 22 Feb 2004 09:57:51 +0100, "Dimitre Novatchev [MVP XML]"
    <> wrote:

    >
    >"Marcel Akkerman" <> wrote in message
    >news:...
    >>
    >> Hi,
    >>
    >> Does anyone have a clue how to reduce the number of nodes using XSLT?

    >
    >Yes, you can reduce it completely by having:
    >
    > <xsl:template match="/" />
    >
    >
    >> When outputing all nodes in order I could just use
    >> <xsl:for-each select="name[position & $someNumber]">

    >
    >This is not well-formed xml -- what do you want to say?

    sorry
    it just a fragment and supposed to be:
    <xsl:for0each select="name[position $lt; %someNumber]">

    >>
    >> But what if I, besides sorting and grouping, I also output
    >> conditionally?
    >>
    >> <xsl:for-each
    >> select="//name[generate-id(.)=generate-id(key('names',city))]">
    >> <strong><xsl:value-of select="city"/></strong>
    >> <xsl:for-each select="key('names',city)">
    >> <xsl:sort select="date" order="ascending"/>
    >> <xsl:if test="translate(date, '-', '') &gt; translate($afterDate, '-',
    >> '')">
    >> <xsl:value-of select="name"/><br>
    >> </xsl:if>
    >> </xsl:for-each>
    >> </xsl:for-each>
    >>
    >>
    >> With this transformation I can get the names of people who's birthday
    >> is after a given date. The names are sorted by date and grouped by the
    >> city.

    >
    >No, what would be output as result depends completely on the source xnl
    >document, which you haven't shown to us.


    Fine, here's one with the irellevant data left out.

    <people>
    <person>
    <name>Johnson</name>
    <city>Boston</city>
    <date>1965-02-05</date>
    </person>
    <person>
    <name>Smit</name>
    <city>Lutjebroek</city>
    <date>1975-04-06</date>
    </person>

    <!-- etc. -->

    </people>


    Desired output (I get it this far)

    Boston
    Johnons
    Peterson
    Ackerman

    Lutjebroek
    Smit
    Timmerman
    de la Frost
    Bos

    Amsterdam
    Lubbers
    Veensma

    This goes on as long as there are nodes in the original XML
    What I want is to reduce the number names output to, let's say 5 in
    total. This would look like:

    Boston
    Johnons
    Peterson
    Ackerman

    Lutjebroek
    Smit
    Timmerman

    An maybe reduce it to 2 per city. Which will look like:

    Boston
    Johnons
    Peterson

    Lutjebroek
    Smit
    Timmerman

    Amsterdam
    Lubbers
    Veensma



    -- hope you know what I'm after now :-D
    -- thanks for any help.

    Marcel.
     
    Marcel Akkerman, Feb 22, 2004
    #3
  4. On Sun, 22 Feb 2004 12:10:30 +0100, Marcel Akkerman
    <> wrote:

    >On Sun, 22 Feb 2004 09:57:51 +0100, "Dimitre Novatchev [MVP XML]"
    ><> wrote:
    >
    >>
    >>"Marcel Akkerman" <> wrote in message
    >>news:...
    >>>
    >>> Hi,
    >>>
    >>> Does anyone have a clue how to reduce the number of nodes using XSLT?

    >>
    >>Yes, you can reduce it completely by having:
    >>
    >> <xsl:template match="/" />
    >>
    >>
    >>> When outputing all nodes in order I could just use
    >>> <xsl:for-each select="name[position & $someNumber]">

    >>
    >>This is not well-formed xml -- what do you want to say?

    >sorry
    >it just a fragment and supposed to be:

    <xsl:for-each select="name[position() &lt; $someNumber]">
     
    Marcel Akkerman, Feb 22, 2004
    #4
  5. > Fine, here's one with the irellevant data left out.
    >
    > <people>
    > <person>
    > <name>Johnson</name>
    > <city>Boston</city>
    > <date>1965-02-05</date>
    > </person>
    > <person>
    > <name>Smit</name>
    > <city>Lutjebroek</city>
    > <date>1975-04-06</date>
    > </person>
    >
    > <!-- etc. -->
    >
    > </people>
    >
    >
    > Desired output (I get it this far)
    >
    > Boston
    > Johnons
    > Peterson
    > Ackerman
    >
    > Lutjebroek
    > Smit
    > Timmerman
    > de la Frost
    > Bos
    >
    > Amsterdam
    > Lubbers
    > Veensma
    >
    > This goes on as long as there are nodes in the original XML
    > What I want is to reduce the number names output to, let's say 5 in
    > total. This would look like:
    >
    > Boston
    > Johnons
    > Peterson
    > Ackerman
    >
    > Lutjebroek
    > Smit
    > Timmerman
    >
    > An maybe reduce it to 2 per city. Which will look like:
    >
    > Boston
    > Johnons
    > Peterson
    >
    > Lutjebroek
    > Smit
    > Timmerman
    >
    > Amsterdam
    > Lubbers
    > Veensma



    This transformation:

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

    <xsl:eek:utput method="text"/>

    <xsl:key name="kdistCity" match="city" use="."/>
    <xsl:key name="kNamesByCity" match="name" use="../city"/>

    <xsl:template match="/">
    <xsl:variable name="vCities" select=
    "/*/*/city[generate-id()
    =
    generate-id(key('kdistCity', .)[1])
    ]"/>
    <xsl:call-template name="dispNames">
    <xsl:with-param name="pCities" select="$vCities"/>
    <xsl:with-param name="pBornAfter" select="19650201"/>
    <xsl:with-param name="pMaxNames" select="6"/>
    <xsl:with-param name="pMaxNamesPerCity" select="2"/>
    </xsl:call-template>
    </xsl:template>

    <xsl:template name="dispNames">
    <xsl:param name="pCities" select="/.."/>
    <xsl:param name="pBornAfter" select="0"/>
    <xsl:param name="pMaxNames" select="1000"/>
    <xsl:param name="pMaxNamesPerCity" select="100"/>
    <xsl:param name="ptotalDisplayed" select="0"/>

    <xsl:variable name="vmore2Display"
    select="$pMaxNames - $ptotalDisplayed"/>

    <xsl:variable name="vthisCity" select="$pCities[1]"/>

    <xsl:variable name="vnamesInThisCity" select=
    "key('kNamesByCity', $vthisCity)
    [translate(../date, '-', '')
    >

    $pBornAfter
    ]"/>
    <xsl:variable name="vcntNamesInCity"
    select="count($vnamesInThisCity)"/>

    <xsl:if test="$vmore2Display > 0 and $pCities">
    <xsl:variable name="vdispLimit" select=
    "$pMaxNamesPerCity * ($vmore2Display > $pMaxNamesPerCity)
    +
    $vmore2Display * (not($vmore2Display > $pMaxNamesPerCity))
    "/>

    <xsl:value-of select="concat('

    ', $vthisCity)"/>

    <xsl:for-each select="$vnamesInThisCity">
    <xsl:sort select="translate(../date, '-', '')"/>

    <xsl:if test="position() &lt;= $vdispLimit">
    <xsl:value-of select="concat('
    ', .)"/>
    </xsl:if>
    </xsl:for-each>

    <xsl:call-template name="dispNames">
    <xsl:with-param name="pCities" select="$pCities[position() > 1]"/>
    <xsl:with-param name="pBornAfter" select="$pBornAfter"/>
    <xsl:with-param name="pMaxNames" select="$pMaxNames"/>
    <xsl:with-param name="pMaxNamesPerCity" select="$pMaxNamesPerCity"/>
    <xsl:with-param name="ptotalDisplayed" select=
    "$ptotalDisplayed
    + $vdispLimit * ($vcntNamesInCity > $vdispLimit )
    + $vcntNamesInCity *(not($vcntNamesInCity > $vdispLimit))"/>

    </xsl:call-template>

    </xsl:if>

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

    when applied on this source.xml:

    <people>
    <person>
    <name>Johnson</name>
    <city>Boston</city>
    <date>1965-02-05</date>
    </person>
    <person>
    <name>Smit</name>
    <city>Lutjebroek</city>
    <date>1975-04-06</date>
    </person>
    <person>
    <name>Peterson</name>
    <city>Boston</city>
    <date>1965-02-05</date>
    </person>
    <person>
    <name>Ackerman</name>
    <city>Boston</city>
    <date>1965-02-05</date>
    </person>
    <person>
    <name>Timmerman</name>
    <city>Lutjebroek</city>
    <date>1975-04-06</date>
    </person>
    <person>
    <name>de la Frost</name>
    <city>Lutjebroek</city>
    <date>1975-04-06</date>
    </person>
    <person>
    <name>Bos</name>
    <city>Lutjebroek</city>
    <date>1975-04-06</date>
    </person>
    <person>
    <name>Lubbers</name>
    <city>Amsterdam</city>
    <date>1975-04-06</date>
    </person>
    <person>
    <name>Veensma</name>
    <city>Amsterdam</city>
    <date>1975-04-06</date>
    </person>

    <!-- etc. -->

    </people>



    produces the wanted result:

    Boston
    Johnson
    Peterson

    Lutjebroek
    Smit
    Timmerman

    Amsterdam
    Lubbers
    Veensma

    It has a total limit of 6 names and a limit of maximum 2 names per city.


    Hope this helped.

    Cheers,

    Dimitre Novatchev [XML MVP],
    FXSL developer, XML Insider,

    http://fxsl.sourceforge.net/ -- the home of FXSL
    Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
     
    Dimitre Novatchev [MVP XML], Feb 22, 2004
    #5

  6. >It has a total limit of 6 names and a limit of maximum 2 names per city.
    >
    >
    >Hope this helped.


    It sure does. Thanksalot!

    Marcel
     
    Marcel Akkerman, Feb 22, 2004
    #6
    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. Edwin G. Castro
    Replies:
    3
    Views:
    3,688
    Edwin G. Castro
    Sep 17, 2004
  2. Replies:
    4
    Views:
    31,797
  3. Replies:
    4
    Views:
    5,806
    Peter Flynn
    Jan 11, 2006
  4. njsimha
    Replies:
    0
    Views:
    443
    njsimha
    Sep 12, 2008
  5. shrek11001
    Replies:
    6
    Views:
    109
    Roy Johnson
    Oct 28, 2003
Loading...

Share This Page