Lukasz
Lukasz

Reputation: 7662

Call named templates from the sequence in XSLT 2.0

Let's say that I have a sequence of strings. The strings are actually names of named templates. Each of these named templates validates something in the input XML and returns a string. If the validation fails, it returns error message, otherwise it returns zero length string (it means that the validation succeeded).

I would like to have a template that would iterate through the sequence and call the named templates one after another. If one of them returned response (error message) that is longer than 0, then it should stop calling the templates and return that error message.

I am wondering if this is possible using XSLT 2.0.

Upvotes: 1

Views: 520

Answers (3)

G. Ken Holman
G. Ken Holman

Reputation: 4403

You can dispatch activity based on a sequence of strings by exploiting the template matching mechanism of XSLT 2 and synthesizing the actions that are then acted on by the push and match. This has a similar effect to the call, that is invoking another template, but it is done on demand. The transcript below illustrates this:

t:\ftemp>type dispatch.xml
<?xml version="1.0" encoding="UTF-8"?>
<doc>Data file</doc>

t:\ftemp>type dispatch.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xsd"
                version="2.0">

<xsl:output indent="yes"/>

<xsl:template match="/">
  <xsl:variable name="requirements" select="'this','that','other','that'"/>
  <xsl:variable name="data" select="."/>
  <xsl:for-each select="$requirements">
    <xsl:variable name="action" as="element()">
      <xsl:element name="{.}"/>
    </xsl:variable>
    <xsl:apply-templates select="$action" mode="dispatch">
      <xsl:with-param name="data" select="$data"/>
    </xsl:apply-templates>
  </xsl:for-each>
</xsl:template>

<xsl:template match="this" mode="dispatch">
  <xsl:param name="data"/>
  <xsl:for-each select="$data">
Doing this with the data:  <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

<xsl:template match="that" mode="dispatch">
  <xsl:param name="data"/>
  <xsl:for-each select="$data">
Doing that with the data:  <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

<xsl:template match="other" mode="dispatch">
  <xsl:param name="data"/>
  <xsl:for-each select="$data">
Doing the other with the data:  <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

t:\ftemp>xslt2 dispatch.xml dispatch.xsl
<?xml version="1.0" encoding="UTF-8"?>
Doing this with the data:  Data file
Doing that with the data:  Data file
Doing the other with the data:  Data file
Doing that with the data:  Data file
t:\ftemp>

Upvotes: 4

Jirka Š.
Jirka Š.

Reputation: 3428

You could make a recursive template processing sequence of strings as a parameter.

In it you could hardcode some (a bit clumsy) xsl:choose evaluating first string in that sequence and in appropriate xsl:when call the appropriate template. If it returned no error then call your recursive template again with the rest of strings sequence otherwise do something else.

But it is obvious you had to add new xsl:when every time you added new template to be called and therefore such code could be difficult to maintain.

Actually I think the main point of your question is the purpose of your requirement. Might be you could achieve same goal using more separate stylesheets combined with some pipeline (e.g. XProc or something similar)

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167696

It is not possible in pure XSLT 1.0 or 2.0, like in many other languages you can't call a template (or function/subroutine/procedure) dynamically. Saxon however offers http://www.saxonica.com/documentation/index.html#!extensions/instructions/call-template.

Upvotes: 1

Related Questions