Re: [xsl] For-each loop or recursion

Subject: Re: [xsl] For-each loop or recursion
From: Oleg Konovalov <olegkon@xxxxxxxxx>
Date: Mon, 16 May 2005 19:11:46 -0400
Aron,

Thank you very much.
It was very helpful.

My solution to get was similar, but without Count.

Thanks again,
Oleg.


On 5/16/05, Aron Bock <aronbock@xxxxxxxxxxx> wrote:
> Oleg,
>
>
> >Existing code is very complex - big Cocoon project
>
> Which is why I, among other people, have been asking for a "representative"
> example.  It doesn't have to be your actual XML.  Just make up something
> that's representative.  Making up a representative sample is possible, as
> you'll see at the end of this note.
>
> >(and I started using XSLT 2 weeks ago, but have lots of experience in
> >Java/C/C++), so I tried to keep concentrated on what I am doing:
>
> Nobody's questioning your competency with those languages.  But since you
> mention it, it seems you're giving into the thinking that if you're
> proficient at something, it's an admission of, uh, who knows what, to start
> from basics in another field.  You're saying, "tell me how this is done,
and
> I'm smart enough/nice enough/whatever enough to apply it myself", whereas
> sampes and descriptions you've provided thus far show only that you're
> bringing to bear imperative solutions on declarative problems.  Trust me on
> this--provide a sample, and you'll get all the specific help you need.
>
> >At this point I am interested in how to implement algorithms in XSLT:
> >a) find out first non-zero on either rebate1 and rebate2
> >b) find out first occurrence of max number in either rebate1 or rebate2
>
> This was already answered succintly by a prior respondent, who suggested
you
> use a loop and pick out the first/last element.
>
>
> >So back to my questions:
> >1) How do I get a position of last occurrence of min ?
>
> Many ways, 2 of which may be:
> --locate the node and count its preceding siblings
> --count number of min and adjust
>
> >1a) Can I scan using for-each loop from the end of the sequence
> >to the beginning ?
>
> yes, see <xsl:sort> and its attributes
>
> >2) OK, lets try to get a position of the first occurrence when var2 = max
> >node.
> >What would be a correct ?
> >
> ><xsl:for-each select=mystruct/myarray1[1]/myvar>
> >  <xsl:if select="rebate1=*[last()]">
> >    <xsl:value-of select="position()">
> >  </xsl:if>
> ></xsl:for-each>
> >
> >3) Expanding 2 for the rebate2 (var3) for the values from another
> >(parallel) branch,
> >would that work ?
> >
> ><xsl:for-each select=mystruct/myarray1[1]/myvar>
> >  <xsl:if select="rebate1=*[last()] and
> >      ../../../myarray2[1]/myvar/rebate2=*[last()]">
> >    <xsl:value-of select="position()">
> >  </xsl:if>
> ></xsl:for-each>
> >
> >I think, that second *[last()] is wrong,
> >I have to get a max of the rebate2 (second sequence)
> >before that for-each loop.
> >
> >3a) Can I calculate max of rebate2 like:
> ><xsl:variable name="max2"
> >select="mystruct/myarray2[1]/myvar/rebate2[position()=last()]">
> >Is that the right way of assigning *[last()] to a variable ?
>
> These need more context to respond to with any value.  As a prior
respondent
> said, showing just the XSL is of little use--without the corresponding XML
> it's more often than not futile to comment on its semantics.
>
> Now, using your description below, *I'll* make up XML, and write simple, if
> verbose, XSL to get your results:
>
>
> >column to be displayed [first non-zero on either rebate1 and rebate2]
> >and the last one [first occurrence of max number in either rebate1 or
> >rebate2]
> >
> >                         1    2   3   4  5   6    7   8   9  10  11  12
> >13 (sales volume)
> >rebate1(%)     0   0   1   2   3   4    5   6   7   8    8    8    8
> >rebate2(%)     0   1   2   3   4   5    6   7   9   10  11  11  11
> >
> >Need it be dynamically trimmed to display:
> >
> >                         2   3   4  5   6    7   8   9  10  "11 or more"
> >rebate1(%)     0   1   2   3   4    5   6   7   8    8
> >rebate2(%)     1   2   3   4   5    6   7   9   10  11
> >
> >So if it makes it any easier, we can call it
> >mystruct/myarray1[1]/myvar/rebate1 and
> >mystruct/myarray2[1]/myvar/rebate2
>
> This XML:
>
> <mystruct>
>    <myarray1>
>        <myvar><rebate1>0</rebate1></myvar>
>        <myvar><rebate1>0</rebate1></myvar>
>        <myvar><rebate1>1</rebate1></myvar>
>        <myvar><rebate1>2</rebate1></myvar>
>        <myvar><rebate1>3</rebate1></myvar>
>        <myvar><rebate1>4</rebate1></myvar>
>        <myvar><rebate1>5</rebate1></myvar>
>        <myvar><rebate1>6</rebate1></myvar>
>        <myvar><rebate1>7</rebate1></myvar>
>        <myvar><rebate1>8</rebate1></myvar>
>        <myvar><rebate1>8</rebate1></myvar>
>        <myvar><rebate1>8</rebate1></myvar>
>    </myarray1>
>    <myarray2>
>        <myvar><rebate2>0</rebate2></myvar>
>        <myvar><rebate2>1</rebate2></myvar>
>        <myvar><rebate2>2</rebate2></myvar>
>        <myvar><rebate2>3</rebate2></myvar>
>        <myvar><rebate2>4</rebate2></myvar>
>        <myvar><rebate2>5</rebate2></myvar>
>        <myvar><rebate2>6</rebate2></myvar>
>        <myvar><rebate2>7</rebate2></myvar>
>        <myvar><rebate2>9</rebate2></myvar>
>        <myvar><rebate2>10</rebate2></myvar>
>        <myvar><rebate2>11</rebate2></myvar>
>        <myvar><rebate2>11</rebate2></myvar>
>        <myvar><rebate2>11</rebate2></myvar>
>    </myarray2>
> </mystruct>
>
> With this XSL:
>
> (This could be shortened, but I'm unwilling to put in any more time w/
> guessed-at data)
>
> <?xml version="1.0" encoding="iso8859-1"?>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>    <xsl:output method="text"/>
>
>    <xsl:template match="/">
>        <xsl:call-template name="raw-data"/>
>        <xsl:text>&#xa;</xsl:text>
>        <xsl:call-template name="trimmed-data"/>
>    </xsl:template>
>
>    <xsl:template name="raw-data">
>        <xsl:text>raw data (sorted)&#xa;</xsl:text>
>        <xsl:text>rebate1 </xsl:text>
>        <xsl:apply-templates select="mystruct/myarray1/myvar/rebate1">
>            <xsl:sort data-type="number" select="."/>
>        </xsl:apply-templates>
>        <xsl:text>&#xa;</xsl:text>
>
>        <xsl:text>rebate2 </xsl:text>
>        <xsl:apply-templates select="mystruct/myarray2/myvar/rebate2">
>            <xsl:sort data-type="number" select="."/>
>        </xsl:apply-templates>
>        <xsl:text>&#xa;</xsl:text>
>    </xsl:template>
>
>    <xsl:template name="trimmed-data">
>        <!-- pos of first non-zero rebate1 -->
>        <xsl:variable name="pr1"
> select="count(mystruct/myarray1/myvar/rebate1[. &lt;= 0]) + 1"/>
>
>        <!-- pos of first non-zero rebate2 -->
>        <xsl:variable name="pr2"
> select="count(mystruct/myarray2/myvar/rebate2[. &lt;= 0]) + 1"/>
>
>        <!-- pos of first non-zero rebate* -->
>        <xsl:variable name="pr">
>            <xsl:choose>
>                <xsl:when test="$pr1 &lt;= $pr2">
>                    <xsl:value-of select="$pr1"/>
>                </xsl:when>
>                <xsl:otherwise>
>                    <xsl:value-of select="$pr2"/>
>                </xsl:otherwise>
>            </xsl:choose>
>        </xsl:variable>
>
>        <!-- max rebate1 -->
>        <xsl:variable name="mr1">
>            <xsl:for-each select="mystruct/myarray1/myvar/rebate1">
>                <xsl:sort data-type="number" select="."/>
>                <xsl:if test="position() = last()">
>                    <xsl:value-of select="."/>
>                </xsl:if>
>            </xsl:for-each>
>        </xsl:variable>
>
>        <!-- pos first max rebate1 -->
>        <xsl:variable name="pmr1"
> select="count(mystruct/myarray1/myvar/rebate1[. &lt; $mr1]) + 1"/>
>
>        <!-- max rebate2 -->
>        <xsl:variable name="mr2">
>            <xsl:for-each select="mystruct/myarray2/myvar/rebate2">
>                <xsl:sort data-type="number" select="."/>
>                <xsl:if test="position() = last()">
>                    <xsl:value-of select="."/>
>                </xsl:if>
>            </xsl:for-each>
>        </xsl:variable>
>
>        <!-- pos first max rebate2 -->
>        <xsl:variable name="pmr2"
> select="count(mystruct/myarray2/myvar/rebate2[. &lt; $mr2]) + 1"/>
>
>        <!-- pos of greater max rebate* -->
>        <xsl:variable name="pmr">
>            <xsl:choose>
>                <xsl:when test="$pmr1 &gt;= $pmr2">
>                    <xsl:value-of select="$pmr1"/>
>                </xsl:when>
>                <xsl:otherwise>
>                    <xsl:value-of select="$pmr2"/>
>                </xsl:otherwise>
>            </xsl:choose>
>        </xsl:variable>
>
>        <xsl:text>trimmed data&#xa;</xsl:text>
>        <xsl:text>rebate1 </xsl:text>
>        <xsl:for-each select="mystruct/myarray1/myvar/rebate1">
>            <xsl:if test="position() &gt;= $pr and position() &lt;= $pmr">
>                <xsl:apply-templates select="."/>
>            </xsl:if>
>        </xsl:for-each>
>        <xsl:text>&#xa;</xsl:text>
>
>        <xsl:text>rebate2 </xsl:text>
>        <xsl:for-each select="mystruct/myarray2/myvar/rebate2">
>            <xsl:if test="position() &gt;= $pr and position() &lt;= $pmr">
>                <xsl:apply-templates select="."/>
>            </xsl:if>
>        </xsl:for-each>
>        <xsl:text>&#xa;</xsl:text>
>    </xsl:template>
>
>    <xsl:template match="rebate1">
>        <xsl:value-of select="."/>
>        <xsl:text> </xsl:text>
>    </xsl:template>
>
>    <xsl:template match="rebate2">
>        <xsl:value-of select="."/>
>        <xsl:text> </xsl:text>
>    </xsl:template>
>
> </xsl:stylesheet>
>
> Produces:
>
> raw data (sorted)
> rebate1 0 0 1 2 3 4 5 6 7 8 8 8
> rebate2 0 1 2 3 4 5 6 7 9 10 11 11 11
>
> trimmed data
> rebate1 0 1 2 3 4 5 6 7 8 8
> rebate2 1 2 3 4 5 6 7 9 10 11
>
> Regards,
>
> --A
>
> _________________________________________________________________
> Express yourself instantly with MSN Messenger! Download today - it's FREE!
> http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/

Current Thread