A dog-food use case

I thought it might be useful to report on a little experiment I did.

Test case evaluate-046 is a stylesheet that does a simple simulation of the preprocessing phase of an XSLT 3.0 compiler:

* it processes a source document (actually, a stylesheet) in streaming mode

* it evaluates static variables as it goes (using accumulators)

* it evaluates and acts on use-when expressions (using xsl:evaluate)

* it expands the values of AVT-valued shadow attributes (also using xsl:evaluate)

There are many aspects of the real preprocessor that it doesn't attempt to tackle, for example

* externally-supplied values for static params

* included and imported modules

* shadow attributes overriding non-shadow attributes

Some of the difficulties I encountered might be of interest:

(1) the current values of static variables are maintained using an accumulator, the value of the accumulator being a map from variable names to variable values. The accumulator matches static xsl:variable elements and uses xsl:evaluate to evaluate the select attribute. The problem is that the select attribute can reference the values of other static variables, so xsl:evaluate needs to be called with 

with-param="accumulator-before('static-vars')"

to make the map of static variables accessible. On first attempt this caused infinite recursion. But I solved the problem by making the accumulator rule specify phase="end" so the new value is only computed at the end of the xsl:variable processing, and a phase="end" accumulator rule can access the accumulator-before() value with no problems.

(2) processing of AVT-valued shadow attributes is done in a template rule that matches attributes and uses xsl:analyze-string. It calls xsl:evaluate within xsl:analyze-string to process the embedded expressions. At this point, however, the context item is a string, so we can't call accumulator-before() directly. It's necessary to bind a variable to the value of the accumulator outside the xsl:evaluate (we can't bind a variable to the containing attribute node, because it's a streamable node). The next difficulty is that you can't call accumulator-before when the context item is an attribute node, but you can get around that by using ../accumulator-before('static-vars')

(3) Actually the use of regular expressions to parse an attribute value template is a cheat. Embedded expressions can contain curly braces, and it's only really feasible to determine where an embedded expression ends by parsing it using an XPath parser that's happy for the supplied string to continue beyond the end of the XPath expression.  But that can't be done using xsl:evaluate. Probably the only way this can be implemented using xsl:evaluate is with some kind of pre-parser that detects the end of the embedded expression by counting paired curly braces and discounting curly braces within string literals and comments, which is kind of tedious to implement in XSLT, though it can no doubt be done.

Michael Kay
Saxonica

Received on Saturday, 14 January 2017 23:27:32 UTC