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.