[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
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
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|