This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: character entities
- From: Joerg Pietschmann <joerg dot pietschmann at zkb dot ch>
- To: XSL List <xsl-list at lists dot mulberrytech dot com>
- Date: Wed, 28 Nov 2001 12:37:25 +0100
- Subject: Re: [xsl] character entities
- Organization: ZKB
- Reply-to: xsl-list at lists dot mulberrytech dot com
Dimitre Novatchev <dnovatchev@yahoo.com> 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