tools/boostbook/xsl/lookup.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- Generate an ID for the entity referenced -->
<xsl:template name="generate.id">
<xsl:param name="node" select="."/>
<xsl:apply-templates select="$node" mode="generate.id"/>
</xsl:template>
<xsl:template match="*" mode="generate.id">
<xsl:value-of select="generate-id(.)"/>
<xsl:text>-bb</xsl:text>
</xsl:template>
<!-- Strip the qualifiers off a qualified name and return the unqualified
name. For instance, "boost::python::function" would become just
"function". -->
<xsl:template name="strip-qualifiers">
<xsl:param name="name"/>
<xsl:choose>
<xsl:when test="contains($name, '::')">
<xsl:call-template name="strip-qualifiers">
<xsl:with-param name="name" select="substring-after($name, '::')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$name"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Build the fully-qualified name of the given node -->
<xsl:template name="fully-qualified-name">
<xsl:param name="node"/>
<xsl:param name="separator" select="'::'"/>
<xsl:apply-templates select="$node" mode="fully-qualified-name">
<xsl:with-param name="separator" select="$separator"/>
</xsl:apply-templates>
</xsl:template>
<!-- Hack to make the node we are building the current node so that the
ancestor:: syntax will work -->
<xsl:template match="*" mode="fully-qualified-name">
<xsl:param name="separator" select="'::'"/>
<xsl:call-template name="build-fully-qualified-name">
<xsl:with-param name="separator" select="$separator"/>
</xsl:call-template>
</xsl:template>
<!-- The real routine that builds a fully-qualified name for the current
node. -->
<xsl:template name="build-fully-qualified-name">
<xsl:param name="separator" select="'::'"/>
<!-- The depth of qualified name element that we will print now-->
<xsl:param name="depth" select="1"/>
<!-- Determine the set of ancestor namespaces -->
<xsl:variable name="ancestors"
select="ancestor::namespace|ancestor::class"/>
<xsl:choose>
<xsl:when test="$depth > count($ancestors)">
<xsl:apply-templates select="." mode="print-name"/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="name($ancestors[$depth])='namespace' or
count(ancestor::free-function-group)=0">
<xsl:apply-templates select="$ancestors[$depth]" mode="print-name"/>
<xsl:value-of select="$separator"/>
</xsl:if>
<xsl:call-template name="build-fully-qualified-name">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Print the name of the current node -->
<xsl:template match="*" mode="print-name">
<xsl:value-of select="@name"/>
</xsl:template>
<xsl:template name="name-matches-node">
<!-- The name we are looking for -->
<xsl:param name="name"/>
<!-- The name to display -->
<xsl:param name="display-name" select="$name"/>
<!-- The context in which this name occurs -->
<xsl:param name="context"/>
<!-- The node that we are checking against -->
<xsl:param name="node"/>
<!-- The mode we are in. Can be one of:
matches: emits the matches as they are found (for debugging)
link: link to the node that was found
-->
<xsl:param name="mode" select="'matches'"/>
<!-- The index into the list of using directives for the context node -->
<xsl:param name="index" select="1"/>
<!-- The prefix we should append to the name when checking this node -->
<xsl:param name="prefix" select="''"/>
<!-- The fully-qualified name of the node we are checking against -->
<xsl:variable name="fully-qualified-name">
<xsl:call-template name="fully-qualified-name">
<xsl:with-param name="node" select="$node"/>
</xsl:call-template>
</xsl:variable>
<!-- The set of using directives for this context node -->
<xsl:variable name="directives"
select="$context/ancestor::*/using-namespace |
$context/ancestor::namespace |
$context/ancestor::*/using-class |
$context/ancestor::class"/>
<!-- The name of the current directive -->
<xsl:variable name="this-context">
<xsl:apply-templates select="$directives[$index]" mode="print-name"/>
</xsl:variable>
<!-- Check if we have a match -->
<xsl:variable name="have-match"
select="$fully-qualified-name = concat($prefix, $name)"/>
<xsl:if test="$have-match">
<xsl:choose>
<xsl:when test="$mode='matches'">
Match in namespace ::<xsl:value-of select="$prefix"/>
</xsl:when>
<xsl:when test="$mode='link'">
<xsl:call-template name="internal-link">
<xsl:with-param name="to">
<xsl:call-template name="generate.id">
<xsl:with-param name="node" select="$node"/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="text" select="$display-name"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:if>
<xsl:if test="(not($index > count($directives))) and
(not($have-match) or ($mode = 'matches'))">
<xsl:variable name="first-branch">
<xsl:if test="not ($prefix = '')">
<!-- Recurse and append the current context node to the prefix -->
<xsl:call-template name="name-matches-node">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="display-name" select="$display-name"/>
<xsl:with-param name="context" select="$context"/>
<xsl:with-param name="node" select="$node"/>
<xsl:with-param name="mode" select="$mode"/>
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="prefix"
select="concat($prefix, $this-context, '::')"/>
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="string($first-branch) != ''">
<xsl:copy-of select="$first-branch"/>
</xsl:when>
<xsl:otherwise>
<!-- Recurse with just the current context node -->
<xsl:call-template name="name-matches-node">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="display-name" select="$display-name"/>
<xsl:with-param name="context" select="$context"/>
<xsl:with-param name="node" select="$node"/>
<xsl:with-param name="mode" select="$mode"/>
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="prefix"
select="concat($this-context, '::')"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- Count the number of nodes in the set that match the given name and
lookup context -->
<xsl:template name="count-matches">
<xsl:param name="name"/>
<xsl:param name="context"/>
<xsl:param name="nodes"/>
<xsl:variable name="match-string">
<xsl:for-each select="$nodes">
<xsl:variable name="does-match">
<xsl:call-template name="name-matches-node">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="context" select="$context"/>
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="not($does-match='')">X</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="string-length($match-string)"/>
</xsl:template>
<xsl:template name="cxx-link-name">
<!-- The actual lookup node -->
<xsl:param name="lookup"/>
<!-- The type of name to lookup (e.g., class) -->
<xsl:param name="type"/>
<!-- The name we are looking for -->
<xsl:param name="name"/>
<!-- The name we will display -->
<xsl:param name="display-name"/>
<!-- The name we are looking for (unqualified)-->
<xsl:param name="unqualified name"/>
<!-- The list of nodes that match the lookup node in both name and type -->
<xsl:param name="nodes"/>
<!-- Count the number of nodes that match -->
<xsl:variable name="matches">
<xsl:call-template name="count-matches">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="context" select="$lookup"/>
<xsl:with-param name="nodes" select="$nodes"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$matches = 0">
<xsl:message>
<xsl:text>Cannot find </xsl:text>
<xsl:value-of select="$type"/>
<xsl:text> named '</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>'</xsl:text>
</xsl:message>
<xsl:value-of select="$display-name"/>
</xsl:when>
<xsl:when test="$matches = 1">
<xsl:for-each select="$nodes">
<xsl:call-template name="name-matches-node">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="display-name" select="$display-name"/>
<xsl:with-param name="context" select="$lookup"/>
<xsl:with-param name="node" select="."/>
<xsl:with-param name="mode" select="'link'"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:message>
<xsl:text>Reference to </xsl:text>
<xsl:value-of select="$type"/>
<xsl:text> '</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>' is ambiguous. Found:</xsl:text>
<xsl:for-each select="$nodes">
<xsl:call-template name="name-matches-node">
<xsl:with-param name="name" select="$name"/>
<xsl:with-param name="context" select="$lookup"/>
<xsl:with-param name="node" select="."/>
<xsl:with-param name="mode" select="'matches'"/>
</xsl:call-template>
</xsl:for-each>
</xsl:message>
<xsl:value-of select="$display-name"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>