Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing effective XSLT

Tags:

xml

xslt

What are the principles and patterns that go into writing effective XSLT?

When I say "effective" I mean that it is

  1. Well-structured and readable
  2. Simple, concise
  3. Efficient (i.e. has good performance)

In short, I'm looking for the best practices for XSLT.

I've already seen the question regarding efficiency, but efficient code loses its value if you can't understand what it's doing.

like image 777
Peter Dolberg Avatar asked Apr 12 '09 00:04

Peter Dolberg


People also ask

Is XSLT still relevant?

XSLT is very widely used. As far as we can judge from metrics like the number of StackOverflow questions, it is in the top 30 programming languages, which probably makes it the top data-model-specific programming language after SQL. But XSLT isn't widely used client-side, that is, in the browser.

Is XSLT difficult?

XSLT is difficult to work with, but once you conquer it you will have a very thorough understanding of the DOM and schema. If you also XPath, then you on your way to learning functional programming and this will expose to new techniques and ways about solving problems.

What is XSLT example?

XSL stands for EXtensible Stylesheet Language. It is a styling language for XML just like CSS is a styling language for HTML. XSLT stands for XSL Transformation. It is used to transform XML documents into other formats (like transforming XML into HTML).


2 Answers

I. Elegant XSLT code


One can often find examples of beautiful XSLT code, especially when XSLT is used as a functional programming language.

For examples see this article on FXSL 2.0 -- the Functional Programming library for XSLT 2.0.

As an FP language XSLT is also a declarative language. This, among other things means that one declares, specifies existing relationships.

Such a definition often does not need any additional code to produce a result -- it itself is its own implementation, or an executable definition or executable specification.

Here is a small example.

This XPath 2.0 expression defines the "Maximum Prime Factor of a natural number":

if(f:isPrime($pNum))
  then $pNum
  else
    for $vEnd in xs:integer(floor(f:sqrt($pNum, 0.1E0))),
        $vDiv1 in (2 to $vEnd)[$pNum mod . = 0][1],
        $vDiv2 in $pNum idiv $vDiv1
      return
        max((f:maxPrimeFactor($vDiv1),f:maxPrimeFactor($vDiv2)))

To pronounce it in English, the maximum prime factor of a number pNum is the number itself, if pNum is prime, otherwise if vDiv1 and vDiv2 are two factors of pNum, then the maximum prime factor of pNum is the bigger of the maximum prime factors of vDiv1 and vDiv2.

How do we use this to actually calculate the Maximum Prime Factor in XSLT? We simply wrap up the definition above in an <xsl:function> and ... get the result!

 <xsl:function name="f:maxPrimeFactor" as="xs:integer">
  <xsl:param name="pNum" as="xs:integer"/>

  <xsl:sequence select=
   "if(f:isPrime($pNum))
      then $pNum
      else
        for $vEnd in xs:integer(floor(f:sqrt($pNum, 0.1E0))),
            $vDiv1 in (2 to $vEnd)[$pNum mod . = 0][1],
            $vDiv2 in $pNum idiv $vDiv1
          return
            max((f:maxPrimeFactor($vDiv1),f:maxPrimeFactor($vDiv2)))
   "/>
 </xsl:function>

We can, then, calculate the MPF for any natural number, for example:

f:maxPrimeFactor(600851475143) = 6857

As for efficiency, well, this transformation takes just 0.109 sec.

Other examples of both ellegant and efficient XSLT code:

  • Tim Bray's Wide Finder, as solved here.
  • Cascade deletions
  • Transitive closure
  • Finding all anagrams of a word
  • Concordance of a text corpus (the Old Testament)
  • Spelling checking (Shakespear's Othello)
  • Sudoku solver

II. Some rules


Here are some rules for writing "quality XSLT code", as taken from Mukul Ghandi's blog.

They can be checked/enforced using a tool developed by Mukul:

  1. DontUseDoubleSlashOperatorNearRoot: Avoid using the operator // near the root of a large tree.

  2. DontUseDoubleSlashOperator: Avoid using the operator // in XPath expressions.

  3. SettingValueOfVariableIncorrectly: Assign value to a variable using the 'select' syntax if assigning a string value.

  4. EmptyContentInInstructions: Don't use empty content for instructions like 'xsl:for-each' 'xsl:if' 'xsl:when' etc.

  5. DontUseNodeSetExtension: Don't use node-set extension function if using XSLT 2.0.

  6. RedundantNamespaceDeclarations: There are redundant namespace declarations in the xsl:stylesheet element.

  7. UnusedFunction: Stylesheet functions are unused.

  8. UnusedNamedTemplate: Named templates in stylesheet are unused.

  9. UnusedVariable: Variable is unused in the stylesheet.

  10. UnusedFunctionTemplateParameter: Function or template parameter is unused in the function/template body.

  11. TooManySmallTemplates: Too many low granular templates in the stylesheet (10 or more).

  12. MonolithicDesign: Using a single template/function in the stylesheet. You can modularize the code.

  13. OutputMethodXml: Using the output method 'xml' when generating HTML code.

  14. NotUsingSchemaTypes: The stylesheet is not using any of the built-in Schema types (xs:string etc.), when working in XSLT 2.0 mode.

  15. UsingNameOrLocalNameFunction: Using name() function when local-name() could be appropriate (and vice-versa).

  16. FunctionTemplateComplexity: The function or template's size/complexity is high. There is need for refactoring the code.

  17. NullOutputFromStylesheet: The stylesheet is not generating any useful output. Please relook at the stylesheet logic.

  18. UsingNamespaceAxis: Using the deprecated namespace axis, when working in XSLT 2.0 mode.

  19. CanUseAbbreviatedAxisSpecifier: Using the lengthy axis specifiers like child::, attribute:: or parent::node().

  20. UsingDisableOutputEscaping: Have set the disable-output-escaping attribute to 'yes'. Please relook at the stylesheet logic.

  21. NotCreatingElementCorrectly: Creating an element node using the xsl:element instruction when could have been possible directly.

  22. AreYouConfusingVariableAndNode: You might be confusing a variable reference with a node reference. (contributed by, Alain Benedetti)

  23. IncorrectUseOfBooleanConstants: Incorrectly using the boolean constants as 'true' or 'false'. (contributed by, Tony Lavinio)

  24. ShortNames: Using a single character name for variable/function/template. Use meaningful names for these features.

  25. NameStartsWithNumeric: The variable/function/template name starts with a numeric character

like image 153
Dimitre Novatchev Avatar answered Oct 11 '22 15:10

Dimitre Novatchev


Best practice 1 : use templates in stead of < xsl:for-each > whenever you can (which is 99% of the cases)

(may I add MAINTAINABILITY as extra ingredient in the best practices, imho even the most important one)

For understanding xsl you realy need a bit of practice.
Not understanding what sth. is doing is very relative of course.

That goes doube for XSLT, since the xsl:for-each construct tends to be

  • more readable

for a novice, but is in fact

  • less structured,
  • less simple,
  • less concise and
  • a lot less maintainable

than templates, and only

  • equaly readable (at best!!) for so. with a minimum of template experience.

NEVER, EVER USE THE < xsl:for-each > ELEMENT!

I admit, the title is somewhat exaggerated, there do exist, I've been told, cases in which a "xsl for each" can have it's merits, but those cases are very, very rare.

I once had to come up with a fairly complicated xml/xslt client site in less than a week, and used the for-each element all over the place. Now, several years later and, sort of, wiser, I took my time and rewrote the initial code, using only templates. The code now is much much cleaner and more adaptable.

Either you know this, or either you should : < xsl:template > and < xsl: apply-templates> are almost always the way to go. If you are xsl-ing, and you don't fully understand these tags, stop your work now, learn them, get a aha-erlebnis, and continue your work a as a reborn (wo)man.

like image 22
Peter Avatar answered Oct 11 '22 15:10

Peter