This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Findings: Merging XSL:FO & HTML Style Sheets


On Tuesday 05 March 2002 05:54, Peter Bray wrote:
> Greetings All,
[snip]
> ASIDE: From this experience I'm considering if it is worth while to
> mail the w3c XSL-Editors Group with a proposal I'm loosing calling
> "Further support for simple variable / parameter expansion in XSLT
> attributes". I was wondering whether the lack of expansion of
> attributes was something causing others on the list to jump thru
> unnecessary hoops and if we should, as a list, have a discussion on
> such issues.

You bring a lot of good use-cases, and I think we all wish there was more 
flexibility with attribute value templates (XSLTC and other compilers be 
damned :->).  Another example that recently came up on this list was the use 
of attribute value templates with <apply-templates mode="{...}">.  I know 
that I have also had use for the ability to specify the Doctype dynamically, 
and I had to resort, like you did, to using wrapper stylesheets.

I have never written an XSLT compiler, but could someone from the XSLTC 
project or other experts please comment on whether it is truly necessary to 
require many of the restrictions on AVTs?  Setting the mode and output params 
dynamically are so useful, and it seems to me like it would not be difficult 
to implement compiled versions for that (I'll grant you that using AVTs with 
<call-template name="{...}"> is a use-case for which there are other 
workarounds, and so I won't ask for that concession from the compilers).

For those who are worried about compiled performance if AVTs are more widely 
allowed, let me remind you that compilers are capable of only compiling what 
the stylesheet actually uses.  If the stylesheet does not use, for example, 
AVTs to dynamically select the mode, then a compiler can use the current 
method.  If the stylesheet does use AVTs, then the compiler could add a named 
hash of the templates with that mode and only use that hash when necessary.  
Like I said, I've never written an XSLT compiler, so I'll leave it to the 
experts to comment on the feasability of this.

> Anyway the method which is working for me for the core XSLT file, is
> the use of numerous key named templates to push down (defer) generation
> of the actual output tags (ie the HTML and FO) and within these
> templates and others, wrapping of all tag generation in <xsl:choose>
> elements.
>
> To give you an idea of the named templates I used, here are the names
> of a few of the key ones which greatly simplified the task:
> MakeLinkInternal, MakeLinkExternal, SectionBegin, SectionEnd,
> MinorHeading, GenerateTableRow, GenerateTableRowLabel,
> GenerateTableRowContents
>
> Also for some simple cases the following proved useful (note that
> OUTPUT_MODE is a global parameter):
>
>     <xsl:variable name="enclosingTag">
>       <xsl:choose>
>         <xsl:when test="$OUTPUT_MODE = 'FO'">fo:block</xsl:when>
>         <xsl:otherwise>p</xsl:otherwise>
>       </xsl:choose>
>     </xsl:variable>
>
>     <xsl:element name="{$enclosingTag}">
> 	<!-- ... -->
>     </xsl:element>
[snip]

I've had to solve something very similar to your problem in the past, but I 
came up with a slightly different solution.  It's kind of a hack to get 
around that <apply-templates mode="{}"> and <call-template name="{}"> cannot 
be specified dynamically, but it uses the same idea of a "wrapper stylesheet" 
that you already have.

What I did was to have a wrapper that did the obvious things you already do, 
such as set the output parameters appropriately.  But I also went further to 
define a list of all of the named templates my stylesheet used, and implement 
multiple copies of those directly in the wrapper templates.  So my wrappers 
looked like this:

<stylesheet ...>
  <output .../>
  <{import|include} href="wrapped-stylesheet.xsl"/>
  <template name="output-custom-code">
    foo
    <call-template name="output-common-code"/>
  </template>
</stylesheet>

And wrapped-stylesheet.xsl had something like:

<stylesheet ...>
  <template match="some-element">
    ... common code ...
    <call-template name="output-custom-code"/>
    ... more common code ...
  </template>
  <template name="output-common-code">
    ... even more common code ...
  </template>
</stylesheet>

So rather than having a global parameter to select the output mode, I simply 
changed the wrapper stylesheet and thus changed the implementation of the 
custom templates.  Only those templates that were not implemented in the 
wrapped-stylesheet.xsl needed to be redefined, and the custom templates could 
call back and forth between the common ones.

The nice things about this method are that you don't lose any performance by 
testing the value of the global variable each time a template is called and 
that code clutter is drastically reduced (no <choose> blocks and <variable> 
declarations everywhere, and in general no need to use <element>).  
Maintanance is also not a real big problem, since the only thing that has to 
be synchronized between the implementations is the names of the custom 
templates -- something to which any Java programmer who has created their own 
interface is already accustomed.

Sometimes it is a little tough to negotiate bouncing back and forth between 
the common code and custom code, but it is still perfectly possible to resort 
to a global variable and a <choose> statement in the more difficult cases.

In the end I had about a dozen stylesheets that were modularized and could be 
<include>ed by the wrapper stylesheets to customize each part of the output 
(I did not have such a clearcut problem of either HTML or FO; the format 
output by each implementation was the same, but only slightly different 
content).

-- 
Peter Davis
The way to fight a woman is with your hat.  Grab it and run.

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]