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

Subject: Re: [xsl] Implementing XPointer Resolution With saxon:evaluate()
From: "W. Eliot Kimber" <eliot@xxxxxxxxxx>
Date: Wed, 14 Aug 2002 09:59:54 -0500
Ok, I seem to have everything working, at least within the scope of a
single document (I haven't stepped up to handling cross-document
XPointers, although I know how to do it).

Here are the parts of my initial solution (tested with Saxon, but should
work with any XSLT processor that implements the EXSLT common and
function packages):

1. Indirector functions (implemented using EXSLT function features and
XSLT as the implementation language) (xindirect-functions.xsl):

<?xml version='1.0'?>
<!-- Copyright (c) 2002 ISOGEN International -->
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xlink="http://www.w3.org/TR/xlink";
  xmlns:xindr="http://www.isogen.com/papers/xindirection.xml";
  xmlns:xindrf="http://www.isogen.com/functions/xindirection";
  xmlns:saxon="http://icl.com/saxon";
  xmlns:func="http://exslt.org/functions";
  xmlns:fcommon="http://exslt.org/common";
  extension-element-prefixes="func xindrf"
>

<func:function name="xindrf:resolve-indirector">
  <xsl:param name="indirector-node"/>
  <xsl:variable name="indirector-treatment-str"
select="string(@indirector-treatment)"/>
  <func:result select="xindrf:resolve-xpointer($indirector-node,
$indirector-treatment-str)"/>
</func:function>

<func:function name="xindrf:resolve-xpointer">
  <xsl:param name="pointer-node"/><!-- The Element node that exhibits
the XPointer to be resolved -->
  <xsl:param name="indirector-treatment">as-indirector</xsl:param>
  <xsl:variable name="indirector-treatment-str"
select="string($indirector-treatment)"/>
  <xsl:variable name="xpointer">
    <xsl:choose>
      <xsl:when test="starts-with($pointer-node/@href,'#')">
        <xsl:value-of select="substring($pointer-node/@href, 2)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$pointer-node/@href"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:choose>
    <xsl:when test="$xpointer != ''">     
      <xsl:variable name="direct-result-set"
select="saxon:evaluate($xpointer)"/>
      <xsl:for-each select="$direct-result-set">
        <xsl:choose>
          <xsl:when test="self::xindr:indirector and
($indirector-treatment-str != 'as-resource')" >
            <func:result select="xindrf:resolve-indirector(.)"/>
          </xsl:when>
          <xsl:otherwise>
            <func:result select="."/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message>
*** XIndirect error: $xpointer value is '' in resolve-xpointer.
      </xsl:message>
    </xsl:otherwise>
  </xsl:choose>  
</func:function>
</xsl:stylesheet>

2. Processing test script:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xlink="http://www.w3.org/TR/xlink";
  xmlns:xindr="http://www.isogen.com/papers/xindirection.xml";
  xmlns:xindrf="http://www.isogen.com/functions/xindirection";
  xmlns:saxon="http://icl.com/saxon";
  xmlns:func="http://exslt.org/functions";
  xmlns:fcommon="http://exslt.org/common";
  extension-element-prefixes="func xindrf"
>

<xsl:import href="./xindirect-functions.xsl"/>

<xsl:output 
  method="xml" 
  indent="no"
  omit-xml-declaration="no" 
  encoding="UTF-8"
/>

<xsl:template match="/">
  <html>
    <body>
      <div>
      <hr/>
      <h2>Input Document</h2>
      <pre>
      <xsl:apply-templates mode="echo-markup"/>
      </pre>
      </div>
      <div>
      <hr/>
      <h2>Debug Report</h2>
      <xsl:apply-templates/>
      </div>
    </body>
  </html>
</xsl:template>

<xsl:template match="links">
  <div>
    <h2>Links</h2>
    <table border="1" width="100%">
      <xsl:apply-templates/>
    </table>
  </div>
</xsl:template>

<xsl:template match="xlink:simple">
  <!-- <xsl:message>*** Starting xlink:simple</xsl:message> -->
  <tr>
    <td><a name="{generate-id()}"
      /><xsl:text>[</xsl:text
      ><xsl:value-of select="generate-id()"
      /><xsl:text>] Initial pointer: </xsl:text>
      <xsl:value-of select="@href"/><xsl:text>: </xsl:text>
      <xsl:apply-templates/>
      <br/><xsl:text>Direct targets: </xsl:text>
      <xsl:apply-templates 
          select="xindrf:resolve-xpointer(., 'as-resource')" 
          mode="generate-link-to"/>
    </td>
    <td>
      <xsl:text>ID of ultimate target: </xsl:text>
      <xsl:variable name="members" select="xindrf:resolve-xpointer(.)"/>
      <!-- <xsl:message>$members='<xsl:copy-of
select="$members"/>'</xsl:message> -->
      <xsl:for-each select="$members">
        <!-- <xsl:message>member[<xsl:value-of
select="position()"/>]=<xsl:copy-of select="."/></xsl:message> -->
        <br/>
        <a href="#{generate-id()}"
        ><xsl:value-of select="generate-id()"
        /></a>: <code><xsl:apply-templates select="."
mode="echo-markup"/></code>
      </xsl:for-each>
    </td>
  </tr>
</xsl:template>

<xsl:template match="paras">
  <div>
    <h2>Paragraphs</h2>
    <xsl:apply-templates/>
  </div>
</xsl:template>

<xsl:template match="para">
  <p
    ><a name="{generate-id()}"
    /><xsl:text>[</xsl:text
    ><xsl:value-of select="generate-id()"
    /><xsl:text
    >]</xsl:text
  ><xsl:apply-templates
  /></p>
</xsl:template>

<xsl:template match="xindr:indirectorset">
  <div>
    <h2>Indirectors</h2>
    <table border="1" width="100%">
      <xsl:apply-templates/>
    </table>
  </div>
</xsl:template>

<xsl:template match="xindr:indirector">
  <xsl:variable name="direct-target" select="xindrf:resolve-xpointer(.,
'as-resource')"/>
  <tr>
    <td><a name="{generate-id()}"
      /><xsl:text>[</xsl:text
      ><xsl:value-of select="generate-id()"
      /><xsl:text>] Pointer: </xsl:text
      ><xsl:value-of select="@href"/>
    </td>
    <td>
      <xsl:text>Direct targets: </xsl:text
      >
      <xsl:apply-templates select="$direct-target"
mode="generate-link-to"/>
    </td>
  </tr>  
</xsl:template>

<xsl:template match="*" mode="generate-link-to">
    <br/>
    <a href="#{generate-id()}"
    ><xsl:value-of select="generate-id()"
    /></a>: <code><xsl:apply-templates select="."
mode="echo-markup"/></code>
</xsl:template>

<xsl:template name="echo-element-markup">
  <xsl:text>&lt;</xsl:text><xsl:value-of select="name()"/>
  <xsl:for-each select="./attribute::*">
    <xsl:text>  </xsl:text><xsl:value-of select="name()"/>=<xsl:value-of
select="."/>
  </xsl:for-each>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="echo-markup"/>
  <xsl:text>&lt;</xsl:text><xsl:value-of
select="name()"/><xsl:text>&gt;</xsl:text>  
</xsl:template>

<xsl:template match="*" mode="echo-markup">
  <xsl:call-template name="echo-element-markup"/>
</xsl:template>
</xsl:stylesheet> 

3. Sample input document:

<?xml version="1.0"?>
<xindrtest 
  xmlns:xindr="http://www.isogen.com/papers/xindirection.xml";
  xmlns:xlink="http://www.w3.org/TR/xlink";
>
<links>
<xlink:simple href="#//*[@id='addr-01']">indirect link to para
1</xlink:simple>
<xlink:simple href="#//*[@id='addr-02']">indirect link to para
2</xlink:simple>
<xlink:simple href="#//*[@id='addr-03']">double indirect link to para
2</xlink:simple>
</links>
<paras>
<para>This is the first para</para>
<para>This is the second para</para>
</paras>
<xindr:indirectorset>
<xindr:indirector id="addr-01"
  href="#/*/paras/para[1]">pointer to para 1</xindr:indirector>
<xindr:indirector id="addr-02"
  href="#/*/paras/para[2]">pointer to para 2</xindr:indirector>
<xindr:indirector id="addr-03"
  href="#../xindr:indirector[2]">pointer to indirector
"addr-02"</xindr:indirector>
</xindr:indirectorset>
</xindrtest>

-- 
W. Eliot Kimber, eliot@xxxxxxxxxx
Consultant, ISOGEN International

1016 La Posada Dr., Suite 240
Austin, TX  78752 Phone: 512.656.4139

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


Current Thread