[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: lookup-table thoughts (was Re: matching multiple t

Subject: Re: lookup-table thoughts (was Re: matching multiple times, outputting once?
From: Tom Myers <tommy@xxxxxxxxxxxxxx>
Date: Tue, 06 Nov 2001 20:47:59 -0500
accumulator pattern
I'm still basically hoping that somebody will say something 
to contribute to my education, and I see that since I started
with Dimitre Novatchev's solution to Marty McKeever's problem
rather than with the problem itself, I was thinking backwards.
Sorry. Okay, we want to go from
----------------------------------------------
<contents> 
<emphasis bold="yes">Hello</emphasis> 
<emphasis italic="yes" bold="yes">Hello</emphasis> 
<emphasis underline="yes" italic="yes" bold="yes">Hello</emphasis>
</contents>
----------------------------------------------
to
----------------------------------------------
<b>Hello</b> 
<i><b>Hello</b></i> 
<u><i><b>Hello</b></i></u> 
----------------------------------------------
rather than the other way around, and I really liked Jim Fuller's
<xsl:template match="*[@bold='Yes' ]"> ...
<xsl:template match="*[@bold='Yes' and @italic='Yes' ]"> ...
<xsl:template match="*[@bold='Yes' and @italic='Yes' and @underline='Yes' ]">...
except that you really need six of those, and in general the number of
templates will be N! where N is the number of options...at least I
assume that Marty's three examples were not intended to exclude the
possibility of <emphasis italic="Yes">Hello</emphasis>, which 
presumably has the output <i>Hello</i> and which therefore for
Jim requires a separate rule. And so I think that a recursive
solution really is better here. (Unless I'm missing something, 
again.)

Still, I'd like to propose a variation on the Kay/Novatchev
solutions. My version is longer, but I think that I think
that coming up with it requires less original thought than
either of theirs, because rather than writing a specific
recursion I'm editting a general version. For instance, I'm going
to keep the bold -> b, italic -> i, underline -> u mapping
in a data table, so even though it requires several lines it
requires no thought, 'cos I can start out a stylesheet like so,
just editting the data from my backwards-solution post or from
any similar lookup-table-based stylesheet:
----------------------------------------------
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:trans="myTrans" exclude-result-prefixes="trans" 
 >
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<trans:trans> 
  <in>bold</in>       <out>b</out>
  <in>italic</in>     <out>i</out>
  <in>underline</in>  <out>u</out>
</trans:trans> 

<xsl:key name="transkey" match="out" use="preceding-sibling::in[1]"/>

<xsl:template name="lookup-trans">
   <xsl:param name="in" select="''"/>
   <xsl:for-each select="document('')"> <!-- or whatever doc holds table -->
     <xsl:value-of select="key('transkey',$in)"/>
   </xsl:for-each>
</xsl:template>
----------------------------------------------
Okay, up to here I have really said no more than that 
   bold -> b, italic -> i, and underline -> u
while preserving the option of adding more later, including some that
might share initial letters. Now, for the most part, I'll copy input to
output (at least for a test) so it takes no thought at all to bring in
----------------------------------------------
<xsl:template match="@node()|@*">
   <xsl:copy>
     <xsl:apply-templates/>
   </xsl:copy>
</xsl:template>
----------------------------------------------
Now, I want to override that for "emphasis" elements; I want to
do something to "emphasis" elements that will run through the
sequence of their attributes, using child nodes as base. I'm
thinking of a functional-programming pattern

   accum(f,[],base) = base
   accum(f,[hd]+tail,base) = f(hd,accum(f,tail,base));

(the sum of a sequence S is accum(add,S,0); the product is
accum(multiply,S,1); the minimum is accum(min,S,+infinity);
and so on. Whatever. I'm not actually reusing code here, but
I am re-using a pattern for the umpteenth time since learning
it from _The Little Lisper_ many long years ago. So I copy 
in the pattern, matching "emphasis" nodes with a call on "accum"
and just leaving two blank slots for filling in:
----------------------------------------------

<xsl:template match="emphasis"> 
  <xsl:call-template name="accum"> 
    <xsl:with-param name="seq" select="@*"/>
    <xsl:with-param name="base" select="node()"/>
  </xsl:call-template>
</xsl:template> 

<xsl:template name="accum">
   <xsl:param name="seq" select="''"/>
   <xsl:param name="base" select="''"/>
   <xsl:choose>
     <xsl:when test="$seq">

        <xsl:variable name="hdvalue">
            --- something depending only on $seq[1] ----
         </xsl:call-template>
        </xsl:variable>

        <xsl:variable name="recresult">
          <xsl:call-template name="accum"> 
            <xsl:with-param name="seq" select="$seq[position()!=1]"/>
            <xsl:with-param name="base" select="$base"/>
          </xsl:call-template>
        </xsl:variable>

        --- output depending only on $hdvalue and $recresult --

     </xsl:when>
     <xsl:otherwise>
       <xsl:apply-templates select="$base"/>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

----------------------------------------------
As you can see, there are just two slots to be filled in; 
what to do with each $seq value, and how to put hdvalue
and recresult together. Here I fill them in:
----------------------------------------------

<xsl:template name="accum">
   <xsl:param name="seq" select="''"/>
   <xsl:param name="base" select="''"/>
   <xsl:choose>
     <xsl:when test="$seq">

        <xsl:variable name="hdvalue">
           <xsl:call-template name="lookup-trans">
           <xsl:with-param name="in" select="name($seq[1])"/>
         </xsl:call-template>
        </xsl:variable>

        <xsl:variable name="recresult">
          <xsl:call-template name="accum"> 
            <xsl:with-param name="seq" select="$seq[position()!=1]"/>
            <xsl:with-param name="base" select="$base"/>
          </xsl:call-template>
        </xsl:variable>

        <xsl:element name="{$hdvalue}">
          <xsl:copy-of select="$recresult"/>
        </xsl:element>

     </xsl:when>
     <xsl:otherwise>
       <xsl:apply-templates select="$base"/>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>
----------------------------------------------
And that seems to handle the problem...unless I'm missing something.
It's interesting, I think, that even when filled in, the accumulator
pattern has no idea that the nodelist is a list of attributes...and
info about the mapping of names is confined to the lookup table. Of
course you can make it a little shorter and faster in various ways,
e.g. by bringing the call-template that defines "recresult" into
the one and only place $recresult is used, avoiding the copy-of.
But mainly it's interesting that so little thought is required.
And I'm wondering what I'm missing this time. Oh well, back to
data bases.

Tom Myers 


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.