Warning: geekspek ahead.
For the project I'm working on, I have to write security policies in the rather poor XACML standard. XACML requires a lot to say a little, and this has irritated me while I work on the project. So I decided to be a good hacker and write some scripts to automate some of the work.
Currently the best language for transforming XML into other XML is XSLT. My previous impression was of a couple of good ideas wrapped around one of the most nauseatingly bad syntaxes I'd ever seen until I met XACML. But, it was the best tool available and so I delved into it again.
The things XSLT does right, it does very right; it is actually remarkably good at transforming trees into other trees in weird ways, and the tree-specification language XPath is quite worthwhile. Unfortunately, the language itself uses XML syntax for everything, probably so you can apply XSLT to your XSLT programs.
As an example, let's have a look at some code from my "negativify" script, which takes a condition in XACML and inverts its meaning. First, the XSLT:
<xsl:template match="SubjectMatch"> <SubjectMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:boolean-equal"> <Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:not"> <Function> <xsl:attribute name="MatchId"> <xsl:value-of select="@MatchId"/> </xsl:attribute> <xsl:copy-of select="."/> </Function> </Function> </SubjectMatch> </xsl:template>
This is hard to read because of the sheer variety of tags; the internal XSLT tags are not particularly well distinguished from the XACML that's being generated. So let's fix that.
<xsl:template match="SubjectMatch"> <SubjectMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:boolean-equal"> <Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:not"> <Function> <xsl:attribute name="MatchId"> <xsl:value-of select="@MatchId"/> </xsl:attribute> <xsl:copy-of select="."/> </Function> </Function> </SubjectMatch> </xsl:template>
Here, the green represents XSLT code. All this is supposed to do is find a SubjectMatch tag and bury it where you see the xsl:copy-of
, but in the interests of readability (and because the closing tags are so long) all the closing tags are on lines of their own. And all the xsl:attribute
nonsense is doing is trying to put something on the enclosing Function tag. The sheer amount of punctuation doesn't help matters much. By comparison, some similar Lisp code might look like:
(template-match "SubjectMatch" `(SubjectMatch ((MatchId . "urn:oasis:names:tc:xacml:1.0:function:boolean-equal")) (Function ((FunctionId . "urn:oasis:names:tc:xacml:1.0:function:not")) (Function ((MatchId . ,(value-of "@MatchId"))) ,@(copy-of ".")))))
This probably isn't any easier to read to the untutored, but it's clearly compacter; we can see that the ridiculous XACML function names are far and away the most problematic parts of the syntax, and because we don't have to have five useless lines for closing tags (that being the proper style in XML) cluttering things up, we can see the code itself much more readily.
Unfortunately no such Lisp library exists, meaning I'm stuck with XSLT until I get frustrated enough to write one. And this nastiness really is far and away the best current method of doing this kind of thing.