Using xsl:key to find an attribute from a matched child

4.8k views Asked by At

Fairly new to XSL - so please forgive noobishness.

I have an input XML document (this is actually the docbook form of the Jargon File, snipped significantly):

<?xml version="1.0" encoding="ISO-8859-1"?>
<glossary>
    <glossdiv id='glossdiv-0'>
        <title>0</title>            
        <glossentry id='dev-null'>
            <glossterm>/dev/null</glossterm>
            <glossdef>
                snip...
                <glossterm>bit bucket</glossterm>
            </glossdef>
        </glossentry>
        <glossentry id='me'>
            <glossterm>/me</glossterm>
            <glossdef>
                snip...
                <glossterm>/dev/null</glossterm>
            </glossdef>
        </glossentry>           
    </glossdiv>
</glossary>

This is the testing XSL I've been working with:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xalan="http://xml.apache.org/xalan"
    version="2.0">

    <xsl:output indent="yes" xalan:indent-amount="5" />
    <xsl:template match="text()" />

    <xsl:key name="glossterm-lookup-key" match="glossentry/@id" use="glossentry/glossterm" />

    <xsl:template match="glossary" >
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="glossterm">
        Key: <xsl:value-of select="." />
        Value: <xsl:value-of select="key('glossterm-lookup-key', .)" />
        <xsl:text>
        </xsl:text>
    </xsl:template>
</xsl:stylesheet>

My objective, is that whenever I come across a <glossterm> element, I'd like to lookup the glossentry/@id given the glossterm/text(). So, for example, if I find a <glossterm>/dev/null</glossterm>, I'd like to get dev-null.

I'm only really interested in glossterms in a glossdef, but I have working xsl:templates for all that stuff - for the sake of testing I've just been working on all glossterms.

I have tried creating a separate lookup document and using the approach described at XML.com: Reading Multiple Input Documents but had no luck with that.

Any hints?

2

There are 2 answers

1
Jim Garrison On BEST ANSWER

It's a little hard to tell from your description but I think you want this

<xsl:key name="glossterm-lookup-key" match="glossentry/glossterm" use="text()" />

This creates an index of glossentry/glossterm nodes keyed on the text of the child glossterm. The reference is then:

<xsl:value-of select="key('glossterm-lookup-key', .)/../@id" />

This uses the current context node's text to search the index and returns the @id of the parent.

0
AudioBubble On

Besides @Jim Garrison's correct answer, this is the explanation of your problem.

From http://www.w3.org/TR/xslt#key

The use attribute is an expression specifying the values of the key; the expression is evaluated once for each node that matches the pattern.

That means that your key declaration should be:

<xsl:key name="glossterm-lookup-key" 
         match="glossentry/@id" 
         use="../glossterm" />