Re: [xsl] counting preceding identical elements

Subject: Re: [xsl] counting preceding identical elements
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Mon, 27 Aug 2001 12:24:36 -0400
Steven,

It's not that position() is "bad practice" -- actually, it can be very good practice. The reason it's dangerous is because understanding the way it works depends on a good grasp of how parameters like the context node and the current node set are determined by the processor. If you don't have this deeper grasp of XPath, you'll be left guessing how position() works, and you'll usually guess wrong. Yours is a perfect case in point. For example,

count(//section[position()=$section]/preceding::sibling[position()=$slide])

won't give you anything useful, although it's a correctly formed XPath location path. Specifically, the step

preceding::sibling[position()=$slide]

looks for all elements named 'sibling' before the context node (of the step, which will be a 'section' element), taking only those whose position *among the preceding elements named 'sibling', counting in reverse document order away from the section* (since the preceding axis is a 'reverse' axis), is equal to $slide. That isn't what you want at all. Typing "preceding::sibling" when you probably meant "preceding-sibling::slide" is part of the problem (not that that's what you want, since I don't think your sections have slides as preceding siblings, and even if they did, that's not what you want to count). But the way position() works is also getting you into trouble.

Now, to how to solve the problem. You say

What I basically try to do is to calculate the number of preceding slide
elements of the slide element which position()=$slide and of which the
parent section element's position()=$section.

As you seem to have surmised, this is much easier to do if your slide is the context node, than when it is not. The solution is to go ahead and change contexts, for this operation. Changing contexts can be done with an xsl:for-each. For example:


<xsl:variable name="absolute-slide-number">
<xsl:for-each select="//section[position()=$section]/slide[position()=$slide]">
<xsl:value-of select="count(preceding::slide)+1"/>
</xsl:for-each>
</xsl:variable>


This will give you the count of all slides preceding your target slide, in all sections. Is that what you wanted?

<xsl:number> is also another way to go, but it too will require you to change your current node. Your efforts in that direction haven't worked because you apparently don't know how the 'count' attribute works there (it doesn't specify the node whose position you want, but the type of nodes you want to count, using a match pattern). Try <xsl:number count="slide" level="any"/>.

If I'm guessing wrong about what you need, please post again with a clarification of your requirements (maybe a fuller code sample).

Good luck,
Wendell

At 06:21 PM 8/24/01, you wrote:
Hi,

I am at loss whether what I am trying to do is at all possible. I would be
able to do it in some other way, but this would mean major rearrangements
to what I have so far, and I would prefer to keep things the way they are.

I am building a simple Powerpoint-style presentation tool running on top
of Cocoon.

My XML-structure is simple:

<presentation>
        <info>...</info>
        <body>
                <section>
                        <slide>...</slide>
                        <slide>...</slide>
                        ...
                </section>
                <section>
                        yes, same stuff here
                        ...
                </section>
        </body>
</presentation>

Using Cocoon's clever parameter-passing, I can access each individual
slide using a section and slide number passed through to the stylesheet,
using URL's like
http://localhost/cocoon/presentation/browse?section=2&slide=4

This is all working very nice. Using a main 'presentation' template, I
build the HTML grid and then <xsl:apply-templates
select="body/section[position()=$section]/slide[position()=$slide]"/>.

Outside of the node context created by this template however, I want to
build a little progress indicator showing how far I am in my presentation.

This little portion does most of what I want it to do:


<b><xsl:value-of select="$section"/></b> <font size="-1" color="gray">/<xsl:value-of select="count(//section)"/></font>&#160; <font size="+2"><b>|</b></font>&#160; <font size="-1"><xsl:value-of select="$slide"/> <font color="gray">/ <xsl:value-of select="count(//section[position()=$section]/slide)"/> </font> </font>

builds up a something like this:

2/ 3 | 4/ 6

which is fine, but only depending on the parameters passed into the
stylesheet ($section and $slide).

The last thing I want to add to the indicator is a percentage - roughly
calculated by dividing the number of preceding slides by the total amount
of slides.

And now I fall into problems because this isn't happening when the context
node 'focus' is on the slide element but outside the main loop.

What I basically try to do is to calculate the number of preceding slide
elements of the slide element which position()=$slide and of which the
parent section element's position()=$section.

But I get all kinds of odd numbers - can't really figure out what is
wrong in my count() argument.

I've been trying
count(//section[position()=$section]/preceding::sibling[position()=$slide])
to no avail.

Then I switched strategies into abusing <xsl:number> like:
<xsl:number level="any" count="//section[$section]/slide[$slide]"/>
but that made not much sense neither.

A long story to ask whether what I am trying to do is really feasible when
not at the slide element itself but only with the basic knowledge that
there IS a fourth slide in section 2 due to the parameters.

Any ideas?

I know using position() is considered to be bad practice. Punish me :-)

Regards,
</Steven>


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list



Current Thread