After being "woken up" to a fresh breath of "oh my goodness did I really
swing and miss before the ball even crossed the plate" I am now ready to
take on my day :) Thanks David for keeping me honest on this one...
Howard Schultz is unfortunately going to have to reevaluate his profit loss
statement for the day as the 5 dollars I had planned to contribute to the
other Seattle monopoly for a dose of The Emerald Cities finest rise and
shine elixir (naturally occuring caffeine being a fantastic substitute for
the part normally played by the Sun) is being stapled to 5 more just like
them and dropped off at my local Barnes and Noble in exchange for a copy of
"the complete idiots guide to XSLT" (do they make one of those?) as it
appears it would probably be in my best interest... ;)
For those of you keeping score at home David is more than correct in his
suggestion to use keys to select both the first instance of an occurence
within an XML document as well as all subsequent occurencess following in
document order... And as he mentioned Jeni's site shows several great
examples of using the Muenchian method for selecting and grouping in such a
manner...
One thing to make a note of when you are using the contains() function (as
was the case in this post) however is that the function itself is only going
to compare the value of the first occurence of an element even if it is
passed a set of nodes instead of just one. This is one of those gotchas
that can sometimes nab you if youre not paying attention and relying on the
result of something like...
<xsl:if test="contains(preceding-sibling::foo, 'bar')>do something</xsl:if>
to evaluate each preceding foo sibling and return true or false accordingly.
It doesnt... it only will evaluate the value of the first matching element
and return true or false based on a test of that node and that node only.
Given the fact
<xsl:if test="preceding-sibling::foo = 'bar'">do something else</xsl:if>
will evaluate each preceding foo sibling and return true if any of the foo
elements value is = 'bar' it's easy to see why this could catch even the
most seasoned XSLT professional from time to time.
Although this may seem rediculous at first glance (form a human logic
standpoint in many ways they seem almost interchangeable beyond the fact
that one method tests for an occurence and the other tests for equality) a
quick glance at the String Functions section of the XPath specification
reveals exactly why this is... http://www.w3.org/TR/xpath#function-string
The first list item in this sections states very plainly: "A node-set is
converted to a string by returning the string-value of the node in the
node-set that is first in document order. If the node-set is empty, an empty
string is returned."
If you scroll down just a bit you will find a definition for all of the
string related functions of XPath. Function: boolean contains(string,
string) is defined as such...
"The contains function returns true if the first argument string contains
the second argument string, and otherwise returns false."
Given that less than a page before this we were told that a node-set is
converted to a string by returning the string-value of the first node in
document order we can now see why the contains function limits the XPath
statement preceding-sibling::foo to only the first occurence... It doesnt
look at the XPath statement in the same way the XSLT processor looks at
it... it simply realizes that to complete its task of looking for an
instance of a string inside another string it first needs to make an attempt
at casting any non-string types to a string type and then make the
comparison. When the function receives the return value from the cast it
makes its comparison, returns true or false based on its findings, and then
kicks back until such time as a string comparison between two strings is
needed again.
Anyway, I didnt mean to try an take away from David's original point that
this problem could be solved by using keys to group common elements. But I
have been caught by the contains() function gothcha enough times to want to
make sure that this portion of the posted problem was explained in a way as
to allow the proper usage of keys for grouping when using the contains()
function to search for an occurence instead of doing direct string
comparisons as is the normal case when implementing any sort of grouping
solution using the Meunchian method.
Thanks again for catching this David! :)
Best regards,
<M:D/>
----- Original Message -----
From: "David Carlisle" <davidc(_at_)nag(_dot_)co(_dot_)uk>
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
Sent: Monday, July 19, 2004 3:18 AM
Subject: Re: [xsl] Retaining value of a Global variable
Solution 2 - The second solution requires utilization of the
preceding-sibling
axis in XPath. The problem with using preceding-sibling in any sort of
test is
as the processor continues through the tree another preceding-sibling is
added
to the list of preceding-siblings. This test will evaluate each and
every
preceding-sibling so it doesnt take long for performance to become a BIG
issue.
this is essentially why "muenchiam grouping" using keys is a big win.
The original posters (rephrased) problem sounds like the canonical use
case for the grouping techniques (as explaied at
www.jenitennison.com/xslt/grouping)
David
________________________________________________________________________
This e-mail has been scanned for all viruses by Star Internet. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________
--+------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--+--