Expand | Collapse

◀ 15. Display navigation menu17. Stylesheet to nicely format XML markup ▶

16. Manipulating URIs

16.1. Resolving relative URIs

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.

16.1.1. Why?

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.

16.2. Stylesheet

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-uri
    absolute-id
    map-uri
    id
    generate-id
    generate-id empty
    
    

16.2.1. 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"
              
            
          
        
      

16.2.2. 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"
          
        
      

16.2.3. id

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"
      

16.2.4. 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.