Using XPath generate-id() with XSLT to create links within your XML content

XPath’s generate-id() function is useful for simple links

XSLT for the Modern Web
4 min read4 days ago

In this example we will make a transformation which includes HTML <a href> (hyperlinks) and <a id> (anchor) links, using XPath generate-id() function.

As with most of the posts in this series and disclaimer is given that just because you can use a particular function/method — it may not always be the case that this is a good idea in practice.

This example of using XPath generate-id() is probably more useful in a offline context where there is a necessity to form a link between and hyperlink and id once, and for this to remain static — for example as a connection between tables of contents in an eBook and text content — rather than online context.

The strings generated by generate-id() are fairly limited, not static upon each transformation, and not likely to be useful in a SEO context where the value of the links could be useful.

Anyway, lets put those point to one side, because generate-id() is a useful XPath feature to apply in XSLT.

XSLT for the Modern Web — Re-visiting XSLT in the modern website landscape

Example XML document

Here is an example XML document (simplified for the sake of this example), with a top level <history> element, <period> element and multiple <person> elements.

In this case the <person> elements are used to contain information about the Roman Emperors, and we have to imagine some lengthy text context about their lives and achievements would be contained therein.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="generateid.xsl"?>
<history>
<period from="27BCE" to="476CE" name="Roman Empire">
<person name="Octavian" knownas="Augustus" focusdate="27-14CE">
[ text content ]
</person>
<person name="Tiberius" role="Emperor" focusdate="14-37 BCE">
[ text content ]
</person>
<person name="Caligula" role="Emperor" focusdate="41-54 BCE">
[ text content ]
</person>
<person name="Nero" role="Emperor" focusdate="54-68 BCE">
[ text content ]
</person>
<person name="Vespasian" role="Emperor" focusdate="69-79 BCE">
[ text content ]
</person>
<person name="Titus" role="Emperor" focusdate="79-81 BCE">
[ text content ]
</person>
<person name="Domitian" role="Emperor" focusdate="81-96 BCE">
[ text content ]
</person>
<person name="Marcus Cocceius Nerva" role="Emperor" focusdate="96-98 BCE">
[ text content ]
</person>
<person name="Trajan" role="Emperor" focusdate="98-117 BCE">
[ text content ]
</person>
<person name="Hadrian" role="Emperor" focusdate="117-138 BCE">
[ text content ]
</person>
<person name="Antonius Pius" role="Emperor" focusdate="138-161 BCE">
[ text content ]
</person>
<person name="Marcus Aurelius" role="Emperor">
[ text content ]
</person>
<person name="Commodus" role="Emperor" focusdate="180-192 BCE">
[ text content ]
</person>
<person name="Septimus Severus" role="Emperor" focusdate="193- BCE">
[ text content ]
</person>
<person name="Diocletian" role="Emperor" focusdate="284-305 BCE">
[ text content ]
</person>
<person name="Constantine" role="Emperor" focusdate="312-337 BCE">
[ text content ]
</person>
<person name="Theodosius I" role="Emperor" focusdate="379-395 BCE">
[ text content ]
</person>
</period>
</history>

Now for the XSLT stylesheet. You’ll note here we are using the ‘pull’ XSLT approach towards stylesheets, using <xsl:apply-templates select> to pull in the desired transformation upon <person> elements.

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

<xsl:output method="xml"/>

<xsl:template match="/">
<html lang="en">
<head>
<title>XPath generate-id()</title>
</head>
<body>
<ul>
<xsl:apply-templates select="history/period/person" mode="link"/>
</ul>
<xsl:apply-templates select="history/period/person" mode="section"/>
</body>
</html>
</xsl:template>

<xsl:template match="person" mode="link">
<li>
<a href="#{generate-id(current())}">
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:template>

<xsl:template match="person" mode="section">
<section>
<a id="{generate-id(current())}">
<xsl:value-of select="."/>
<br/>
</a>
</section>
</xsl:template>

</xsl:stylesheet>

This stylesheet is makes use of modes.

None of my other posts have touched upon modes but they can be useful where there is a requirement to transform an element or elements multiple times but differently — in this case the <person> elements are matched once to generate the hyperlinks <a href> and then a second time to generate the anchors <a id>.

The generate-id() function is an XPath function which can be used in an XSLT context. Essentially it returns a unique string which can be used as an id identifier — the format is up to XPath and the execution engine (so you have to consider each time the transformation is applied the id’s will be different — another reason why generate-id() may not always be useful in a website context).

The current() function provides a value reference to the element that is currently being matched within the template scope.

In this case, because the <person> elements are called twice — once for generating the hyperlink and a second time for generating the anchor — the current() function returns the same value.

In other words, when the template below

<xsl:template match="person" mode="link">
<li>
<a href="#{generate-id(current())}">
<xsl:value-of select="@name"/>
</a>
</li>
</xsl:template>

Matches on the element…

<person name="Octavian" knownas="Augustus" focusdate="27–14CE">
[ text content ]
</person>

The value of the current() function is the same as when the template…

<xsl:template match="person" mode="section">
<section>
<a id="{generate-id(current())}">
<xsl:value-of select="."/>
<br/>
</a>
</section>
</xsl:template>

Matches on the element..

<person name="Octavian" knownas="Augustus" focusdate="27–14CE">
[ text content ]
</person>

This ensures that when the transformation is applied, we get a series of <a href> hyperlinks and <a id> anchors that have matching values.

i.e

<a href=”#id0x3208280">Octavian</a>

Which then links to:

<a id=”id0x3208280">
[ text content ]
</a>

Hopefully this hasn’t completely tied your brain in knots. If you want to learn more about XSLT, take a look at the posts:

If you want to learn more about XSLT, how to use it and understand its place in the Modern Web — follow to learn more.

Beginners XSLT patterns so far:

--

--

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