XSLT Quickly

XSLT Quickly by Bob DuCharme. Manning Publications, 2001

XPath.

General:
* XPath expression consists of a location path, which is a series of one or more
location steps separated by slashes.
* Each location step has three parts:
- 1. Axis specifier
- 2. Node test
- 3. Predicate
* Only node test is required for each step.
* Axis specifier precedes the node test and is separated from it by '::'.
* Predicate follows node test and is enclosed in '[]'
* Match patterns in XSLT expressions use a subset of XPath and are limited to
child:: and attribute:: axes only.
 

Axis specifications:

* Axes is the relative position of the selected node to the context node on XML
tree.
* Axes specifier refers to a set of nodes. The selected set can consist of
multiple nodes, a single node, or be empty.
* Node test and predicate specification allow to select a subset of the set of
nodes selected by axis specifier.
* XSLT processor assumes child:: axis when none is specified.
* Parent axis can be expressed as parent::_node_name/ or ../
* When in need of treating the context node differently depending on within which element it exists (no matter the depth), use ancestor:: axis.
* When in need of checking for an existance of an attribute in the context node
or any of its ancestors, use ancestor-or-self:: axis. When checking ancestor
type axis, the processor goes from the context node upwards, counting the nodes
as it ascends.
----
Example: <xsl:if test="ancestor-or-self::*[@xml:lang][1]/@xml:lang='en'">
Select nodes beginning from the context node and going up till its highest
ancestor, such that they have 'lang' attribute. Select the first node from the
set (the self itself, i.e. the context node, or the closest one to the self),
and check if the value of its 'lang' attribute is equal to 'en'. Return the
boolean value as a result of the comparison.
----
* preceding-sibling is the one above and following-sibling is the one
below the context node. These axis might be used for creating links to the
previous and next chapters, for example.
* preceding axis comprises all the nodes above the context node, following axis
contains all the nodes below the context node.
* /descendant-or-self::node()/ is abbreviated as //
* The difference between chapter/title and chapter//title is that the first
expression says 'any title child element of the chapter element', the second
expression says 'any descendant title element of the chapter element'. The
second expression is broader than the first.
----
Example: chapter//@author - the set of elements descendant from chapter element
that have author attribute.
Example: //comment() - all the comments in the document
----
* self::node() is abbreviated as '.' (<xsl:value-of select="."/>
* Not all XSLT processors assume the existence of the default 'xml' namespace
node. It might not be listed or checked.
 

Node test.
 

* Each axis has its default node type: attribute axis refers to attributes,
namespace to namespaces; all the rest refer to elements.
* node() test is true for any node regardless of its type.
* node() test is broader than '*'. '*' refers to all sibling nodes of the type
matching its axis specifier default type. node() refers to all children of the
current node (elements, comments, processing instructions).
 

Predicate details:

* Predicate identifier always returns a boolean value. The nodes that return
'Yes' are selected, the nodes that return 'No' are deselected.
----
Example: <xsl:for-each select="child::wine[@grape='Cabernet']">
Same as: <xsl:for-each select="child::wine[attribute::grape='Cabernet']">
Same as: <xsl:for-each select="wine[attribute::grape='Cabernet']">
Same as: <xsl:for-each select="wine[@grape='Cabernet']">
----
* Use of numbers as predicates is an abbreviation of position() function
----
Example: <xsl:if test="ancestor-or-self::*[@xml:lang][1]/@xml:lang='en'">
Same as: <xsl:if test="ancestor-or-self::*[@xml:lang][position() = 1]/@xml:lang='en'">
----
* last() return the last node in the list
* text() returns 'True' for any node that has textual content. It's a node
test, not a function.
* not() negates the value of it's value expression
----
Example: child::year[not(text())] - year elements that do not have text
Example: child::wine[not(@grape)] - wine elements without attribute 'grape'
----
* Predicates work on the set that is already pre-selected by the node test
----
Example: child::wine[child::year] expression does not selet 'year' elements,
only 'wine' elements which have years as children.
----
* The way to read XPath expression is backwards, starting from what comes after
the last slash. Then see all the slashes and where they are pointing to.
Finally, remember the abbreviations and defaults.

 


 Elements and Attributes.

* One way to add elements to the output is to use "literal elements" in the stylesheet. Any element outside of XSLT namespace is ignored by the processor and included in the output unchanged.

* Another way to include elements is to use <xsl:element> element. Its name attribute will become the name of the output tag. This method allows dynamic generation of element tags.

-----

Example: <xsl:element name="verse"> turns into <verse>

-----

* Easiest way to change the element name is to use <xsl:apply-templates> element on the source and wrap it into a literal element with the desired name.