[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: character entities

Subject: Re: character entities
From: Joerg Pietschmann <joerg.pietschmann@xxxxxx>
Date: Wed, 28 Nov 2001 12:37:25 +0100
xpath previous sibling
Dimitre Novatchev <dnovatchev@xxxxxxxxx> wrote:
> > > Also I'd have to go outside XSLT 1.0 ... then there is _nothing_ a
> > > template can do to create that node set, as templates don't create
> > > nodesets.
> I didn't "jump onto this", because generic templates cannot help here -- they
> create/return RTFs, which even when transformed to a nodeset do not contain the
> original nodes but their copies.

I rather thougt of using the equivalent of a function pointer.

For illustration:
1. Foo-elements as previous sibling in document (perhaps included
there as entity)
  <xsl:template ... >
    ...
    <xsl:for-each select="previous-sibling::foo[1]/bar">
      <!-- do stuff -->
      ...
2. Foo-elements perhaps in external document, use copy-of and node-set
  <xsl:template ... >
    ...
    <xsl:variable name="stuff">
      <xsl:choose>
        <xsl:when test="previous-sibling::*[1][self::nag:reference]">
          <xsl:copy-of select="document(previous-sibling::nag:reference[1]/@url)/refitem/foo)"/>
        </xsl:when>
        <xsl:when test="previous-sibling::*[1][self::foo]">
          <xsl:copy-of select="previous-sibling::self::foo"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message terminate="yes">Problem getting foo</xsl:message>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:for-each select="xx:node-set($stuff)/bar">
      <!-- do stuff -->
      ...
Obvious disadvantage: the processing stage cannot refer to ancestors
and siblings of foo-elements.
3. Foo-elements perhaps referenced, use indirection for xpaths crossing
the reference boundaries.
  <i:do-stuff/>
  <xsl:template match="i:do-stuff">
    <xsl:param name="reference-node"/>
    <xsl:param name="stuff"/>
    <!-- do stuff -->
  </xsl:template>
  <xsl:template name="get-foo">
    <xsl:param name="f"/>
    <xsl:choose>
      <xsl:when test="previous-sibling::*[1][self::nag:reference]">
        <xsl:apply-template select="$f">
          <xsl:with-param name="reference-node" select="previous-sibling::nag:reference[1]"/>
          <xsl:with-param name="stuff" select="document(previous-sibling::nag:reference[1]/@url)/refitem/foo)"/>
        </xsl:apply-template>
      </xsl:when>
      <xsl:when test="previous-sibling::*[1][self::foo]">
        <xsl:apply-template select="$f">
          <!-- leave reference-node empty -->
          <xsl:with-param name="stuff" select="previous-sibling::self::foo"/>
        </xsl:apply-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message terminate="yes">Problem getting foo</xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  ...
  <xsl:template ... >
    ...
    <xsl:call-template name="get-foo">
      <xsl:with-param name="f" select="document('')/*/i:do-stuff"/>
    </xsl:call-template>
You can use the get-foo template everywhere where you have to gather
foos and pass the actual function to be invoked on the foos as a parameter.
I'm not quite sure whether this is actually a "generic template", until
recently i thought so.
Moreover, in order to reference arbitrary ancestors and siblings from
the conceptual tree, some other templates have to be used
  <xsl:template name="get-previous-sibling-foo">
    <xsl:param name="reference-node"/>
    <xsl:param name="context"/>
    <xsl:param name="f"/>
    <xsl:choose>
      <xsl:when test="$reference-node">
        <xsl:apply-templates select="$f">
          <xsl:with-param name="reference-node" select="$reference-node"/>
          <xsl:with-param name="stuff" select="$reference-node/previous-sibling::foo"/>
          <xsl:with-param name="context" select="$context"/>
        </xsl:apply-templates>
      <xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="$f">
          <xsl:with-param name="reference-node" select="$reference-node"/>
          <xsl:with-param name="stuff" select="$context/previous-sibling::foo"/>
          <xsl:with-param name="context" select="$context"/>
        </xsl:apply-templates>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
and something similar for ancestors and everything else.
hardcoding all the element names ("foo") into all the templates
above may not be desirable. A xx:evaluate() extension could be used,
or a somewhat crude interpreter of an xml-ified xpath-syntax:
  <xsl:template name="evaluate-simple-xpath">
    <xsl:param name="xpath"/>
    <xsl:param name="reference-node"/>
    <xsl:param name="context"/>
    <xsl:param name="result"/>
    <xsl:param name="f"/>
    <xsl:choose>
      <xsl:when test="not($xpath)">
        <!-- end condition for recursion: xpath empty, invoke function -->
        <xsl:apply-templates select="$f">
          <xsl:with-param name="reference-node" select="$reference-node"/>
          <xsl:with-param name="stuff" select="$result"/>
          <xsl:with-param name="context" select="$context"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="$xpath/step/axis='previous-sibling'">
        <xsl:choose>
          <xsl:when test="generate-id($result)=generate-id($reference-node)">
            <!-- we are crossing the reference boundary -->
            <xsl:call-template name="evaluate-predicate">
              <xsl:param name="$xpath/predicate"/>
              <xsl:with-param name="reference-node" select="$reference-node"/>
              <xsl:with-param name="result" select="$reference-node/previous-sibling::*[name()=$xpath/step/name"/>
              <xsl:with-param name="context" select="$context"/>
              <xsl:with-param name="f" select="$f"/>
            </xsl:call-template>
          <xsl:when>
          <!-- other cases -->
      </xsl:when>
      <!-- other axes -->
    </xsl:choose>
  </xsl:template>
I'm afraid the above won't work, especially as it's probably possible
to encounter other references, but i hope you'll get the general picture.
Invoke this like
  <x:foo-path>
    <step>
      <axis>previous-sibling</axis>
      <name>foo</name>
      <predicate>
        <equals>
          <function>position</function>
          <constant-number>1</constant-number>
        </equals>
      </predicate>
    </step>
  </x:foo-path>
  ...
    <call-template name="eval-simple-xpath">
       <xsl:with-param name="xpath" select="document('')/*/x:foo-path/>
       ...

The above certainly needs a lot of work, it's only the product of
less than thirty minutes of thinking...

Regards
J.Pietschmann

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


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.