To dig even further into how Umbraco implements XSLT, look at the examples that follow in the rest of the chapter.
When utilizing the Umbraco built-in editor for XSLT manipulation (in the backoffice), you can always refer to the Visualize XSLT tool to see how your XSLT macro will render. This tool allows you to select a target in the content tree and run your XSLT template as is without your having to add the macro to a template or node. Here's how that works:
The script in Listing 11-5 enables you to list all the content starting at the root node. This example is easy because you can take advantage of one of the XSLT extension methods that come with Umbraco.
LISTING 11-5: ListAllContent.xslt
<?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp “ ”> ]> <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:msxml=“urn:schemas-microsoft-com:xslt” xmlns:umbraco.library=“urn:umbraco.library” xmlns:Exslt.ExsltCommon=“urn:Exslt.ExsltCommon” xmlns:Exslt.ExsltDatesAndTimes=“urn:Exslt.ExsltDatesAndTimes” xmlns:Exslt.ExsltMath=“urn:Exslt.ExsltMath” xmlns:Exslt.ExsltRegularExpressions=“urn:Exslt.ExsltRegularExpressions” xmlns:Exslt.ExsltStrings=“urn:Exslt.ExsltStrings” xmlns:Exslt.ExsltSets=“urn:Exslt.ExsltSets” xmlns:umbusersguide.library=“urn:umbusersguide.library” exclude-result-prefixes=“msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets umbusersguide.library “> <xsl:output method=“xml” omit-xml-declaration=“yes” /> <xsl:param name=“currentPage”/> <xsl:template match=“/”> <!-- The fun starts here --> <ul> <xsl:for-each select=“umbraco.library:GetXmlAll()/descendant::xs* [@isDoc and string(umbracoNaviHide) != ‘1’]”> <li class=“level-{@level}”> <!-- create indentations using CSS class definitions --> <a href=“{umbraco.library:NiceUrl(@id)}”> <xsl:value-of select=“@nodeName”/> </a> </li> </xsl:for-each> </ul> </xsl:template> </xsl:stylesheet>
The select statement in Listing 11-5 can be broken down as follows:
The isDoc attribute was introduced along with the new XML schema. This allows you to differentiate between a document node (or a node that represents a page with fields), from the field nodes themselves. In the old schema, field values were all contained in the <data /> nodes and the pages in the <node /> node.
Now take a look at Listing 11-6 to see what this same script looks like in Umbraco 4.0.x and earlier. The difference here is that the script now specifies that it's looking for all nodes named node, as opposed to the wildcard in 4.5.x. Also, to check whether the field umbracoNaviHide equals 1, you must query for it by the node name data and checking its attribute value.
LISTING 11-6: ListAllPages-40x.xslt
<?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp “ ”> ]> <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:msxml=“urn:schemas-microsoft-com:xslt” xmlns:umbraco.library=“urn:umbraco.library” xmlns:Exslt.ExsltCommon=“urn:Exslt.ExsltCommon” xmlns:Exslt.ExsltDatesAndTimes=“urn:Exslt.ExsltDatesAndTimes” xmlns:Exslt.ExsltMath=“urn:Exslt.ExsltMath” xmlns:Exslt.ExsltRegularExpressions=“urn:Exslt.ExsltRegularExpressions” xmlns:Exslt.ExsltStrings=“urn:Exslt.ExsltStrings” xmlns:Exslt.ExsltSets=“urn:Exslt.ExsltSets” xmlns:umbusersguide.library=“urn:umbusersguide.library” exclude-result-prefixes=“msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets umbusersguide.library “> <xsl:output method=“xml” omit-xml-declaration=“yes” /> <xsl:param name=“currentPage”/> <xsl:template match=“/”> <!-- The fun starts here --> <ul> <xsl:for-each select=“umbraco.library:GetXmlAll()/descendant::node [string(data[@alias=‘umbracoNaviHide’] != ‘1’]”> <li class=“level-{@level}”> <!-- create indentations using CSS class definitions --> <a href=“{umbraco.library:NiceUrl(@id)}”> <xsl:value-of select=“@nodeName”/> </a> </li> </xsl:for-each> </ul> </xsl:template> </xsl:stylesheet>
Suppose you want to loop out some nodes, but want only the latest three of them, and they must have a value. Imagine that you want to apply this looping to the FAQs list on your homepage. Listing 11-7 does this task for Umbraco version 4.5.x and later.
LISTING 11-7: ListLatestFaqs.xslt
<?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp “ ”> ]> <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:msxml=“urn:schemas-microsoft-com:xslt” xmlns:umbraco.library=“urn:umbraco.library” xmlns:Exslt.ExsltCommon=“urn:Exslt.ExsltCommon” xmlns:Exslt.ExsltDatesAndTimes=“urn:Exslt.ExsltDatesAndTimes” xmlns:Exslt.ExsltMath=“urn:Exslt.ExsltMath” xmlns:Exslt.ExsltRegularExpressions=“urn:Exslt.ExsltRegularExpressions” xmlns:Exslt.ExsltStrings=“urn:Exslt.ExsltStrings” xmlns:Exslt.ExsltSets=“urn:Exslt.ExsltSets” xmlns:umbusersguide.library=“urn:umbusersguide.library” exclude-result-prefixes=“msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets umbusersguide.library “> <xsl:output method=“xml” omit-xml-declaration=“yes” /> <xsl:param name=“currentPage”/> <!-- Specify the document type --> <xsl:variable name=“documentTypeAlias” select=“string(‘FAQ’)”/> <xsl:template match=“/”> <!-- Output latest FAQs list --> <h2>Latest FAQs</h2> <ul> <xsl:for-each select=“$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != ‘1’]”> <!-- specify sort order so we get the latest updated FAQ first --> <xsl:sort select=“@updateDate” order=“descending” /> <!-- Test to make sure that the current position in the loop is less than or equal to 3 --> <xsl:if test=“position()<=3”> <li> [<xsl:value-of select=“umbraco.library:FormatDateTime(@updateDate,'MM/dd/yy hh:mm:ss')” />] <a href=“{umbraco.library:NiceUrl(@id)}”> <xsl:value-of select=“@nodeName”/> </a> </li> </xsl:if> </xsl:for-each> </ul> </xsl:template> </xsl:stylesheet>
The following list breaks down what's going on in Listing 11-7:
For good measure, Listing 11-8 shows how to list the latest FAQs in Umbraco version 4.x.
LISTING 11-8: ListLatestFaqs-40x.xslt
<?xml version=“1.0” encoding=“UTF-8”?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp “ ”> ]> <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” xmlns:msxml=“urn:schemas-microsoft-com:xslt” xmlns:umbraco.library=“urn:umbraco.library” xmlns:Exslt.ExsltCommon=“urn:Exslt.ExsltCommon” xmlns:Exslt.ExsltDatesAndTimes=“urn:Exslt.ExsltDatesAndTimes” xmlns:Exslt.ExsltMath=“urn:Exslt.ExsltMath” xmlns:Exslt.ExsltRegularExpressions=“urn:Exslt.ExsltRegularExpressions” xmlns:Exslt.ExsltStrings=“urn:Exslt.ExsltStrings” xmlns:Exslt.ExsltSets=“urn:Exslt.ExsltSets” xmlns:umbusersguide.library=“urn:umbusersguide.library” exclude-result-prefixes=“msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets umbusersguide.library “> <xsl:output method=“xml” omit-xml-declaration=“yes” /> <xsl:param name=“currentPage”/> <!-- Specify the document type --> <xsl:variable name=“documentTypeAlias” select=“string(‘FAQ’)”/> <xsl:template match=“/”> <!-- Output latest FAQs list --> <h2>Latest FAQs</h2> <ul> <xsl:for-each select=“$currentPage/node [@nodeTypeAlias=$documentTypeAlias and string(data [@alias=‘umbracoNaviHide’]) != ‘1’]”> <!-- specify sort order so we get the latest updated FAQ first --> <xsl:sort select=“@updateDate” order=“descending” /> <!-- Test to make sure that the current position in the loop is less than or equal to 3 --> <xsl:if test=“position()<=3”> <li> [<xsl:value-of select=“umbraco.library:FormatDateTime(@updateDate,'MM/dd/yy hh:mm:ss')” />] <a href=“{umbraco.library:NiceUrl(@id)}”> <xsl:value-of select=“@nodeName”/> </a> </li> </xsl:if> </xsl:for-each> </ul> </xsl:template> </xsl:stylesheet>
For a list of available node set functions, see Table 11-2.
FUNCTION | DESCRIPTION |
last() | Returns the number of nodes in a node set. |
position() | Returns the position of the context node (current node). The starting value is 1. As you loop through each node, the position increments. |
count(node1, node2, …) | Returns the total number of nodes in the node set as provided between the parentheses. If you leave the parentheses blank, it will use the context node. |
id((string1, string2, …) node) | Returns the nodes whose ID matches the string (s) passed to the function. |
local-name(node_set) | Returns the local name of the first node in the node set. The local name is the name without the namespace prefix. To use the context node, simply leave node_set blank. |
name(node_set) | Returns the full, qualified name of the first node in the node set. To use the context node, simply leave node_set blank. |