Subject: [xsl] having a template remember not to call itself again From: "Chris Papademetrious christopher.papademetrious@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Sun, 5 Mar 2023 16:20:28 -0000 |
Hi everyone, I have a stylesheet with many templates that must all chain together and play nice with each other. So I write them in the following form: <xsl:template match="CONDITION1_HERE"> <!-- apply this template's processing first --> <xsl:variable name="result" as="element()"> ...PROCESSING1_HERE... </xsl:variable> <!-- apply subsequent self-or-children templates last --> <xsl:apply-templates select="$result"/> </xsl:template> When a template applies its processing first then calls other templates last, I will call it "tail-call" template chaining (although I don't know the correct term). For "tail-call" chaining to work, PROCESSING1_HERE must transform the content so that CONDITION1_HERE is not met again (or at least not met in a way that loops infinitely). But, what if PROCESSING1_HERE is very complex (nested moded templates, recursion, etc.) and sometimes CONDITION1_HERE will match after this template was previously applied, and there is no practical way to embed the complexity of predetermining PROCESSING1_HERE's failure to remove the condition into CONDITION1_HERE's match expression? This could be avoided by using "head-call" chaining: <xsl:template match="CONDITION2_HERE"> <!-- apply subsequent self-or-children templates first --> <xsl:variable name="result" as="node()*"> <xsl:next-match/> </xsl:variable> <!-- apply this template's processing last --> ...PROCESSING2_HERE... </xsl:template> But now, all bets are off on what PROCESSING2_HERE will encounter. Maybe the result will have multiple elements, or be filtered out to zero elements, or might have text() nodes interspersed due to reformatting and styling templates. Maybe <xsl:next-match/> modified the content such that CONDITION2_HERE isn't even matched any more. PROCESSING2_HERE must handle a much wider range of possible input, and the more templates that exist in the stylesheet, the more varied the input from <xsl:next-match/> might be. (I actually had all my templates written as "head-call" chaining, and I am converting them to "tail-call" chaining due to such issues.) So now I'm back to "tail-call" chaining, and figuring out how to get a template to not call itself when it fails to remove the condition triggering the match. I tried setting a tunnelling variable that would give a heads-up to the template not calling itself again: <xsl:template match="CONDITION1_HERE[not($CONDITION1_CALLED)]"> <xsl:param name="CONDITION1_CALLED" as="xs:boolean" select="false()" tunnel="yes"/> <!-- apply this template's processing --> <xsl:variable name="result" as="element()"> ...PROCESSING1_HERE... </xsl:variable> <!-- apply subsequent self-or-children templates --> <xsl:apply-templates select="$result"> <xsl:with-param name="CONDITION1_CALLED" as="xs:boolean" select="true()" tunnel="yes"/> </xsl:apply-templates> </xsl:template> but the template's $CONDITION1_CALLED parameter is out-of-scope in its match expression. So now the only solution I can think of is to put some kind of temporary marker attribute in the matching element, then have a final document-down cleanup pass to remove the markers. And if multiple templates need markers, I'll need to clean them all up. Icky. Is there a more elegant way to handle this that am missing? Thanks as always for your collective wisdom, and thanks for making it this far! * Chris ----- Chris Papademetrious Tech Writer, Implementation Group (610) 628-9718 home office (570) 460-6078 cell
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] XSL-List Guidelines, B Tommie Usdin btusd | Thread | Re: [xsl] having a template remembe, Imsieke, Gerrit, le- |
[xsl] XSL-List Guidelines, B Tommie Usdin btusd | Date | Re: [xsl] having a template remembe, Imsieke, Gerrit, le- |
Month |