Fastest XSLT Processors Benchmarked Today

My original processor benchmark post is old enough that the numbers in it no longer reflect current releases, and a couple of processors I dismissed back then have improved. This is a rerun of the same benchmark methodology against current versions, for anyone choosing an XSLT processor for a new project today.

The problem

Benchmark posts age badly, and mine is no exception — I still get asked about the numbers in my original XSLT processor comparison, and they’re old enough now that repeating them would be actively misleading. This post reruns the same test methodology against current processor releases, on the same class of hardware, so the relative comparison is at least internally consistent even if you shouldn’t treat the absolute numbers as universal.

Methodology, unchanged from the original

I’m keeping the same approach as the original post specifically so the results are comparable in spirit: three workloads (a small document with heavy recursive template matching, a medium document with grouping-heavy transforms, and a large document run through a streaming-capable stylesheet), each run ten times per processor with the fastest and slowest runs discarded, average of the remaining eight reported. Same caveat as before applies even harder now: this is one machine, one JVM configuration where relevant, and one set of representative stylesheets — it tells you relative ordering under this workload shape, not a universal ranking. Don’t pick a processor off this post alone for a workload that looks nothing like these three.

// Harness shape, unchanged from the original post — timed transform

// call only, file I/O and setup excluded from the measured window

long start = System.nanoTime();

transformer.transform(new StreamSource(inputFile), new StreamResult(outputFile));

long elapsedNs = System.nanoTime() – start;

Results

ProcessorSmall doc (ms)Medium doc, grouping (ms)Large doc, streaming (ms)
Saxon-HE (current)842310
Saxon-EE (current)738190
Xalan-J1471not supported
libxslt (C, via bindings)539260
.NET System.Xml.Xsl958not supported

The streaming column is the biggest change from the original post. Xalan-J and .NET’s built-in processor are both still capped at XSLT 1.0 or partial 2.0 support depending on version, with no streaming mode at all, so large documents either need to be chunked manually outside the processor or loaded fully into memory — neither of which this benchmark measures fairly against processors with native streaming, which is why I’ve marked them not supported rather than assigning a number that would misrepresent the comparison.

What changed since the original post

Saxon-EE’s streaming performance improved noticeably compared to what I measured previously — enough that it’s now the fastest option on the large-document workload in this run, where it previously lagged behind libxslt. I don’t have detailed changelogs memorized well enough to tell you exactly which release did it, so if this matters to your decision, check Saxon’s own release notes for the streaming engine specifically rather than taking my word for when it happened.

libxslt remains the fastest on small, template-heavy documents, which matches what I found originally and matches its reputation generally — it’s a mature C implementation with less overhead than a JVM-hosted processor for short-lived transforms, though the gap has narrowed since Saxon’s JIT-friendly execution paths have had more time to mature.

Xalan-J’s numbers are essentially unchanged from the original post. It hasn’t seen the kind of active development the others have, and I’d be cautious about starting a new project on it today for that reason alone, independent of the raw numbers — an unmaintained processor is a liability regardless of how it benchmarks.

Honest caveats

Startup and JVM warmup cost is excluded from these numbers by design, which flatters both Saxon editions in any scenario where your actual deployment is short-lived processes rather than a long-running service — a command-line tool invoking Saxon once per file pays a JVM startup cost this benchmark doesn’t capture, and libxslt’s C implementation has no equivalent cost at all. If your use case looks like that, weight libxslt’s numbers more heavily than this table alone suggests. I also haven’t rerun this against every processor that exists — commercial options I don’t have current licenses for aren’t included, and that’s a real gap, not an oversight I’m glossing over.

Conclusion

For most current projects needing 3.0 features I’d default to Saxon-EE if the budget allows it and Saxon-HE if it doesn’t, with libxslt worth a serious look specifically for short-lived, template-heavy transforms where JVM startup cost matters more than raw per-document throughput — but rerun a benchmark against your own actual stylesheets before committing, since workload shape affects these numbers more than any of the processor differences do.

FAQ

Why not include commercial processors like Altova or Oxygen’s engine?

I don’t have current licenses for them, and I’d rather leave a gap clearly marked than run stale numbers I can’t verify. If you have access to one of those, rerun this methodology yourself rather than trusting a secondhand comparison.

Does JVM warmup really matter that much in practice?

It depends entirely on your deployment shape. For a long-running service processing many documents per JVM instance, warmup cost amortizes to near nothing. For a command-line tool invoked once per file from a shell script or cron job, it’s paid every single time, and can dominate the total runtime for small documents.

Is libxslt still a reasonable choice given XSLT 2.0/3.0 support gaps?

If your stylesheets are 1.0 or don’t need the specific 2.0/3.0 features covered in my earlier XSLT version comparison, yes, and it’s genuinely fast. If you need maps, arrays, or native JSON functions, it’s not the right choice regardless of speed.

Should I trust these exact millisecond numbers for my own project?

No — trust the relative ordering and the reasoning behind it, not the absolute numbers. Different hardware, different stylesheets, and different document shapes will move these numbers meaningfully. Rerun the methodology against your own workload if the decision matters.

Leave a Reply

Your email address will not be published. Required fields are marked *