XSLT Templates and Compiling

This document describes compiling of XSLT stylesheets and the evaluation of the result.

Objectives:

Concepts:

LRE namespaces
All namespace aliases are merged wit import precedence into an array of all namespace ids, which is used to map the LRE namespace in the source to the LRE namespace in the result. Non-aliased namespaces just have their namespace id in that array.

Compilation:

The XSLT specification describes XSLT in terms of the XPath datamodel, something pretty close to a DOM. So we talk about the input in terms of DOM elements.

The DOM nodes in a stylesheet get compiled into either The xslInstructions fall into classes,
  1. simple instructions,
  2. utilities (no-op, variable-pop, push-handler),
  3. branching instructions,
  4. instructions changing the result handler and
  5. instructions calling into different xslTopElements.

How do instructions work?

The general pattern used to create output from a set of instructions is
while (instruction) {
  rv = instruction.do(args);
  if (NS_FAILED(rv)) {
    //cleanup
    return rv;
  }
  instruction = instruction.mNext;
}
This says pretty much all about simple and utility instructions.

Branching instructions

see xsl:choose. The trailing single no-op helps in rejoining the paths, as that no-op can be created before the paths and thus easily appended to each end of the paths.

Instructions that change the output handler

These instructions (attribute, comment, pi creating text handlers, variable possibly creating a rtf handler) get created by inserting a push-handler-instruction into the workflow for the start of the element and the XSLT instruction at the end. The handler instruction should keep a non-owning reference to the push-handler-instruction to get the result and restore the previous handler.

xsl:apply-imports

no idea

xsl:apply-templates

members:
select
node-set-expression
mode
qname
sorts
list of xsl:sort elements
params
list of xsl:with-param elements
do()
set up the params, if any, evaluate the select, create a evalContext and push it on the evalContextStack. push the next instruction to the instruction return stack. trigger the new context (how do we do this?).

xsl:attribute

members:
name
AVT with QName value
namespace
AVT with uri value
do()
the start tag pushes a textValueHandler, the end tag pops the value handler and calls the outputhandler::attribute

xsl:attribute-set (tle)

attribute sets are merged, we should pay attention that multiple stylesheet compilers don't mix their content. Order of attributes is relevant, IMHO.
members:
name
qname
use-attribute-sets
list of qnames
do()
merging and stuff needed in the global stylesheet object, (NOT part of import frame).

xsl:call-template

members:
name
qname
with-params
list of xsl:with-params
do()
push the next instruction onto the instruction return stack, lookup the template and set the instruction pointer to the called template. Setup the params, if there are. This does not change the evalContextStack.
Can we cache this? What happens if a added stylesheet between two transforms changes which stylesheet this qname resolves to?

xsl:choose

This is a branching instruction with one exit point and several conditional entry points (xsl:when) and one default (xsl:otherwise). The conditional entry points start with a conditionalGotoInstrunction, which jumps to the next entry point if they don't succeed. Each of them ends with a gotoInstruction that jumps to the end of the xsl:choose (for simplicity in the compilation phase, this might be a noopInstruction). The xsl:otherwise is just the instructions list of the xsl:otherwise, linked to the ending noopInstruction. Note that this construct a single instruction list for the complete xsl:choose, as the mNext of the final gotos is the next entry point. This mNext is only used for iterations, though.

xsl:comment

do()
startElement pushes a textHandler, endElement takes the value and calls ::comment() in the output handler

xsl:copy

members:
do()
xsl:copy has a use-attribute-sets attribute, TODO

xsl:copy-of

members:
select
an expression to be added to the result tree
do()
the value of the result is added to the result tree. If the result is a RTF, the RTF is just fed into the output handler, if the result is not a nodeset, it is converted into a string and ::characters is called on the output handler. For nodesets, the result is a list of source nodes which have to be interpreted, for example thru the stylesheet compiler. This has be xslt-blind, that is, xslt elements in the source must be treated as LRE elements and copied into the result, instead of generating XSLT instructions. is this all?

xsl:decimal-format (tle)

xsl:decimal-format is stored in the global stylesheet object, import precedence does not apply.

xsl:element

members:
name
AVT with QName value
namespace
AVT with URI value
do()
xsl:element has attribute-sets, todo. Other than that, this just generates an element. Note that the attributes of this element have to be discarded, if the name AVT does not evaluate to a QName.

xsl:fallback

do we care?

members:
do()