xsl-list
[Top] [All Lists]

RE: [xsl] best practices re xsl:{import,include,next-match,apply-imports}

2008-05-07 15:52:31

No magic answer to this one. You could use apply-imports instead of
next-match - interesting to see that there is a use case for this. Is there
any reason the generic match="node()|@*" template can't be moved into the
generic stylesheet module?

Changing the import to include seems to me to be storing up other problems
for the future.

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

-----Original Message-----
From: James A. Robinson [mailto:jim(_dot_)robinson(_at_)stanford(_dot_)edu] 
Sent: 07 May 2008 16:44
To: XSL-List
Subject: [xsl] best practices re 
xsl:{import,include,next-match,apply-imports}


Hi folks,

For the first time I've had an application where I think 
xsl:next-match or xsl:apply-imports might applicable.

This application needs to be able to transform various 
elements in various schema into be a fairly complicated 
atom:entry format (where atom is the Atom Syndication Format, 
http://www.w3.org/2005/Atom) which we have developed to 
indicate hyperlinking relationships.  The constructions of 
the atom:entry takes 15 variables into account when it constructed.

A specific example is the need to transform an element from 
the NLM Journal Publishing DTD, the relateed-article element 
into this format.
Many of the 15 variables used to create the atom:entry are 
generic when dealing with a related-article element.  Two are not.

I thought it'd be nice to keep construction of these entries 
as simple as possible for the people who will be maintaining 
these stylesheets.
Specificaly I want to make it simple to add new templates for 
transforming new types of related-article elements into these 
atom:entry forms.

I thought what I would do is create a generic library 
stylesheet with a callable template which takes 15 tunneled 
parameters and creates the proper atom:entry.

Then I would create a stylesheet which matches on any 
"related-article"
element, using a priority of 1, which called the library 
template, constructing and passing along those tunneled 
parameters which are generic (i.e., all those parameters 
which are applicable to all related-article elements).

Finally, I wanted to add a last stylesheet with very specific 
"related-article" element match, one which matched on 
specific attributes, and which had a priority of 2.  This top 
level stylesheet would use xsl:next-match to tunnel through 
the one or two parameters which weren't handled by the more 
generic layer.

So I'd have

  xsl:template match="related-article[...predicates...]" priority="2"
    -> xsl:next-match w/ tunneled 2 parameters

       xsl:template match="related-article" priority="1"
         -> xsl:call-template w/ 13 tunneled parameters

           xsl:template name="atom:hyperlink"
             xsl:param ...13 tunneled parameters ...
             <atom:entry>...</atom:entry>

This is the first time I'd used xsl:next-match, and I found 
myself being confounded by how one should use xsl:import vs. 
xsl:include or should use xsl:next-match vs. xsl:apply-imports.

My first reaction was that one should use xsl:import and 
xsl:next-match to offer the most flexibility re future 
changes.  E.g., introduction of overridable variables or the 
need to "next-match" at various priorities within the highest 
level stylesheet.

What I've realized is that the rules of xsl:import and 
xsl:next-match and how XSLT defines the next-match, by lower 
priority -or- by lower precedence, means I run into trouble 
if I introduce a template which suppresses the default 
behavior of XSLT to print the string value of elements as it 
walks the tree.

To try and boil this down to a simple set of examples, let's 
say I have three stylesheets and a source document:

(1) A named template stylesheet, t.xsl.

    <xsl:stylesheet 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema";>
      <xsl:template name="t">
        <xsl:param name="a" as="xs:string?" tunnel="yes" />
        <xsl:param name="b" as="xs:string?" tunnel="yes" />
        <xsl:message select="concat('t: ', 
string-join(($a,$b), ', '))"/>
      </xsl:template>
    </xsl:stylesheet>

(2) A "generic" stylesheet, g.xsl, which matches on an element 't' and
    calls the named template in (1) with a tunneled parameter.

    <xsl:stylesheet 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
      <xsl:import href="t.xsl"/>
      <xsl:template mode="t" match="t" priority="1">
        <xsl:call-template name="t">
          <xsl:with-param name="a" select="'g'" tunnel="yes"/>
        </xsl:call-template>
      </xsl:template>
    </xsl:stylesheet>
    
(3) A "specific" stylesheet, s.xsl, which assumes it can fall-back to
    templates in (2) with a tunneled parameter.

    Because it is processing a source document filled with other
    elements and text nodes, it also contains a generic match to
    navigate the document while surpressing default XSLT behavior.

    <xsl:stylesheet 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
      <xsl:import href="g.xsl"/>
      
      <xsl:template mode="t" match="@*|node()">
        <xsl:apply-templates mode="#current"/>
      </xsl:template>
    
      <xsl:template mode="t" match="t[(_at_)specific eq 'yes']" 
priority="2">
        <xsl:next-match>
          <xsl:with-param name="b" select="'s'" tunnel="yes"/>
        </xsl:next-match>
      </xsl:template>
    </xsl:stylesheet>
    
(4) A source document with a lot of text nodes in it, none of which I
    want to have emitted.  I just want a final result of an
    xsl:message ('t: g, s') to be emitted.

    <x>text<y>text<t specific="yes"/>text</y>text</x>


Because (3) has a template match "@*|node()", which is lower 
precedence, the xsl:next-match won't ever fall back to (2).  
This means I have to make one of the following changes to (3):

 (a) change the xsl:import to xsl:include.
 (b) change the xsl:next-match to xsl:apply-import.
 (c) not use a generic match="@*|node()", require that callers
     specifically target the elements to be processed

I'm wondering if there are any other options available?  If 
not, is there one of those which the developers here would 
recommend as being likely to be better for long term maintenance?

I'm disclined to choose (c).  The problems I have with (a) 
and (b) are that they seem to imply a limitation in later 
flexibility of the stylesheets (e.g., having parameters w/ 
the same name but different precedence in (2) and (3), or 
allowing for xsl:next-match to work on templates introduced into (3))

My inclination, at this point, is that it will be better to 
use xsl:include and require that both generic and specific 
template matches have their priorities renumbered as new 
functionality as added.

I'd appreciate any thoughts on this from you folks!


Thank you,

Jim

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
James A. Robinson                       
jim(_dot_)robinson(_at_)stanford(_dot_)edu
Stanford University HighWire Press      http://highwire.stanford.edu/
+1 650 7237294 (Work)                   +1 650 7259335 (Fax)

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--