This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Understanding xsl:key


Heiner,

When you define the key:

> <xsl:key name="test" match="title" use="name"/>

Then you are setting up a number of associations between 'title' nodes and
key values given to them through their 'name' child:

node		key value
title[1]	'Design Patterns'
title[2]	'Pattern Hatching'
title[3]	'Building Applications'

When you use:

  key('test', 'Pattern Hatching')

you are saying "What nodes within the 'test' key have the key value of
'Pattern Hatching'?"

The answer is always the second title (in your example), so that node is
always returned as a result.

When you test on that node as in:

  <xsl:if test="key('test', 'Pattern Hatching')">
    ...
  </xsl:if>

then the test expression is evaluated and then converted to a boolean.
When node sets are converted to a boolean value, they return true() if
there is a node in the node set, and false() if not.  In your case, since
the key() does return a node, the test is always true, so the contents of
xsl:if are always used, and you get information about all the books.

>Now, I'd expect the xsl:if to make sure only "name" elements that are 
>children of "title" and have the content "Pattern Hatching"  are 
>shown.

If you are matching all books, as you are here, then it's easy to test
whether a book that you have has a 'title' child with a 'name' child that
has a content of 'Pattern Hatching'.  You don't need key() to do it:

  <xsl:if test="title/name = 'Pattern Hatching'">
    ...
  </xsl:if>

Keys are really useful for *selecting* nodes that you want to process.  So
if you only wanted to process the book with the title 'Pattern Hatching',
then you could use something like:

<xsl:template match="booklist">
  <booklist>
    <xsl:apply-templates
        select="key('test', 'Pattern Hatching')" />
  </booklist>
</xsl:template>

<xsl:template match="title">
  <node>
    <xsl:value-of select="name" />
  </node>
</xsl:template>

If you want to give any information about the book aside from its title,
you also may be better off changing your key so that it matches on *books*
rather than on their *titles*.  The match expression for a key should match
the nodes that you're actually interested in, rather than one of their
children, or an attribute.  It's the 'use' expression that lets you select
*what* is interesting about the node (e.g. the name child of the title child):

<xsl:key name="test" match="book" use="title/name" />

and then:

<xsl:template match="booklist">
  <booklist>
    <xsl:apply-templates select="key('test', 'Pattern Hatching')" />
  </booklist>
</xsl:template>

<xsl:template match="book">
  <node>
    <xsl:value-of select="title/name" />
  </node>
</xsl:template>

I hope that this clears things up somewhat.

Cheers,

Jeni

Jeni Tennison
http://www.jenitennison.com/



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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]