[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Key function using key strings from msxsl:node-set generated node. Doesn't work?


Subject: Re: [xsl] Key function using key strings from msxsl:node-set generated node. Doesn't work?
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 15 Mar 2002 10:44:21 +0000

Hi Malcolm,

> I have a baffling problem. I'm trying to call the key function using
> strings extracted from nodes coming from the msxsl:node-set
> function. No matter what I try (i.e. normalize-space etc) I can't
> get the same string from msxsl:node-set as I do from the raw XML.

Whitespace is one possible problem, but I think that the real issue
that you're running into here is the fact that the key() function only
searches the document containing the current node for nodes matching
the key value. You do:

> <xsl:for-each select="msxsl:node-set($UniqueAddressStrings)/Address">
>   <xsl:sort select="."/>
>   <tr>
>     <td>
>       <xsl:value-of select="normalize-space(.)"/>
>     </td>
>     <td>
>       <xsl:value-of select="count(key('PersonByAddress',normalize-space(.)))"/>
>     </td>
>   </tr>
> </xsl:for-each>

Within the xsl:for-each, the current node is an Address element from
the $UniqueAddressStrings document. When you use the 'PersonByAddress'
key within the xsl:for-each, it's the $UniqueAddressStrings document
that's searched.

You need to store the value of the address in a variable, then switch
context back to the source document, then use the key. To make this
possible, store the root node of the source document in a global
variable:

<xsl:variable name="people" select="/" />

Then within the xsl:for-each, create a variable holding the value of
the address:

  <xsl:for-each select="msxsl:node-set($UniqueAddressStrings)/Address">
    <xsl:sort select="."/>
    <xsl:variable name="address" select="normalize-space()" />
    <tr>
      <td>
        <xsl:value-of select="$address"/>
      </td>
      <td>
        ...
      </td>
    </tr>
  </xsl:for-each>

And when you want to get the value using the key, use an xsl:for-each
as a 'with' to switch back into the context of the source document,
and call the key within that:

  <xsl:for-each select="msxsl:node-set($UniqueAddressStrings)/Address">
    <xsl:sort select="."/>
    <xsl:variable name="address" select="normalize-space()" />
    <tr>
      <td>
        <xsl:value-of select="$address"/>
      </td>
      <td>
        <xsl:for-each select="$people">
          <xsl:value-of
            select="count(key('PersonByAddress', $address))" />
        </xsl:for-each>
      </td>
    </tr>
  </xsl:for-each>

Gennady is correct that you should make sure that the expression you
use the use attribute of the xsl:key matches the one that you use when
you try to retrieve the value of the key. If you're using
normalize-space() in the rest of the code, you should use
normalize-space() there for safety:

<xsl:key name="PersonByAddress" match="/People/Person"
         use="normalize-space(Address)" />

Cheers,

Jeni

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


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



Current Thread