advanced xsl learn how to use advanced xslt techniques, exslt, and xalan extensions to solve...
TRANSCRIPT
Advanced XSL
Learn how to use advanced XSLT techniques, EXSLT, and Xalan extensions
to solve complicated problems.
2008 Cascade Server User’s Conference Amy Liu & Brett Goodwin
Amy Liu & Brett Goodwin
Agenda
XSL & XSLTXSLT Warmup
Muenchian MethodEXSLT
Xalan ExtensionsVelocity Script Formats
09/22/2008
Amy Liu & Brett Goodwin
XSL & XSLT
• XSL (eXtensible Stylesheet Language) consists of three parts:– XSLT
a language for transforming XML documents
– XPatha language for navigating in XML documents
– XSL:FOa language for formatting XML documents
09/22/2008
Amy Liu & Brett Goodwin
http://www.w3schools.com/xsl/xsl_w3celementref.asp
XSLT Warmup• <xsl:template match=“xpath-expression”></xsl:template>
• <xsl:value-of select=“xpath-expression”/><xsl:copy-of select=“xpath-expression/node()”/>
• <xsl:call-template name=“template-name"/><xsl:apply-templates select=“xpath-expression”/><xsl:for-each select=“xpath-expression”></xsl:for-each>
• <xsl:if test=“expression=‘boolean’”></xsl:if><xsl:choose>
<xsl:when test=“expression”></xsl:when><xsl:otherwise></xsl:otherwise>
</xsl:choose>
• <xsl:sort select=“xpath-expression” order=“descending”/>
09/22/2008
Amy Liu & Brett Goodwin
Using { } in place of <xsl:value-of/><xsl:variable name=“default-page”>
index</xsl:variable>
<xsl:template match=“something”> <a> <xsl:attribute name=“href”> <xsl:value-of select=“path”/> <xsl:text>/</xsl:text> <xsl:value-of select=“$default-
page”/> </xsl:attribute> <xsl:value-of select="display-name"/> </a></xsl:template>
<xsl:variable name=“default-page”> index</xsl:variable>
<xsl:template match=“something”> <a href=“{path}/{$default-page}”> <xsl:value-of select="display-name"/> </a></xsl:template>
09/22/2008
Amy Liu & Brett Goodwin
Problem #1:Categorical Grouping…
Example Scenario:You have categorized a set of pages within
Cascade Server by utilizing Custom Metadata checkboxes.
Now, you would like to create a listing of all the categories along with the list of pages that belong to each category in alphabetical order for display on a “Campus Resources” page.
09/22/2008
[01grouping.xml]
Amy Liu & Brett Goodwin
1st Attempt:Easy-&-High-Maintenance Method
<xsl:template match=“/system-index-block”> <h1>Campus Resources</h1> <h3>Alumni</h3> <ul><xsl:apply-templates select=“//system-page[dynamic-metadata[name=‘Audience’]/value =
‘Alumni’]”><xsl:sort select=“display-name”/></xsl:apply-templates></ul> <h3>Current Students</h3> <ul><xsl:apply-templates select=“//system-page[dynamic-metadata[name=‘Audience’]/value = ‘Current
Students’]”><xsl:sort select=“display-name”/></xsl:apply-templates></ul> <h3>Prospective Students</h3> <ul><xsl:apply-templates select=“//system-page[dynamic-metadata[name=‘Audience’]/value = ‘Prospective
Students’]”><xsl:sort select=“display-name”/></xsl:apply-templates></ul> <h3>Visitors</h3> <ul><xsl:apply-templates select=“//system-page[dynamic-metadata[name=‘Audience’]/value =
‘Visitors’]”><xsl:sort select=“display-name”/></xsl:apply-templates></ul></xsl:template><xsl:template match=“system-page”> <li><xsl:value-of select=“display-name”/></li></xsl:template>
09/22/2008
[02grouping-attempt.xsl]
Amy Liu & Brett Goodwin
Muenchian Method!<xsl:key name=“unique-values” match=“//system-page/dynamic-metadata[name=‘Audience’]/value” use=“.”/><xsl:template match=“/system-index-block”> <h1>Campus Resources</h1> <xsl:apply-templates select=“//system-page/dynamic-metadata[name=‘Audience’]/value[generate-id()
=generate-id(key(‘unique-values’, .))]”> <xsl:sort select=“.”/> </xsl:apply-templates></xsl:template><xsl:template match=“value”> <xsl:variable name=“currentValue” select=“.”/> <h3><xsl:value-of select=“.”/></h3> <ul> <xsl:for-each select=“//system-page[dynamic-metadata[name=‘Audience’]/value=$currentValue]”> <xsl:sort select=“display-name”/> <li><xsl:value-of select=“display-name”/></li> </xsl:for-each> </ul></xsl:template>
09/22/2008
[03muenchian.xsl]
Amy Liu & Brett Goodwin
Problem #2:Truncating Content…
Example Scenario:Your users are now familiar with Cascade and
have created several blog posts within the system. You would like to set up some sort of landing page that features the latest blog posts.
09/22/2008
[04recent-blogs.xml]
Amy Liu & Brett Goodwin
1st Option:List 3 Latest Posts + Full Content
<xsl:template match=“system-index-block”> <xsl:apply-templates select=“//system-page”> <xsl:sort order=“descending” select=“start-date”/> </xsl:apply-templates></xsl:template>
<xsl:template match=“system-page”> <xsl:if test=“position() < 4”> <h3><xsl:value-of select=“title”/></h3> <xsl:copy-of select=“page-xhtml/node()”/> </xsl:if></xsl:template>
09/22/2008
[05full-listing.xsl]
Amy Liu & Brett Goodwin
2nd Option:Truncate using Character Count
<xsl:variable name=“char-count” select=“216”/><xsl:template match=“system-index-block”> <xsl:apply-templates select=“//system-page”> <xsl:sort order=“descending” select=“start-date”/> </xsl:apply-templates></xsl:template>
<xsl:template match=“system-page”> <h3><xsl:value-of select=“title”/></h3> <p> < xsl:copy-of select=“substring(page-xhtml, 1, $char-count)”/> <xsl:text>...</xsl:text> </p> <p><a href=“{path}” title=“More”>More...</a></p></xsl:template>
09/22/2008
[06truncate-charcount.xsl]
Amy Liu & Brett Goodwin
3rd Option:Truncate after Whole Words
<xsl:variable name=“char-count” select=“216”/><xsl:template match=“system-index-block”> …</xsl:template><xsl:template match=“system-page”> <h3><xsl:value-of select=“title”/></h3> <p><xsl:call-template name=“parse”> <xsl:with-param name=“unrendered”> <xsl:variable name=“truncated-result”> <xsl:call-template name=“truncate-markup-text”> <xsl:with-param name=“unrendered” select=“page-
xhtml”/> </xsl:call-template> </xsl:variable> <xsl:value-of select=“substring-after($truncated-result,
‘]’)”/> </xsl:with-param> </xsl:call-template></p> <p><a href=“{path}” title=“More”>More...</a></p></xsl:template><xsl:template name=“truncate-markup-text”> <xsl:param name=“unrendered”/> <xsl:param name=“characters-chugged” select=“number(0)”/>
…</xsl:template><xsl:template name=“count-markup-text”> <xsl:param name=“content”/> <xsl:param name=“characters-chugged” select=“number(0)”/> <xsl:value-of select=“concat($characters-chugged + string-
length($content),‘]’)”/> …</xsl:template><xsl:template name=“get-trimmed-string”> <xsl:param name=“string”/> …</xsl:template><xsl:template name=“parse”> <xsl:param name=“unrendered”/> …</xsl:template><xsl:template name=“parseTagContent”> <xsl:param name=“tag”/> <xsl:param name=“tag-content”/> …</xsl:template>
09/22/2008
[07truncate-wordcount.xsl]
7 Templates382 Lines
15,167 Characters
Amy Liu & Brett Goodwin
EXSLT• Although XSLT lacks features like loops and mutable variables, it is considered
Turing-complete, meaning that given sufficient memory, XSLT can perform any calculation that can be performed by a modern computer program. However, this theoretical ability is often impractical.
• EXSLT is a community initiative to provide extensions to XSLT 1.0 and to partition them into functional groups that can be implemented on an á la carte basis. The EXSLT effort is an open one; anyone who wishes to contribute may do so. http://www.exslt.org/
• Many of the functions in EXSLT are simply shortcuts to equivalent behaviors that can be achieved using XSLT templates. For these functions, the EXSLT authors have provided XSLT templates that may be imported into existing style sheets. This approach offers the most portability, as all XSLT 1.0-compliant processors are able to correctly interpret the template and provide the functionality.
09/22/2008
Amy Liu & Brett Goodwin
3rd Option:Truncate using str:tokenize()
<xsl:variable name=“word-count” select=“37”/><xsl:template match=“system-index-block”> <xsl:apply-templates select=“//system-page”> <xsl:sort order=“descending” select=“start-date”/> </xsl:apply-templates></xsl:template><xsl:template match=“system-page”> <h3><xsl:value-of select=“title”/></h3> <p> <xsl:for-each select=“str:tokenize(string(page-xhtml))”> <xsl:if test=“position() < $word-count”> <xsl:value-of select=“.”/><xsl:text> </xsl:text> </xsl:if> </xsl:for-each> <xsl:text>...</xsl:text> </p> <p><a href=“{path}” title=“More”>More...</a></p></xsl:template>
09/22/2008
[08exslt-tokenizer.xsl]
<xsl:stylesheet version=“1.0”xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”xmlns:str=“http://exslt.org/strings”extension-element-prefixes=“str” >
Be sure to specify the extension namespace URI & use the extension-element-prefix!
Amy Liu & Brett Goodwin
Problem #3:Formatting Date & Time…
Example Scenario:Now that you have successfully truncated your
blog posts, the next item to tackle is to format and display the date/time that is associated with each post.
As you probably know, all date values within Cascade are represented in UNIX timestamp format (i.e., <start-date>1221165000000</start-date>).
09/22/2008
[04recent-blogs.xml]
Amy Liu & Brett Goodwin
Problem #3:Formatting Date & Time…
• If you were to attempt this calculation using only native XSLT 1.0, it will probably take about 304 lines or 10,345 characters.
• The EXSLT Dates-and-Times functions don’t have anything readily available for use with UNIX timestamps.
• Any other options?
09/22/2008
Amy Liu & Brett Goodwin
That’s right!Xalan Extensions
• Xalan is the XSLT processor that Cascade Server utilizes.• For those situations where you would like to augment the functionality
of XSLT with calls to a procedural language, Xalan-Java supports the creation and use of extension elements and extension functions.
• The Xalan XSLT processor can invoke almost any method in almost any Java™ class in the classpath. Doing so can improve performance, provide features like trigonometric functions that aren't available in XSLT, perform file I/O, talk to databases and network servers, or implement algorithms that are easy to write in the Java language but hard to write in XSLT.
• Typically, you'll resort to using Xalan extensions when you can't accomplish what you need using the existing XSLT or EXSL functions and need to write your own custom functions in Javascript or Java.
09/22/2008
Amy Liu & Brett Goodwin
Xalan Date Converter <p class=“date”> <xsl:value-of select=“date-
converter:convertMonth(number(start-date))”/> 
<xsl:value-of select=“date-converter:convertDate(number(start-date))”/>,
<xsl:value-of select=“date-converter:convertYear(number(start-date))”/>
</p><h3><xsl:value-of select=“title”/></h3><p><xsl:for-each select=“str:tokenize(string(page-
xhtml))”> <xsl:if test=“position() < $word-count”> <xsl:value-of select=“.”/> <xsl:text> </xsl:text> </xsl:if></xsl:for-each><xsl:text>...</xsl:text></p>
<xalan:component functions="convertDate" prefix="date-converter">
<xalan:script lang="javascript"> function convertMonth(date) { var months = new Array(13); months[0] = "January"; months[1] = "February"; months[2] = "March"; months[3] = "April"; months[4] = "May"; months[5] = "June"; months[6] = "July"; months[7] = "August"; months[8] = "September"; months[9] = "October"; months[10] = "November"; months[11] = "December"; var d = new Date(date); // Splits date into components var month = months[d.getMonth()]; return month; } convertDay(date) {…} convertDate(date) {…} convertYear(date) {…} convertTime(date) {…} </xalan:script></xalan:component>
09/22/2008
[09xalan-convertdate.xsl]
Amy Liu & Brett Goodwin
Velocity! The Non-XSLT Bonus
• Velocity is a Java-based template engine that Cascade Server will support starting with version 5.7
• It can be used to generate web pages, SQL, PostScript and other output from templates
• Velocity Template Language (VTL) should have a lower learning curve than XSLT for developers who are already familiar with traditional programming languages
• Utilizing VTL Formats, in some cases, can simplify the transformation code within Cascade
http://velocity.apache.org/engine/devel/user-guide.html
09/22/2008
Amy Liu & Brett Goodwin
Context Menu Comparison
XSLT Format<xsl:template match=“/”> <ul> <xsl:apply-templates select=“//system-
page | //system-folder”/> </ul></xsl:template><xsl:template match=“system-page | system-
folder”> <li> <a href=“{path}”> <xsl:value-of select=“name”/> </a> </li></xsl:template>
VTL Format<ul> #foreach ($child in $contentRoot.children) <li> <a href=“$child.getChild(“path”).text”> $child.getChild(“name”).text </a> </li> #end </ul>
09/22/2008