ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> xsl-list
xsl-list
[xsl] Re: lookup-table thoughts (was Re: matching multiple times, outputting once?
by Tom Myers other posts by this author
Nov 7 2001 1:47AM messages near this date
RE: [xsl] Transform XML to HTML table with multiple columns and lines. | [xsl] reliability of MSXML
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
Thread:
Tom Myers
Pedro Pastor
Pedro Pastor
Michael Kay
Daniel Veillard
Trevor Nash
Daniel Veillard
Michael Kay
Daniel Veillard
Michael Kay
David Carlisle
Kevin Jones
Michael Kay
Kevin Jones
David Carlisle
Jeni Tennison
Tom Myers
Jeni Tennison
Michael Kay
Jeni Tennison
Dimitre Novatchev
cutlass
Jeni Tennison
Mark Nahabedian
Dimitre Novatchev
Tom Myers
Michael Kay
David Carlisle
Tom Myers
David Carlisle
David Carlisle
Jeni Tennison

Privacy Policy | Email Opt-out | Feedback | Syndication
© ActiveState Software Inc. All rights reserved