XSLT Explorer

Volume 4, Issue 30; 03 Jun 2020

Better understanding through static analysis. Not deep, serious static analysis, but a bit of XSLT on XSLT static analysis.

What happened was, I started writing some XSLT for my Balisage paper [register now!] and I made a casual decision: I’d put all the functions in functions.xsl. That seemed reasonable at the time: most of the functions are shared across several other modules.

Some time later, having written a lot more XSLT, I was writing a utility function that was only ever going to be used in the one module I was working on, so I decided to put the function in that module. That seemed reasonable too.

As I thought about it some more, I realized that I’d been a little careless with where functions were declared and over the course of several refactorings, the places where they’re used had changed. (The f:attributes() function, for example, was right at the top of functions.xsl because it was used everywhere. Except that I’d subsequently refactored things such that it was now only used from one module, attributes.xsl.)

Hang on, I thought, what is the structure of this stylesheet?

Well, really, what does a programmer love more than a rabbit hole? Right. Down we go!

Of course XSLT can be used to transformIf you use an IDE, like the excellent Oxygen XML Editor, you can just jump around between uses and declarations in the IDE. That’s great, but it isn’t exactly what I had in mind. an XSLT stylesheet into a report on its structure. What we’re interested in here is, where are functions declared and where are they used? Where are they declared is easy. To find out where they’re used, we need to parse the XPath expressions in the stylesheet. Luckily, Gunther Rademacher’s REx Parser Generator will happily build us an XPath 3.1 parser in XSLT.

At this point, I could find the function declarations and their uses. Problem solved.

Except, with just a little more work, I could highlight unused functions too. And, really, with a lot of functions, it would be nice to highlight the functions that are only used in one other module (instead of working that out in my head from the list of modules that use the function).

And aren’t named templates just like functions in a lot of ways? Wouldn’t it be nice to know how they’re used? And, for that matter, don’t these questions apply to variables and parameters too?

And what about shadowing? Could I have declared two variables with the same name and not even noticed? I should be able to check that too, right?

Ok, this is too complicated to just assume I’m getting it all correct. Time to write some tests. I should probably have started writing tests sooner.

Now I’ve got functions, templates, variables, and parameters in the report. It sure would be nice if I could expand and collapse sections so that it was easier to get an overview. Well, that’s just a little JavaScript, right?

And by the time I’d got all that built, most of the weekend was gone.

I also discovered almost immediately after I started using the tool, that it would be really nice to be able to link from the report to the source code. (It’s not always easy to distinguish between different unnamed templates in the report, so being able to jump to the actual declaration is handy.)

And then I had this cool idea about how I could make links into the source code go to the right line.

Finally, I got @linguacelta to design a gorgeous logo, I registered a domain, checked the whole thing into a GitHub repo, configured CircleCI to build, test, and release it automatically, and XSLT Explorer was born.

This wasn’t a displacement activity at all. Why do you ask?