Re: [xsl] Implementing XPointer Resolution With saxon:evaluate()

Subject: Re: [xsl] Implementing XPointer Resolution With saxon:evaluate()
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 13 Aug 2002 22:50:54 +0100
Hello Eliot :)

> In my test style sheet I am generating an HTML page that makes
> explicit both the resolved links from the initial references to
> their ultimate targets as well as each of the intermediate steps
> through the indirectors. To express the linkages in HTML I'm using
> the normal generate-id() approach in the output:
>
>       <xsl:text>ID of ultimate target: </xsl:text>
>       <xsl:variable name="members">
>         <xsl:call-template name="resolve-xpointer"/>
>       </xsl:variable>
>       <xsl:for-each select="$members">
>         <a href="#{generate-id()}"
>         ><xsl:value-of select="generate-id()"
>         /></a><xsl:text>, </xsl:text>
>       </xsl:for-each>
>
> Where the "resolve-xpointer" template should resolve the xpointer in
> the href= attribute of the current node to a node set of ultimate
> targets. However, my implementation of resolve-xpointer uses
> xsl:copy-of, which of course isn't going to work because the copy
> nodes are not the same as the initial target nodes.
>
> What I can't figure out is how to have the resolve-xpointer template
> return the actual nodes referenced, not a copy of them--is this even
> possible without writing an extension function that does all the
> address resolution? That is, I don't see a way for the value of a
> template to be the direct value of a select action, rather than a
> copy of the value.

Yep, you're stuck. I can see two possible ways around the problem.

First option, since you're using extensions anyway, you could use
EXSLT's func:function to define a function for resolve-pointer. You
should be able to rejig the resolve-xpointer code so that it
recursively puts together a node-set rather than copying the nodes,
and then return that node set from the function, setting the variable
with:

  <xsl:variable name="members" select="isogen:resolve-xpointer()" />

Second option, since the only information that you seem to be using
about these nodes is their generated ID, is to create a new set of
nodes whose values are the generated IDs of the nodes that you're
interested in. You can then turn the result tree fragment into a
node-set in the usual way in order to iterate over them:

 <xsl:variable name="members">
   <xsl:call-template name="resolve-xpointer"/>
 </xsl:variable>
 <xsl:for-each select="exsl:node-set($members)/*">
   <a href="#{.}"><xsl:value-of select="." /></a>
   <xsl:text>, </xsl:text>
 </xsl:for-each>

Let us know if you need assistance with either of those.

> Also, why does this fail?:
>
>      <xsl:for-each select="$direct-result">
>         <xsl:choose>
>           <xsl:when test="xindr:indirector">
>             <!-- Never gets here -->
>
> When the context node is "xindr:indirector" (as returned by name())?
> The corresponding template match does work. Is this a subtle side
> effect of name-space processing?
>
> If I use test="name() = 'xindr:indirector'" then the when succeeds
> and I can verify that the addresses are getting resolved correctly
> and the indirection is being correctly recursed through.

I'm not quite sure, but could the difference be that when you do
test="xindr:indirector" you're testing whether the current node has a
*child* xindr:indirector element, but the name() function returns the
name of the current node? If you want to test whether the *current*
node is an xindr:indirector element, you need to use the self:: axis
explicitly:

  <xsl:when test="self::xindr:indirector">
    ...
  </xsl:when>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread