4 ms·
XSLT is conceptually sound indeed, a transformation of tree structures. But the requirements and real-world usage cases thrown at it are often terribly suited
by T-hawk 12y ago
XSLT is conceptually sound indeed, a transformation of tree structures. But the requirements and real-world usage cases thrown at it are often terribly suited for it.
Real applications just don't fall neatly into tree transformations. I inherited a financial reporting web app using XSLT as the rendering mechanism. Requirements included things like running totals (state!), suppressing leading values when repeated between rows (also state), alternating row colors, external dependencies such as numeric formatting based on user's locale settings. A stateless tree transformation doesn't express that elegantly, so you end up with fantastically complicated and ugly XPath hacks. A running total would come from something like "sum all my parent's children with an index less than mine". Then that breaks when something comes up to introduce a need for another layer beneath that parent.
XSLT is purely functional. <xsl:if>template</xsl:if> isn't even control logic, it is functional evaluation, the same as Lisp's (if x template nil). <xsl:for-each> also isn't an imperative loop (it's map) even though it looks imperative and most enterprise programmers trained on imperative languages think it is and use it as such. So it's no surprise that XSLT in the wild ends up as a messy ball of mud.
Most templating languages have this problem, including PHP/HTML. The messy nature of real requirements isn't unique to XSLT. But XSLT manifests it most dramatically since it lacks a stateful and imperative framework to fall back on.
- spdustin 12y agoJust in case you're using XSL still, you could use <xsl:key/> to let you quickly do subtotals by summing the node set of items that match whatever grouping level you're on when you emit the last item in the group. <xsl:key name="items-by-order" match="item" use="../@orderid"/> ...snip... <!-- Union current item node with last item node of the order - if it's the same, the count will be one --> <xsl:if test="count(. | key('items-by-order', ../@orderid)[last()]) = 1"> <xsl:value-of select="sum(key('items-by-order', ../@orderid))"/> </xsl:if> Running totals would be similar, except that your apply-templates for the item group would include a select that restricts the available nodes to the key() function's result, and you would sum current node with preceding nodes.