What Is the Purpose of generate-id() in XSLT?
The generate-id() function in XSLT produces a unique
alphanumeric string identifier for a specified node in an XML document.
It serves as a foundational utility in XSLT stylesheets, primarily used
to test whether two node references point to the exact same node in the
source tree, build internal hyperlinks and cross-references in output
formats like HTML, and enable advanced grouping techniques such as
Muenchian grouping.
Understanding the generate-id() Function
In XSLT, the generate-id() function accepts an optional
node-set as an argument. When passed a node (or evaluated against the
context node if no argument is provided), it returns an
implementation-dependent string that uniquely identifies that specific
node throughout a single transformation run.
<!-- Generates a unique string for the current context node -->
<xsl:value-of select="generate-id()" />
<!-- Generates a unique string for a specific node in a variable or node-set -->
<xsl:value-of select="generate-id($targetNode)" />If the argument is an empty node-set, the function returns an empty string. If multiple nodes are passed, it generates an ID for the first node in document order.
Node Identity Comparison
XSLT 1.0 lacks a dedicated operator for comparing node identity. In
XPath 1.0, the equality operator (=) compares string values
rather than references, meaning two completely separate XML elements
with identical text content evaluate as equal.
<!-- This checks if text content matches, NOT if they are the exact same node -->
<xsl:if test="$nodeA = $nodeB"> ... </xsl:if>To determine whether $nodeA and $nodeB
represent the identical node in the document hierarchy,
generate-id() converts node identity into a distinct
string:
<!-- True only if $nodeA and $nodeB are the exact same node -->
<xsl:if test="generate-id($nodeA) = generate-id($nodeB)">
<!-- Identical node logic -->
</xsl:if>In XSLT 2.0 and later, the is operator
($nodeA is $nodeB) was introduced to compare node identity
directly, but generate-id() remains widely used for
backward compatibility and specialized cross-referencing.
Cross-Referencing and Hyperlink Generation
When transforming XML into presentation formats like HTML or SVG, stylesheets frequently require matching anchor tags, footnotes, table-of-contents links, and cross-references.
Because generate-id() returns the exact same string
every time it is called on a given node within the same transformation,
it provides a deterministic way to construct matching id
and href attributes without needing to maintain manual
counters or parse complex hierarchy paths.
<!-- Table of contents linking to sections -->
<xsl:template match="document">
<nav class="toc">
<ul>
<xsl:for-each select="section">
<li>
<a href="#{generate-id()}">
<xsl:value-of select="title" />
</a>
</li>
</xsl:for-each>
</ul>
</nav>
<main>
<xsl:apply-templates select="section" />
</main>
</xsl:template>
<!-- Section target template -->
<xsl:template match="section">
<section id="{generate-id()}">
<h2><xsl:value-of select="title" /></h2>
<xsl:apply-templates select="content" />
</section>
</xsl:template>Grouping with the Muenchian Method
Before native grouping constructs like
<xsl:for-each-group> were introduced in XSLT 2.0, the
standard way to group items efficiently in XSLT 1.0 was Muenchian
grouping. This technique relies on combining an xsl:key
definition with generate-id().
An xsl:key indexes elements by a specific grouping
property. To find the first element of each group, the stylesheet checks
if the current node's generated ID matches the generated ID of the first
node retrieved by the key:
<xsl:key name="books-by-author" match="book" use="author" />
<xsl:template match="library">
<xsl:for-each select="book[generate-id() = generate-id(key('books-by-author', author)[1])]">
<h3>Author: <xsl:value-of select="author" /></h3>
<ul>
<xsl:for-each select="key('books-by-author', author)">
<li><xsl:value-of select="title" /></li>
</xsl:for-each>
</ul>
</xsl:for-each>
</xsl:template>This condition filters out duplicate authors by only selecting the first node that represents each distinct key value.
Important Characteristics and Constraints
- Run-to-Run Variability: The format and value of the generated ID are processor-dependent and are not guaranteed to remain identical across different execution runs or across different XSLT processors.
- Intra-Run Consistency: Within a single execution on
a single document, calling
generate-id()on the same node will always yield the exact same string. - Document Conformance: The output of
generate-id()is guaranteed to consist of ASCII alphanumeric characters and start with an alphabetic character, making it valid for HTMLidattributes and XMLIDtypes.