How to use <xsl:key> to perform a simple lookup in XSLT

Performing a simple lookup is a useful XML/XSLT pattern — lets look at matching an element in one XML document with a value/attribute in another XML document

XSLT for the Modern Web
3 min readAug 11, 2024
XSLT for the Modern Web — Re-visiting XSLT in the modern website landscape

Example — matching element value to attribute value

document.xml

In this XML document we have a simple list of <lookup> elements within a <history> element. The aim will be to use the value of the <lookup> elements to pull in content from a different XML document (index.xml) during an XSLT transformation.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="key-index.xsl"?>
<history>
<lookup>Tiberius</lookup>
<lookup>Caligula</lookup>
<lookup>Nero</lookup>
<lookup>Claudius</lookup>
</history>

index.xml

Here is a simple XML document with a list of <entry> elements with attribute “name” and the value of the attributes match the values of the elements in the document.xml.

<?xml version="1.0" encoding="UTF-8"?>
<index>
<entry name="Tiberius">Tiberius (Tiberius Julius Caesar Augustus) was emperor from AD 14 until 37.</entry>
<entry name="Caligula">Caligula (Gaius Caesar Augustus Germanicas) was emperor from AD 37 until his assassination in AD 41.</entry>
<entry name="Claudius">Claudius (Tiberius Claudius Caesar Augustus) ruled from AD 41 to 54.</entry>
<entry name="Nero">Nero (Claudius Caesar Augustus Germanicas) was the final emperor of the Julio-Claudian dynasty, reigning from AD 54 until AD 68.</entry>
</index>

What we want to achieve in our XSLT transformation is a Lookup from index.xml, given the values in document.xml e.g. — we want to <lookup>Claudius</lookup> in document.xml should pull in the value of <entry name=”Claudius”>…</entry> in index.xml

key-index.xsl

Below is just one way to achieve this lookup using XSLT keys, a matching template on <lookup>, a <xsl:for-each> and <xsl:apply-templates select>.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:key name="lookup" match="entry" use="@name"/>

<xsl:template match="lookup">
<xsl:variable name="name" select="."/>
<xsl:for-each select="document('index.xml')">
<xsl:apply-templates select="key('lookup', $name)"/>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

The <xsl:key> sets up a key which matches on <entry> and uses the attribute “name”. Notice that at this point in the document, the stylesheet does not know where the <entry> elements are.

<xsl:key name="lookup" match="entry" use="@name"/>

The key-index.xsl is applied from document.xml so the <xsl:template match=”lookup”> comes into play as the XSLT Processor identifies each <lookup> element.

<xsl:template match="lookup">
<xsl:variable name="name" select="."/>
<xsl:for-each select="document('index.xml')">
<xsl:apply-templates select="key('lookup', $name)"/>
</xsl:for-each>
</xsl:template>

Once the element <lookup> is matched, the value of the element is assigned to the <xsl:variable> variable “name” — this is just make the key() function cleaner.

Next there is a <xsl:for-each> loop which loads the document(‘index.xml’) into the XSLT stylesheet.

There’s a bit of context magic going on here. Note that the XPath function document(“index.xml”) set the context of the following <xsl:apply-templates to index.xml NOT document.xml.

<xsl:for-each select="document('index.xml')">
//the context is index.xml
<xsl:apply-templates select="key('lookup', $name)"/>
</xsl:for-each>

The key function is then looking up within index.xml. Recall that the key was defined as:

<xsl:key name="lookup" match="entry" use="@name"/>

Which is matching the <entry> elements in index.xml.

<?xml version="1.0" encoding="UTF-8"?>
<index>
<entry name="Tiberius">Tiberius (Tiberius Julius Caesar Augustus) was emperor from AD 14 until 37.</entry>
<entry name="Caligula">Caligula (Gaius Caesar Augustus Germanicas) was emperor from AD 37 until his assassination in AD 41.</entry>
<entry name="Claudius">Claudius (Tiberius Claudius Caesar Augustus) ruled from AD 41 to 54.</entry>
<entry name="Nero">Nero (Claudius Caesar Augustus Germanicas) was the final emperor of the Julio-Claudian dynasty, reigning from AD 54 until AD 68.</entry>
</index>

If this didn’t turn your brain in knots and you want to learn more about XSLT, how to use it and understand its place in the Modern Web — follow to learn more.

--

--

XSLT for the Modern Web

Re-learning XSLT in the context of the Modern Web - occassional writer, reader, Digital Humanities enthusiast All text is 100% non-AI - learn, explore, reuse