660 likes | 811 Views
4.1 Additional XSLT Features. XPath for arithmetics , cross-references, and string manipulation Generating text for content for attribute values Repetition, sorting and conditional processing Numbering document contents 4.2 Computing with XSLT. XPath : Arithmetics.
E N D
4.1 Additional XSLT Features • XPath for arithmetics, cross-references, and string manipulation • Generating text • for content • for attribute values • Repetition, sorting and conditional processing • Numbering document contents 4.2 Computing with XSLT XSLT: Additional features & Computing
XPath: Arithmetics • Double-precision floating-point operators +, -, *, div, mod(same as %in Java) • e.g. 2.3 mod 1.1≈ 0.1 • Truncating numbers, and rounding up/to the closest int: floor(x), ceiling(x), round(x) • Formatting numbers as strings (e.g.): • format-number(-1.2534, "0.0") = "-1.3" • XSLT 1.0 function; uses Java DecimalFormat patterns XSLT: Additional features & Computing
Aggregate Functions • Counting nodes • count(node-set) • and summing them as numbers • sum(node-set) • Example: • Average of observed temps below current node:sum(.//obs/@temperature) div count(.//obs) XSLT: Additional features & Computing
Cross-referencing • Function idselects elements by their unique ID • NB: ID attributes must be declared in DTD(See an example later) • Examples: • id('sec:intro')selects the element with unique ID"sec:intro" • id('sec:intro')/auth[3]selects the thirdauthof the above element • id('sec1 sec2 sec3')selects 3 sections (with corresponding ID values) XSLT: Additional features & Computing
String manipulation • Equality and inequality of strings with operators=and!= • "foo" = 'foo'; (NB alternative quotes) • "foo" != "Foo" • Testing for substrings: • starts-with("dogbert", "dog") = true() • contains("dogbert", "gbe") = true() • Concatenation (of two or more strings), • concat("dog", "bert") = "dogbert" XSLT: Additional features & Computing
More XPath string functions • substring-before("ftp://a", "//") = substring-before("ftp://a", "/") = "ftp:" • substring-after("ftp://a", "/")= "/a" • string-length("dogbert")=7 • substring(string, start, length?): • substring("dogbert", 1, 3) = "dog" • substring("dogbert", 3) = "gbert" • translate(Str, Replaced, Replacing): • translate("doggy","dgo","Ssi") = "Sissy" XSLT: Additional features & Computing
Generating Text • Insert text nodes with a computed value in the result:<xsl:value-of select="Expr" /> • if Expr gives a node-set, the value of the first nodein document order is used (in XSLT 2.0 all, space-separated) • Example: Transform elements like • <name alias="Bird"> <first>Charlie</first><last>Parker</last></name> • to the form • Charlie ("Bird") Parker XSLT: Additional features & Computing
Computing generated text (2) • This can be specified by template rule <xsl:template match="name"> <xsl:value-of select="first" />("<xsl:value-of select="@alias" />") <xsl:value-of select="last" /> <xsl:text> </xsl:text></xsl:template> • xsl:textis seldom needed, but useful for including whitespace text XSLT: Additional features & Computing
Attribute value templates • Expression string-values can be inserted in attribute values by enclosing expressions in braces{and} • Example: Transform source element <photo> <file>Mary.jpg</file> <size width="300"/> </photo>into form <img src="/images/Mary.jpg" width="300" /> XSLT: Additional features & Computing
Attribute value templates (2) • This can be specified by template rule <xsl:template match="photo"> <img src="/images/{file}" width="{size/@width}" /> </xsl:template> • Expressions{file}and{size/@width} are evaluated in the context of the current node (the photoelement) XSLT: Additional features & Computing
XSLT: Repetition • Nodes can be "pulled" from source for processing using <xsl:for-each select="Expr">Template </xsl:for-each> • Template is applied to the selected nodelist, each node in turn as the current() node • in document order, unless sorted using xsl:sort instructions (see later) XSLT: Additional features & Computing
Example (of for-each) • Format the below document as HTML: <!DOCTYPE document [ <!ATTLIST section id ID #IMPLIED> ]><document> <title>The Joy of XML</title> <section id="Intro"><title>Getting Started</title> <name><first>Helen</first> <last>Brown</last></name> says that processing XML documents is fun. <name><first>Dave</first> <last>Dobrik</last></name> agrees. </section> <section><title>Family affairs</title> <name><first>Bob</first> <last>Brown</last></name> is the husband of <name><first>Helen</first> <last>Brown</last></name>. </section> <section><title>Finishing Up</title> As we discussed in <title-ref idref="Intro" />, processing XML documents is fun. </section></document> XSLT: Additional features & Computing
Example: Table of contents • A table of contents can be formed of section titles: <xsl:template match="/"><HTML><HEAD> <TITLE><xsl:value-of select="document/title"/></TITLE></HEAD> <BODY> <H2>Table of Contents</H2> <OL> <!-- Pull each section title: --> <xsl:for-each select="//section/title"> <LI><xsl:apply-templates /></LI> </xsl:for-each> </OL> <!-- then process the sections: --> <xsl:apply-templates select="document/section"/> </BODY> </HTML></xsl:template> XSLT: Additional features & Computing
Example (cont; Cross references) • Cross-refs can also be processed usingfor-each: <xsl:template match="title-ref"> <xsl:for-each select="id(@idref)"> <!-- just one selected --> Section (<xsl:value-of select="substring(title, 1, 8)" />...)</xsl:for-each></xsl:template> • With this rule the source fragment As we discussed in <title-ref idref="Intro"/> becomes As we discussed in Section (Getting …) XSLT: Additional features & Computing
XSLT Sorting • Nodes can be processed in sorted order, by xsl:for-eachor xls:apply-templates, with <xsl:sort/> • controlled by attributes ofxsl:sort, like • select: expression for the sort key (default: ".") • data-type: "text"(default) or"number" • order:"ascending" (default) or "descending" • The first xsl:sort specifies the primary sort key, the second one the secondary sort key, and so on. XSLT: Additional features & Computing
Possible to eliminate duplicates?Yes, but a bit tricky. See next Example (cont; Sorted index of names) • All names can be collected in a last-name-first-name order using the below template <H2>Index</H2> <UL> <xsl:for-each select="//name"> <xsl:sort select="last" /> <xsl:sort select="first" /> <LI><xsl:value-of select="last" />, <xsl:value-of select="first"/></LI> </xsl:for-each> </UL> • This creates an UL list with items <LI>Brown, Bob</LI> <LI>Brown, Helen</LI> <LI>Brown, Helen</LI> <LI>Dobrik, Dave</LI> XSLT: Additional features & Computing
Conditional processing • A template can be instantiated or ignored with <xsl:iftest="BooleanExpr">Template</xsl:if> • Example: a comma-separated list of names: <xsl:template match="namelist/name"> <xsl:apply-templates/> <xsl:iftest="position() < last()" >,</xsl:if></xsl:template> XSLT: Additional features & Computing
An aside: Meaning of position() • Evaluation wrt the current node list. The above applied to <namelist><name>a</name><name>b</name></namelist> <namelist><name>c</name><name>d</name></namelist>by invocation<xsl:apply-templates select="//name" />yields"a,b,c,d" (← single node list); With invocation from<xsl:template match="namelist"> <xsl:apply-templates select="name" />we'd get"a,b"and"c,d" (Clever!) XSLT: Additional features & Computing
Conditional processing (2) • A case construct ( switch in Java): <xsl:choose> <!-- The first 'when' whose test=true() is instantiated: --> <xsl:when test="Expr1"> … </xsl:when> <xsl:when test="Expr2"> … </xsl:when> … <!-- If no 'when' applies, an optional 'otherwise' is instantiated: --> <xsl:otherwise> … </xsl:otherwise> </xsl:choose> XSLT: Additional features & Computing
Example (cont; Eliminating duplicate names) • Only the current() node accessible in current node list • but can refer to nodes in the source tree • Process just the first one of duplicate names: <xsl:for-each select="//name"> <xsl:sort select="last"/><xsl:sort select="first" /> <xsl:if test="not( preceding::name[first=current()/first and last=current()/last] )"> <LI><xsl:value-of select="last" />, <xsl:value-of select="first"/></LI></xsl:if> </xsl:for-each> XSLT: Additional features & Computing
Numbering Document Contents • Formatted numbers can be generated using <xsl:number/> • by the position of the current node in the source tree • or by an explicit value="ArithmExpr" • nodes to be counted specified by a count pattern • supports common numbering schemes : single-level, hierarchical, and sequential through levels • Typical cases in following examples • (Complete specification is rather complex) • Example 1: Numbering list items XSLT: Additional features & Computing
item item item ol 1. 2. 3. apricot banana coconut Generating numbers: Example 1 • <xsl:template match="ol/item"> <!-- default: count similar siblings (items) --><xsl:number format="1. "/> <xsl:apply-templates/><xsl:template> apricot banana coconut XSLT: Additional features & Computing
Generating numbers: Example 2 • Hierarchical numbering (1, 1.1, 1.1.1, 1.1.2, …) for titles of chapters, titles of their sections, and titles of subsections: <xsl:template match="title"><xsl:number level="multiple" count="chap | sect | subsect" format="1.1 "/> <xsl:apply-templates/></xsl:template> XSLT: Additional features & Computing
subsect title title title title chap part Sweets 1 1.1 1.1.1 2 Cherry chap Berries sect Generating numbers: Example 2 . . . Vegetables Sweets Berries Cherry Vegetables . . . XSLT: Additional features & Computing
Example 2: Variation • As above, but number titles within appendices with A, A.1, A.1.1, B.1 etc: <xsl:template match="appendix//title"><xsl:number level="multiple" count="appendix | sect | subsect" format="A.1 "/> <xsl:apply-templates/></xsl:template> XSLT: Additional features & Computing
appendix subsect title title title title part Sweets A A.1 A.1.1 B Cherry Berries sect Example 2: Variation appendix . . . Vegetables Sweets Berries Cherry Vegetables . . . XSLT: Additional features & Computing
Generating numbers: Example 3 • Sequential numbering of noteswithinchapters:(more precisely: starting anew at the start of any chapter) <xsl:template match="note"><xsl:number level="any" from="chap" format="(1) "/> <xsl:apply-templates/></xsl:template> XSLT: Additional features & Computing
chap note note note note Yes! (1) (2) (3) (1) Yes! No! Perhaps? OK Perhaps? No! sect Ex 3: Sequential numbering from chap chap . . . OK . . . XSLT: Additional features & Computing
4.2 Computing with XSLT • XSLT is a declarative rule-based language • for XML transformations • Could we use it for general computing? • What is the exact computational power of XSLT? • We've seen some programming-like features: • iteration over source nodes (xsl:for-each) • XSLT 2.0 supports iteration over arbitrary sequences • conditional evaluation (xsl:ifandxsl:choose) XSLT: Additional features & Computing
Computing with XSLT • Further programming-like features: • variables (names bound to non-updatable values): <xsl:for-each select="//name"><xsl:variable name="LAndF" select="concat(last, ', ', first)"/>... ...</xsl:for-each> • callablenamed templateswithparameters:<xsl:call-template name="process-name"> <xsl:with-param name="pname" select="$LAndF" /> </xsl:call-template> XSLT: Additional features & Computing
Result Tree Fragments • Result tree fragments built by templates can be stored, too:<xsl:variable name="fooBar"> <FOO>BAR</FOO></xsl:variable> • They can only be used as string valuessubstring($fooBar, 2, 2) = "AR" • or inserted in the result:<xsl:copy-of select="$fooBar" /> • (XSLT 2.0 allows unlimited accessing of (computed) sequences, e.g., with location paths) XSLT: Additional features & Computing
Visibility of Variable Bindings • The binding is visible in following siblings of xsl:variable,and in their descendants: <xsl:for-each select="//name"><xsl:variable name="LAndF" select="concat(last, ', ', first)"/>... <xsl:call-template name="process-name"> <xsl:with-param name="pname" select="$LAndF" /> </xsl:call-template> ...</xsl:for-each><TABLE> . . . </TABLE> XSLT: Additional features & Computing
A Real-Life Example • We used LaTeX to format an XML article. For this, we needed to map source table structures<tgroup cols="3"> ... </tgroup>to corresponding LaTeX environments:\begin{tabular}{lll} %3 left-justified cols ... \end{tabular} • How to do this? XSLT: Additional features & Computing
Possible solution (for up to 4 columns) <xsl:template match="tgroup"> \begin{tabular}{l }<xsl:apply-templates /> \end{tabular} </xsl:template> • OK, but inelegant! • How to support arbitrarily many columns? <xsl:if test="@cols > 1">l</xsl:if ><xsl:if test="@cols > 2">l</xsl:if ><xsl:if test="@cols > 3">l</xsl:if> XSLT: Additional features & Computing
More General Solution (1/2) • Pass the column-count to a named template which generates the requested number of ‘l’s:<xsl:template match="tgroup"> \begin{tabular}{ } <xsl:apply-templates /> \end{tabular} </xsl:template> <xsl:call-template name="gen-cols"> <xsl:with-param name="count" select="@cols" /> <xsl:with-param name="symb" select="'l'" /> </xsl:call-template> XSLT: Additional features & Computing
formal parameters Solution 2/2: Recursive gen-cols <xsl:template name="gen-cols"> <xsl:param name="count" /> <xsl:param name="symb" /> <xsl:if test="$count > 0"> <xsl:value-of select="$symb" /> <xsl:call-template name="gen-cols"> <xsl:with-param name="count" select="$count - 1" /> <xsl:with-param name="symb" select="$symb" /> </xsl:call-template> </xsl:if> </xsl:template> XSLT: Additional features & Computing
Iteration in XSLT 2.0 • XSLT 2.0 is more convenient, by allowing iteration over generated sequences, too:<xsl2:template match="tgroup">\begin{tabular}{<xsl2:for-each select="1 to @cols"> <xsl2:text>l</xsl2:text> </xsl2:for-each>} \end{tabular} </xsl2:template> XSLT: Additional features & Computing
StylesheetParameters • Stylesheetcangetparamsfromcommandline, orthrough JAXP withTransformer.setParameter(name, value): <xsl:transform ... > <xsl:output method="text" /> <xsl:param name="In" select="0" /><xsl:template match="/"> <xsl:value-of select="2*$In"/> </xsl:template> </xsl:transform> $ java -jar saxon.jar dummy.xml double.xslt In=120 240 default value XSLT: Additional features & Computing
Generating XML TestCases • XSLT is handy for generating XML test cases • An XSLT 2.0 script to generate n sections: <!DOCTYPE xsl:transform [ <!ENTITY CONT "<xsl:comment>Lengthy XML fragment (excluded)</xsl:comment>" > ]> <xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="n" select="10"/> XSLT: Additional features & Computing
XSLT 2.0 scriptcontinues <xsl:template match="/"> <doc> <title>A doc with <xsl:value-of select="$n"/> sections</title> <xsl:for-each select="1 to $n"> <section> <title>Section number <xsl:value-of select="." /> </title> &CONT; </section> </xsl:for-each> </doc> </xsl:template> </xsl:transform> Extensions in XPath 2.0, to generate and access non-nodesequences XSLT: Additional features & Computing
Invoking the Script • The script can be used as the required (dummy) input document: $ saxon9 genTest-iter.xsltgenTest-iter.xslt n=1000 • XSLT 1.0 does not support iteration over generated sequences ; In XSLT 1.0 we must recurse: <doc> <title>A doc with <xsl:value-of select="$n"/> sections</title> <xsl:call-template name ="genSecs"> <xsl:with-param name="count" select="1"/> </xsl:call-template> </doc> XSLT: Additional features & Computing
Tail-recursivegenSecstemplate <xsl:template name="genSecs"> <xsl:param name="count" /> <xsl:if test="$count <= $n"> <section><title>Section <xsl:value-of select="$count"/></title> &CONT; </section> <!-- Create the rest sections: --> <xsl:call-template name="genSecs"> <xsl:with-param name="count" select="$count + 1" /> </xsl:call-template> </xsl:if> </xsl:template> XSLT: Additional features & Computing
Problem with Tail-Recursion • The depth of tail-recursion is linear. This may lead to problems with large n (say, above a few thousands): • Saxon:StackOverflowError • xsltproc: "A potential infinite template recursion was detected. You can adjust xsltMaxDepth (--maxdepth) in order to raise the maximum number of nested template calls and variables/params (currently set to 3000)." • Solution: Enter Algorithm Design! SDPL 2008 XSLT: Additional features & Computing 43
Apply Divide-and-Conquer • Split the problem/task in (equal-sized) sub-problems, and solve them recursively • To generate secs$first, ..., $last, compute their mid-point $mid, and generate the halves $first, ..., $mid, and $mid+1, ..., $last: • <xsl:call-templatename="genSecsDC"> • <xsl:with-param name="first" select="1"/> • <xsl:with-param name="last" select="$n"/> • </xsl:call-template> SDPL 2008 XSLT: Additional features & Computing 44
Divide-and-ConquergenSecstemplate <xsl:templatename="genSecsDC"> <xsl:paramname="first" /> <xsl:paramname="last" /> <xsl:choose> <xsl:when test="$first = $last"> <!-- base case --> <section> <title>Section number <xsl:value-of select="$first"/></title> &CONT; </section> </xsl:when> <!-- otherwise recurse: --> SDPL 2008 XSLT: Additional features & Computing 45
Divide&ConquergenSecs (cont.) <xsl:when test="$first < $last"> <xsl:variable name="mid" select="floor(($first + $last) div 2)" /> <xsl:call-template name="genSecsDC"> <xsl:with-param name="first" select="$first" /> <xsl:with-param name="last" select="$mid" /> </xsl:call-template> <xsl:call-template name="genSecsDC"> <xsl:with-param name="first" select="$mid+1" /> <xsl:with-param name="last" select="$last" /> </xsl:call-template> </xsl:when> </xsl:choose> </xsl:template> SDPL 2008 XSLT: Additional features & Computing 46
Balanced D&C Recursion Tree (draw it!) SDPL 2008 XSLT: Additional features & Computing 47
Effect of Divide-and-Conquer • The depth of balanced divide-and-conquer recursion is logarithmic only • E.g., log(10^6) ~ 20, log(10^9) ~ 30 • Piece of cake! • Divide-and-conquer doubles the number of recursive calls above. Does this make a big difference? • No; See next SDPL 2008 XSLT: Additional features & Computing 48
XSLT 1.0 execution times $ timesaxongenTest-tailrec.xsltgenTest-tailrec.xslt n=1000000 > /dev/null real 0m12.808s user 0m12.924s sys 0m0.104s $ timesaxongenTest-tailrec.xsltgenTest-dc.xslt n=1000000 > /dev/null real 0m13.871s (~8% more) user 0m14.016s sys 0m0.088s Div&Conquerscript SDPL 2008 XSLT: Additional features & Computing 49
Iteration vs Tail-recursion vs Div&Conq Some XSLT 2.0 execution times: $ time saxon9 dummy.xmlgenTest-iter.xslt n=1000000 real 0m11.277s user 0m10.118s $ time saxon9 dummy.xmlgenTest-tailrec.xslt n=1000000 real 0m24.803s (~120% morethaniteratively) user 0m24.658s $ time saxon9 dummy.xmlgenTest-dc.xslt n=1000000 real 0m29.779s (~164% morethaniteratively) user 0m30.178s SDPL 2008 XSLT: Additional features & Computing 50