An essential function performed by the site map stylesheet is to resolve all relative links in the given site map into absolute links in the expanded site map.
Why do we need absolute URIs?
Consider generating a document, located in the file chapter1/sect1.xml, with the site map present in site-map.xml. The site map specifies cross reference labels and navigation lists as URIs; if these URIs are relative, then they are relative to the site map document site-map.xml. But relative links in chapter1/sect1.xml must necessarily be interpreted as relative to chapter1/sect1.xml.
So when we want to compare a href link in
chapter1/sect1.xml versus
a href link in site-map.xml,
we must normalize them somehow.
And the easiest way to do this is to make
both of them into absolute URIs;
then the two links point to the same thing if and only if
the absolute URIs that they resolve to compare equal
as character strings.
xsl:stylesheet id="stylesheet" exclude-result-prefixes="x2 lit uri" version="1.0" xml:lang="en" xsl:param name="doc-uri" select="'file://localdir/'"absolute-uriabsolute-idmap-uriidgenerate-idgenerate-idempty
absolute-uri
The absolute-uri
template takes a relative URI reference
(typically from a href attribute
in the current document)
and resolves it to an absolute URI reference.
xsl:template name="absolute-uri" xsl:param name="href" select="@href" xsl:param name="base" xsl:call-template name="uri:resolve-uri" xsl:with-param name="reference" select="$href" xsl:with-param name="base" xsl:choose xsl:when test="$base != ''" xsl:value-of select="$base" xsl:otherwise xsl:value-of select="$doc-uri"
absolute-id
The absolute-id template
takes the target node and returns an absolute URI reference to it.
xsl:template name="absolute-id" xsl:param name="target" select="." xsl:param name="base" select="$doc-uri" xsl:value-of select="$base" xsl:if test="count($target/parent::*)" xsl:text# xsl:call-template name="id" xsl:with-param name="target" select="$target"
The id template
takes the target node and returns the ID for it.
If the id attribute is present on the node,
then that is returned. Otherwise,
an ID is generated by using the generate-id
function of XSLT.
In both cases, an optional suffix may be appended to the ID.
Since generate-id could be used to generate
the ID, the return value cannot guaranteed to be the same
across different invocations of the stylesheet.
Thus the value of this template is unsuitable for use
as a look-up key in site maps. Its intended use is for
generating IDs for immediate XHTML1 output.
xsl:template name="id" xsl:param name="target" select="." xsl:param name="suffix" select="''" xsl:choose xsl:when test="$target/@id" xsl:value-of select="concat($target/@id, $suffix)" xsl:otherwise <-- <xsl:value-of select="concat(generate-id($target), $suffix)"/> --> xsl:text_gid xsl:apply-templates select="$target" mode="generate-id"
xsl:template priority="1.0" match="*" mode="generate-id" xsl:apply-templates select="parent::*" mode="generate-id" xsl:value-of select="concat('.', count(preceding-sibling::*)+1)"
xsl:template match="node()" mode="generate-id"
map-uri
The map-uri template
maps a relative reference originally from the XHTML2 document
into a reference suitable for the XHTML1 output.
We would use this template, for example, if we encounter an element:
<x2:a href="intro.xml#features"> … </x2:a>
in the source, that ought to be translated to, in the final output:
<a href="intro.html#features"> … </a>
In this case, the xml extension was changed to html. In general, we do not to hard-code this text substitution rule, of course. Rather, the site map will contain mapping entries that transform URIs from the original source document to URIs in the final output.
Even more generally, the mapping entries can be used not only for renaming the XML files to their HTML counterparts, but also for arbitrary one-to-one transformations. For example, the user may want to map between differing URI organization schemes in the source and output.
All the mapping details are hidden inside the generation process
for site maps; for XHTML1 generation, the stylesheet only
needs to obtain the output URI given an input URI.
That is exactly the purpose of the
map-uri template.
xsl:template name="map-uri" xsl:param name="href" select="@href" xsl:choose xsl:when test="starts-with($href, '#')" xsl:value-of select="$href" xsl:when test="contains($href, '#') and count($site-map-doc)>0" xsl:variable name="absolute-uri" xsl:call-template name="absolute-uri" xsl:with-param name="href" select="substring-before($href, '#')" xsl:for-each select="$site-map-doc" xsl:choose xsl:when test="count(key('html-uris', $absolute-uri))>0" xsl:call-template name="uri:make-relative" xsl:with-param name="reference" select="key('html-uris', $absolute-uri)[last()]/@to" xsl:with-param name="base" select="$doc-uri" xsl:otherwise xsl:call-template name="uri:make-relative" xsl:with-param name="reference" select="$absolute-uri" xsl:with-param name="base" select="$doc-uri" xsl:text# xsl:value-of select="substring-after($href, '#')" xsl:when test="count($site-map-doc)>0" xsl:variable name="absolute-uri" xsl:call-template name="absolute-uri" xsl:with-param name="href" select="$href" xsl:for-each select="$site-map-doc" xsl:choose xsl:when test="count(key('html-uris', $absolute-uri))>0" xsl:call-template name="uri:make-relative" xsl:with-param name="reference" select="key('html-uris', $absolute-uri)[last()]/@to" xsl:with-param name="base" select="$doc-uri" xsl:otherwise xsl:call-template name="uri:make-relative" xsl:with-param name="reference" select="$absolute-uri" xsl:with-param name="base" select="$doc-uri" xsl:otherwise xsl:value-of select="$href"
Formatted using xhtml2to1 by Steve Cheng.