RE: [xsl] determine the number of payment methods and specify order depending on page type being viewed

Subject: RE: [xsl] determine the number of payment methods and specify order depending on page type being viewed
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 4 Nov 2008 15:57:08 -0000
> Now it happens that the fact that you're generating the 
> results in a fixed order actually simplifies things for you. 
> Your 'class' 
> attributes can each be one of three values, "doubleLine 
> completed", "doubleLine current" and "doubleLine". But 
> because the elements will come in order, these do not map 
> arbitrarily. Actually it's something like this:

Good work Wendell, and congratulations on your patience. I spent a few
minutes on this and gave it up: somehow it the ratio of complexity and
tedium didn't inspire me to work on it. But you've broken the back of it.
Now it just needs a way to generify it a bit more.

How about a two-pass solution?

<xsl:template match="paymentMethods">
   <xsl:variable name="temp">
     <xsl:apply-templates select="directDebit"/>
     <xsl:apply-templates select="creditCard"/>
     <xsl:apply-templates select="invoice"/>
   </xsl:variable>
   <xsl:apply-templates select="$temp/*" mode="add-class"
</xsl:template>

<xsl:template match="directDebit">
  <directDebit>Payment by <br/>Direct Debit</directDebit> 
</xsl:template>

<xsl:template match="creditCard">
  <creditCard>Payment by <br/>Credit Card</creditCard> 
</xsl:template>

<xsl:template match="invoice">
  <invoice>Payment by <br/>Invoice</invoice> 
</xsl:template>

<xsl:template match="*" mode="add-class">
  <xsl:variable name="status">
    <xsl:choose>
      <xsl:when test="$label = local-name()">current</xsl:when>
      <xsl:when test="preceding-sibling::*[local-name() =
$label]">completed</xsl:when>
      <xsl:otherwise/>
    </xsl:choose>
  </xsl:variable> 
  <li class="doubleLine {$status}"><xsl:copy-of select="node()"/></li>
</xsl:template>
  
Probably doesn't save many lines of code, and it runs into the 1.0
node-set() restriction, but it strikes me as capturing the logic of the
problem a bit better: if a fourth and fifth kind of payment were added,
fewer changes would be needed, as the final template has no knowledge of the
different kinds of payment.

Michael Kay
http://www.saxonica.com/



> 
> ... I won't try to explain the logic of the assignment of 
> values to $status in each case. You should examine and test 
> it to be sure I'm right. (The logic assumes that only three 
> values are possible.)
> 
> But it's worth noticing I use XSLT "attribute value syntax" (the { }
> syntax) to get this value into the li/@class attribute.
> 
> Cosmetically, if you don't like the extra space you get on 
> the @class when $status has no value, you can write around 
> that like this:
> 
>    <xsl:variable name="status">
>      <xsl:if test="$label = 'directDebit'"> current</xsl:if>
>    </xsl:variable>
>    <li class="doubleLine{$status}">Payment by <br/>Direct Debit</li>
> 
> The other concern here is to make sure that $label is 
> available as a global parameter or variable; you said it was 
> set at run time, so I assume it is.
> 
> I think this handles your problem, except for one exception. 
> What happens if $label is set to 'creditCard', say, but you 
> have no 'creditCard' element? Currently, the stylesheet will generate:
> 
> <ul>
>    <li class="doubleLine completed">Payment by <br/>Direct Debit</li>
>    <li class="doubleLine">Payment by <br/>Invoice</li> </ul>
> 
> If your system does not have a way of preventing this from 
> happening, you need to think about what you want the 
> stylesheet to do if (when) it does.
> 
> Finally -- notice that you don't need to test to see how many 
> and which element children of 'paymentMethod' are present. 
> Instead, this work is simply done by processing the input 
> data: elements not present are not processed. :-) This is far 
> more robust, and reflects the way XSLT is intended to work.
> 
> If you need to dive in and learn how to apply and match 
> templates in order to get this going -- so much the better. 
> You'll never understand XSLT without this capability. 
> Template matching and the idea of "tree traversal" (context 
> nodes, child elements, etc. etc.) are at the heart of the language.
> 
> Finally -- I have used XSLT 1.0 methods and idioms 
> throughout. In XSLT 2.0, there are ways of making this more 
> concise (and possibly opaque). But there's little point in 
> doing this in XSLT 2.0 unless you can do it in XSLT 1.0 
> (which is arguably not true of all XSLT problems).
> 
> Please ask any followup questions for clarification.
> 
> Cheers,
> Wendell
> 
> 
> 
> ======================================================================
> Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
> Mulberry Technologies, Inc.                http://www.mulberrytech.com
> 17 West Jefferson Street                    Direct Phone: 301/315-9635
> Suite 207                                          Phone: 301/315-9631
> Rockville, MD  20850                                 Fax: 301/315-8285
> ----------------------------------------------------------------------
>    Mulberry Technologies: A Consultancy Specializing in SGML 
> and XML 
> ======================================================================

Current Thread