Re: [xsl] The evaluate function

Mike wrote:
>> It seems that many questions on this list involve solutions that
>> require use of an evaluate function. So the need is clearly there.
>
> It would be useful if you would make that point to the xsl-editors list,
> ideally with a summary of the common use cases.

Use cases that I can think of:

1. Interface specification

This is arguably the most common use case, where the use is combining
some kind of abstract specification of an interface (e.g. a table, a
form) with a set of data to produce the output. The abstract interface
specification holds references to the pieces of the data that need to
be inserted in the result, as XPaths.

For example, you have a definition of a table that you wish to
generate, something like:

<table>
  <column use="@date" />
  <column use="@payee" />
  <column use="." />
</table>

and you want to generate the table for a set of data using that
specification. Something like:

  <table>
    <xsl:for-each select="$rows">
      <xsl:variable name="row" select="." />
      <xsl:for-each select="$table-spec/column">
        <xsl:variable name="path" select="concat('$row/', @use)" />
        <td><xsl:value-of select="evaluate($path)" /></td>
      </xsl:for-each>
    </xsl:for-each>
  </table>

[Note that this use case implies that having access to variables would
be useful.]

---

2. Sort specifications

Another one that often comes up is where you have a definition of the
way in which a set of information should be sorted, again as an XPath.

For example, have a parameter that states what the rows in a table
should be sorted by:

  <xsl:param name="sortby" select="@date" />

And sort the rows accordingly:

  <xsl:for-each select="$rows">
    <xsl:sort select="evaluate($sortby)" ... />
    ...
  </xsl:for-each>

---
  
3. Linking

A third example is where someone has used XPath as a means of
specifying the links between two pieces of data. The link needs to be
interpreted on the fly in order to pull in information from the linked
source.

For example, you might have something like:

<para>
  The picture is <insert resource="images/image[3]" />.
</para>

And need to do:

<xsl:template match="insert">
  <xsl:copy-of
    select="document('resources.xml')/resources/evaluate(@resource)" />
</xsl:template>

---

4. Validation

A fourth example is illustrated in Schematron and Examplotron, both of
which use XPath to provides tests to validate XML documents, those
tests being written in XPath.

Currently, these schemas are used to generate an XSLT document, which
is then run on the instance document. If evaluate() was available,
then you could instead use at least some of the XPaths directly:

<xsl:template match="assert">
  <xsl:if test="not(evaluate(@test))">
    <xsl:message><xsl:value-of select="." /></xsl:message>
  </xsl:if>
</xsl:template>

---

5. Dynamic extension functions

A final case for the evaluate() function is to allow people to write
dynamic extension functions that can provide close to the facilities
required for things like generic templates. I realise that XPath now
has facilities, in particular the for expression, that reduce the
demand for these types of functions, but I still think that they are
useful.

For example, to implement a function called my:sum() that takes two
arguments - the first being the nodes to sum, the second being the
expression that should be evaluated for each of those nodes, I need:

<xsl:function name="my:sum">
  <xsl:param name="nodes" select="/.." />
  <xsl:param name="expr" select="'.'" />
  <xsl:result
    select="sum( for $n in $nodes return evaluate($expr) )" />
</xsl:function>

---

Actually, a good source of use cases for the evaluate() function comes
from looking at XForms and imagining writing a stylesheet that can
generate an HTML version of the XForm. XForms uses XPath all over the
place - to link into XML structures, to provide tests to see whether
form controls are required, read-only and so on.

It's also worth noting that the XPath used by XForms includes a number
of extension functions; this implies that support for extension
functions within the evaluate() function would be beneficial.

> Some of the discussion needed is over details (for example, should
> the expression be allowed to contain variable references, or calls
> to extension functions? If the expression is read from a source
> document, how should namespace prefixes be resolved?).

For usability, I'd say that it should be allowed to contain variable
references and calls to extension functions. I think you could
probably use the context node as the provider of namespace mappings;
or do something like the document() function and have a second
argument that provides a node that can be used to resolve namespace
prefixes, defaulting to the XSLT element in which the evaluate()
function is called.

> Some relates to other issues concerned with static typing: we are
> generally trying to move towards having as much type information as
> possible available statically, and a crude evaluate() function takes
> us in the opposite direction.

Much as I hate to suggest it, you could always use a keyword instead:

  "evaluate" StrExpr "as" Datatype

where StrExpr is an expression that is cast to a string and Datatype
is a data type as in Production 43 in the XPath 2.0 WD.

> Some is a concern about principles: how do we cater for implementors
> who want to compile stylesheets into compact executable code and
> ship that code for execution on handheld devices?

Make it optional? Or partially optional if there's a subset of
expressions that these implementers could handle.

Cheers,

Jeni

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

Received on Thursday, 3 January 2002 05:22:51 UTC