Reverse Order
Sometimes you want to display a list of items in the reverse order than they appear in the document.
http://www.biglist.com/lists/xsl-list/archives/200105/msg00236.html shows how:
<xsl:apply-templates select="item">
<xsl:sort select="position()" data-type="number" order="descending" />
</xsl:apply-templates>
Non-breaking Space
Short answer: use   instead of
Long answer:
http://www.dpawson.co.uk/xsl/sect2/nbsp.html
Passthrough
This transform (which I learned from the guys that wrote the most excellent
Maverick MVC framework) passes everything through unmolested.
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Links
http://www.jenitennison.com/xslt/ - lots of good XSLT tips
http://www.jenitennison.com/xslt/grouping/index.xml - how to group items in XSLT (can be used to emulate sql's "select distinct" functionality)
http://www.dpawson.co.uk/xsl/sect2/N3328.html - testing whether an element is empty or not (in the many different ways that it can be empty)
Translets vs. Templates
I wanted to see if pre-compiled translets were any faster than
Templates so I found some code to compile and run them, and did some micro-benchmarks. Bottom line: translets didn't transform XML faster than Templates, maybe even a little slower. The big win was in initialization but I don't really care about that. Given that translets require Xalan and Templates are built in to Sun's Java I think I'll stick with Templates. While I was at it I tried Java .15 and 1.6 and Saxon 8. I was surprised that Saxon didn't kick the shit out of Xalan - it sure did back in 2003, but now they're in the same ballpark.
using Xalan's "birds" example files, running 5000 times:
first: Templates t = tf.newTemplates(new StreamSource(URI));
second: Transformer transformer = t.newTransformer();
third: transformer = tf.newTransformer(new StreamSource(URI));
fourth: transformer.transform(document, result);
using XSL as input, generating Templates:
before newTemplates: 1189707648447
after newTemplates: 1189707667564
before newTransformer: 1189707667564
after newTransformer: 1189707667665
before newTransformer: 1189707667665
after newTransformer: 1189707689644
before transform: 1189707689645
after transform: 1189707693274
before newTemplates: 1189707738107
after newTemplates: 1189707757511
before newTransformer: 1189707757511
after newTransformer: 1189707757623
before newTransformer: 1189707757624
after newTransformer: 1189707779782
before transform: 1189707779783
after transform: 1189707783361
before newTemplates: 1189707955318
after newTemplates: 1189707974624
before newTransformer: 1189707974624
after newTransformer: 1189707974747
before newTransformer: 1189707974747
after newTransformer: 1189707996928
before transform: 1189707996929
after transform: 1189708000522
using pre-compiled translets:
before newTemplates: 1189707581547
after newTemplates: 1189707581633
before newTransformer: 1189707581634
after newTransformer: 1189707581770
before newTransformer: 1189707581770
after newTransformer: 1189707581905
before transform: 1189707581906
after transform: 1189707585838
before newTemplates: 1189707596774
after newTemplates: 1189707596867
before newTransformer: 1189707596867
after newTransformer: 1189707597004
before newTransformer: 1189707597004
after newTransformer: 1189707597131
before transform: 1189707597132
after transform: 1189707601164
before newTemplates: 1189707611967
after newTemplates: 1189707612056
before newTransformer: 1189707612056
after newTransformer: 1189707612193
before newTransformer: 1189707612193
after newTransformer: 1189707612330
before transform: 1189707612331
after transform: 1189707616274
using Java 1.5 Templates:
before newTemplates: 1189709259413
after newTemplates: 1189709266558
before newTransformer: 1189709266559
after newTransformer: 1189709267926
before newTransformer: 1189709267926
after newTransformer: 1189709274038
before transform: 1189709274039
after transform: 1189709280763
before newTemplates: 1189709331211
after newTemplates: 1189709338562
before newTransformer: 1189709338562
after newTransformer: 1189709339942
before newTransformer: 1189709339942
after newTransformer: 1189709346095
before transform: 1189709346096
after transform: 1189709352755
before newTemplates: 1189709372059
after newTemplates: 1189709379414
before newTransformer: 1189709379414
after newTransformer: 1189709380865
before newTransformer: 1189709380865
after newTransformer: 1189709386942
before transform: 1189709386942
after transform: 1189709393634
using Java 1.6 Templates:
before newTemplates: 1189709444012
after newTemplates: 1189709450754
before newTransformer: 1189709450754
after newTransformer: 1189709452169
before newTransformer: 1189709452170
after newTransformer: 1189709457757
before transform: 1189709457758
after transform: 1189709464277
before newTemplates: 1189709482416
after newTemplates: 1189709489179
before newTransformer: 1189709489179
after newTransformer: 1189709490581
before newTransformer: 1189709490581
after newTransformer: 1189709496125
before transform: 1189709496125
after transform: 1189709502463
before newTemplates: 1189709517385
after newTemplates: 1189709524028
before newTransformer: 1189709524028
after newTransformer: 1189709525440
before newTransformer: 1189709525440
after newTransformer: 1189709531095
before transform: 1189709531095
after transform: 1189709537325
using saxonb8-j9:
before newTemplates: 1189710098766
after newTemplates: 1189710103040
before newTransformer: 1189710103040
after newTransformer: 1189710103055
before newTransformer: 1189710103055
after newTransformer: 1189710105376
before transform: 1189710105376
after transform: 1189710111238
before newTemplates: 1189710194556
after newTemplates: 1189710198665
before newTransformer: 1189710198665
after newTransformer: 1189710198677
before newTransformer: 1189710198677
after newTransformer: 1189710201122
before transform: 1189710201122
after transform: 1189710206944
before newTemplates: 1189710247241
after newTemplates: 1189710251380
before newTransformer: 1189710251380
after newTransformer: 1189710251393
before newTransformer: 1189710251393
after newTransformer: 1189710253711
before transform: 1189710253712
after transform: 1189710259665
URI Resolution
Contrary to the
javadoc, if you set
setURIResolver() on the
TransformerFactory, your resolver will not be called to resolve URI's provided to the XSLT
document() function.
Sun says it's not a bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4459167
The Xalan people say that it is (and they've fixed it in 2.7.1):
http://issues.apache.org/jira/browse/XALANJ-2205
In the mean time it appears to work if you also
setURIResolver() on the
Transformer as well as the factory.
Look-up Tables
Useful for L10N!
http://www.ibm.com/developerworks/library/x-xsltip.html