Re: Key()

Subject: Re: Key()
From: Richard Light <richard@xxxxxxxxxxxxxxxxx>
Date: Wed, 28 Jun 2000 09:31:15 +0100
In message <3959B9F9.252AAE25@xxxxxxxxxxxxxx>, Rhonda Fischer <rhonda@n-
space.com.au> writes
>
>I have been drawing result trees and applying XPath expressions
>in an endeavour to fully understand how my use of the key()
>function is working. But still the outcome is not quite right.
>Not only is there an ordering problem but also my index
>seems to contain only a duplication of the first paragraph.
>Perhaps I am missing something obvious?

><Template>
>    <Destination>
>         <Target doc="contract"/>
>          <Target doc="advice"/>
>          <Target host="true"/>
>          <Section><SectionHeading>My Heading
>                                 </SectionHeading></Section>
>          <Para>
>               This paragraph appears in both the contract
>                and advice documents and is only included
>                for those customers hosting.
>          </Para>

>Transform.xsl
>-----------
>
><xsl:key name="blueprint" match="Para"
>      use="concat(preceding-sibling::Target/@doc, '-',
>                               preceding-sibling::Target/@host)"/>

Your first preceding-sibling expression asks for all the 'doc'
attributes of Target elements preceding the Para currently in scope.
Since you have three Target elements, this will yield a node-set
containing three 'doc' attribute nodes (in reverse order).  

Putting that node-set inside a 'concat' function causes the node-set to
be converted to a string.  This is done by providing "the string value
of the node that is first in document order" (quote from Mike Kay's XSLT
Programmer's Reference - an indispensible source - p509).

Thus, according to the letter of the law, you should get the value
'contract' for this part of the 'concat' expression.  However, I find
this counter-intuitive - it would make more sense to me to provide the
value of the first node in the node-set, which in this case is an empty
string since the last Target has no 'doc' attribute.

What you probably want is a test that the nodes in your node-sets
actually have the attribute you are interested in:

<xsl:key name="blueprint" match="Para"
      use="concat(preceding-sibling::Target[@doc]/@doc, '-',
                               preceding-sibling::Target[@host]/@host)"/
>

In addition, you might want to specify that you just want the first node
in that node-set (to deal with the case where there is more than one
Target with the required attribute):

<xsl:key name="blueprint" match="Para"
      use="concat(preceding-sibling::Target[@doc]/@doc[1], '-',
                               preceding-sibling::Target[@host]/@host[1]
)"/>

Hope this moves things forward!

Richard Light.

Richard Light
SGML/XML and Museum Information Consultancy
richard@xxxxxxxxxxxxxxxxx


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


Current Thread