XSLT Coding Guidelines, annotated version - ΩJr. Coding Guidelines

This information lives on a webpage hosted at the following web address: 'https://omegajunior.globat.com/code/guidelines/'.

XSLT Coding Guidelines are intended to make it easier to read our work, both for colleagues when we are away, and for ourselves in a year's time. The Guidelines also answer newbie questions, in order to reduce the learning curve.

This is the annotated version. Besides guidelines and examples, it contains verbose explanations. For an overview without explanations, visit the summary.

Suggestions are welcome.

Check the XSLT versions the parser in your environment allows
XSLT 2 has been around for quite a while now, but not all environments allow us to use it. Smartsite for example, can create XSLT 2, but executes XSLT 1.0 only.


Use the xsl:transform element
The xsl:transform is a technical equivalent of the xsl:stylesheet element. We could use either of them. However, semantically we are not styling a document; we are transforming it.
<?xml version="1.0"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
</xsl:transform>



Always add an xsl:output element
The xsl:output element allows you to set important structural features about the output of your XSLT. For instance, you can tell your XSLT to generate HTML or XML by switching a setting, without the need to rewrite your entire mark-up.
<xsl:output
method="html"
version="1"
encoding="iso-8859-1"
omit-xml-declaration="yes"
standalone="yes"
doctype-public="html"
cdata-section-elements=""
indent="yes"
media-type="text/html"
/>

Definition and Usage of xsl:output as described by W3Schools.com


Suppress unexpected text matches
Our templates sometimes match texts we didn't intend to match, didn't intend to have echoed into the output. It happens because of the default text template. The easiest solution is to suppress any errant texts, by overriding the default text template:
<xsl:template match="/text()" />


Avoid xsl:for-each when a template match suffices
Sometimes we like to use an xsl:for-each. However, this comes at a memory and performance cost. So unless you need the additional benefits of an xsl:for-each, simply use a template match instead.
Definition and Usage of xsl:for-each as described by W3Schools.com


Avoid named templates when a template match suffices
A named template has a semantical implication: there was no way this template could have been reached by simply following the input document structure using a straightforward XPath and / or XQuery instruction. Naming templates is a short-cut, a special case. Your coworkers will expect that. Thus, if you use a named template where a simple template match suffices, you make things harder to understand.


When naming templates, choose names based on functional intent
Don't choose a name based on data or XSLT execution: we can read. Instead, make clear why the template is used. Try to do so in as few words as possible. If you find your template names turning into sentences, try breaking the templates into smaller units.


If at all possible, generate new mark-up using xsl:element
Both the W3C XSLT recommendation and the article on tips for cleaner code state that we can create mark-up without using the xsl:element. Sure, you can do that, and the XSLT parser will output your mark-up.
<xsl:template match="/products/link">
<a href="{@url}" title="{hint}><xsl:value-of select="title" /></a>
</se:template>


However, when you are outputting XML, your XSLT will add an XML declaration. When will it do that? Well, we hope to find only one declaration, and we hope it will be located at the top of your output, as the very first thing.

However, Microsoft's XSLT 1.0 parsers thus far have added this XML declaration above the very first generated mark-up. Which means that if you did not already generated your mark-up using xsl:element, chances are the declaration will end up halfway through your output, where you echoed some data using xsl:value-of. Subsequently, your output will be malformed and fail validation, resulting in all kinds of weirdness down the line.

To solve this, avoid sprinkling random mark-up throughout your XSLT, and have each and every piece of mark-up generated by the xsl:element. Unfortunately, this also means that you need to add element attributes using xsl:attribute.
<xsl:template match="/products/link">
<xsl:element name="a">
<xsl:attribute name="href"><xsl:value-of select="@url" /></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="hint" /></xsl:attribute>
<xsl:value-of select="title" />
</xsl:element>
</se:template>



Block indentation
Separate templates by a blank line, and indent levels using 2 spaces. If you need to supply multiple properties per element, put each on its own line, indented. If you need to supply multiple sub elements, put each on its own line, indented. Put each element on a new line.

<?xml version="1.0"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>

<xsl:template match="/text()" />

<xsl:template match="/products">
<xsl:apply-templates select="link" />
</se:template>

<xsl:template match="link">
<xsl:element name="a">
<xsl:attribute name="href"><xsl:value-of select="@url" /></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="hint" /></xsl:attribute>
<xsl:value-of select="title" />
</xsl:element>
</se:template>

</se:transform>



Javascript returned by XSLT
If you need to include Javascript code in your XSLT, so it will be echoed into the output, you need to tell the XSLT parser to ignore the Javascript code. Otherwise the parser will fail on comparison operators < and >.

For (X)HTML, we use the following technique to include Javascript:
<script type="text/javascript">/* <![CDATA[ */
//Your Javascript code here
/* ]]> */</script>


For XSLT, that will run through the XSLT processor without fail. However, the result does fail: since XSLT knows CDATA, it will not output its start or end terms, omitting them completely from the output, returning a script that is no longer hidden from the HTML parser:
<script type="text/javascript">/* */
//Your Javascript code here
/* */</script>


We do not want to add "script" to the xsl:output's cdata-section-elements attribute, because doing that will cause the XSLT parser to add the CDATA block around the Javascript code without the /* comment block */:
<script type="text/javascript"><![CDATA[
//Your Javascript code here
]]></script>


So we want to combine both effects: we need to hide the Javascript code from the XSLT parser, but the output must also include the CDATA term and the /* comment block */:
<xsl:element name="script">
<xsl:attribute name="type">text/javascript</xsl:attribute>
<xsl:text><![CDATA[/* &#60;![CDATA[ */
//Your Javascript code here
/* ]]&#62; */]]></xsl:text>
</xsl:element>

Ugly? Yes. But it works.

Need problem solving?

Talk to me. Let's meet for coffee or over lunch. Mail me at “omegajunior at protonmail dot com”.

Clicky Analytics