Subject: Re: [xsl] Preferred declarative approach for outputting tallies based on complex triggers|
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Thu, 10 Apr 2014 12:41:12 +0100
I don't find the adjective "declarative" particularly helpful here. I don't know how to assess whether one stylesheet is more declarative than another. When you are processing a sequence and the result of processing one item depends on the results of processing previous items, there are three possible approaches: * head/tail recursion * a higher-order fold() function * xsl:iterate At one level all three are equivalent. head/tail recursion is probably the simplest and most primitive. But advising one against the others is a bit like arguing between "for" and "while" expressions. It's essentially a matter of style. When it comes to streamability, xsl:iterate is preferred because the data flow is more amenable to static analysis. Michael Kay Saxonica On 10 Apr 2014, at 12:12, David Rudel <fwqhgads@xxxxxxxxx> wrote: > I have a general question for those who adhere to declarative methods. > What is your preferred regime for outputting results of analyzing a > sequence of items? The "analysis" here might be complicated, requiring > state variables, counters, and triggers (to determine when the > counting occurs). Then the "results" would be the final values of > those counters. > > The main issue I'm thinking about is determining when the sequence has > been consumed so you know when to write the outputs to the result > document. > > I simply use the <xsl:iterate> instruction, and then the > <xsl:on-completion> instruction takes care of this question of > determining when the sequence is finished. > > From my rather inexperienced perspective, a declarative approach to > this would be something like: > > <xsl:variable name="seq" select="<<find the items I need to process>>"/> > > <xsl:apply-templates select="$seq" mode="analyze"> > (: put a bunch of with-param elements in here to control counters and > triggers and anything you need to control the analysis :) > </xsl:apply-templates> > > <xsl:template mode="analyze"> > (: pick up parameters:) > (: modify the state variables and triggers:) > > <xsl:if test="position() = last()"> > (: output results here :) > </xsl:if> > </xsl:template> > > Another method would be to use a recursive function on a sequence: > > <xsl:function name="mynamespace:analyze"> > <xsl:param name="seq" as="item()*"> > (:several other parameters to control analysis: counters, triggers, > state variables, etc.:) > > <xsl:choose> > <xsl:when test="empty($seq)"> > (:output data :) > </xsl:when> > <xsl:otherwise> > (: Modify counters, triggers, and state variables based on their > current values and head($seq)) > <xsl:sequence select="mynamespace:analyze(tail($seq), (: new state > variables and counters:))/> > </xsl:otherwise> > </xsl:choose> > </xsl:function> > > I was wondering what experienced users did in these cases and if > either of the above is wrong-headed. > -David > > -- > > "A false conclusion, once arrived at and widely accepted is not > dislodged easily, and the less it is understood, the more tenaciously > it is held." - Cantor's Law of Preservation of Ignorance.