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

Subject: Re: [xsl] Implementing XPointer Resolution With saxon:evaluate()
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 14 Aug 2002 18:09:34 +0100
Hi Eliot,

Sorry, I should have given more clues...

The basic method of recursively building up a node-set is to have a
function definition that looks like:

<func:function name="my:function">
  <xsl:param name="param"
             select="'The thing you're recursing over'" />
  <xsl:choose>
    <xsl:when test="...$param...">
      <xsl:variable name="node-set"
                    select="...$param..." />
      <func:result select="$node-set |
                           my:function(...$param...)" />
    </xsl:when>
    <xsl:otherwise>
      <func:result select="/.." />
    </xsl:otherwise>
  </xsl:choose>
</func:function>

In other words, you recurse over some parameter. If there's still work
to do on the parameter then you do a standard head/tail division of
the value, create a node-set from the head and return as the result
the union of that node set with the node set you get by recursively
calling the function on the tail.

In your case, this translates into something like:

<func:function name="xindrf:resolve-xpointers">
  <xsl:param name="indirectors" select="/.." />
  <xsl:choose>
    <xsl:when test="$indirectors">
      <func:result select="xindrf:resolve-xpointer($indirectors[1]) |
                           xindrf:resolve-xpointers($indirectors[position() > 1]" />
    </xs:when>
    <xsl:otherwise>
      <func:result select="/.." />
    </xsl:otherwise>
  </xsl:choose>
</func:function>

Step through the indirectors one by one, unioning the result of
resolving the first with the result of resolving the rest on each
recursion. Your xindrf:resolve-xpointer() function would call it with
something like:

<func:function name="xindrf:resolve-xpointer">
  ...
  <func:result
    select="$direct-result-set[not(self::xindr:indirector)] |
            xindrf:resolve-xpointers($direct-result-set[self::xindr:indirector])" />
</func:function>

Which says that the result of xindrf:resolve-xpointer() is the
node-set consisting of the result set that aren't indirector elements
unioned with the node-set resulting from calling
xindrf:resolve-xpointers() on the node-set that are indirector
elements.

(Untested, and I'm notoriously prone to getting the wrong stopping
condition on these things, but hopefully it gives you an idea of what
I was talking about.)

You can do the same kind of thing with templates as well, as long as
you don't want to *return* the node-set from the template. Something
like:

<xsl:template name="resolve-xpointers">
  <xsl:param name="indirectors" select="/.." />
  <xsl:param name="result" select="/.." />
  <xsl:choose>
    <xsl:when test="$indirectors">
      <xsl:call-template name="construct-node-set">
        <xsl:with-param name="indirectors"
                        select="$indirectors[position() > 1]" />
        <xsl:with-param name="result"
          select="$result |
                  xindrf:resolve-xpointer($indirectors[1])" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <!-- do something with the result, such as apply templates to
           it; you can't just return it, since all templates generate
           result tree fragments, not node sets -->
      <xsl:apply-templates select="$result" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Cheers,

Jeni

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


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


Current Thread