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)

members:
name
qname
use-attribute-sets
list of qnames
do()
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

members:
do()