xsl-list
[Top] [All Lists]

Re: [xsl] Input requested for a good genuine example of the best parts of XSLT 2

2007-01-24 16:52:16
I'd give as an example FXSL 2 (FXSL for XSLT 2.0).

Compare it to FXSL 1.x (FXSL for XSLT 1.0).

The difference is dramatic -- probably similar to traveling with the
first planes at the start of the 20th century and then using a modern
jet-liner nowadays.

So, I'd propose taking any FXSL major function or, better, its
application in solving a real problem, and comparing the FXSL2 and
FXSL 1.x - based solutions.

To summarize my own experience:

  - Dramatic code-shrink   -- What in FXSL 1.x required 20-30 lines
of code becomes typically a 1-liner with FXSL 2.

  - Dramatic performance improvements (yes, Saxon rocks!), some of
which seem counterintuitive to me and which I am still trying to
explain. Some FXSL 2 applications execute hundreds of times faster
(observed with Saxon only).

  - Dramatic increase of programmer productivity -- many
type-mismatch errors are caught even at static analysis (compile)
time. Using XSLT 1.0 such errors would remain burried hidden forever
and show their ugly head at most unexpected critical moments.
Not to speak about the error-revealing power of using an SA XSLT processor!
This leads me to:

  -  More reliable XSLT applications.

  - Less things XSLT can't do. With the addition of temporary trees
(avoiding the need of an xxx:node-set() extension), data types,
regular expressions, namespace nodes construction, reading arbitrary
(not only well-formed XML) text, creating multiple output (result)
files, the list of "things XSLT can't do" is now much shorter than the
one for XSLT 1.0.

 - Based on XPath 2.0. Often an XPath 2.0 expression can express a
whole program and this will almost eliminate the grounds for claiming
that XSLT "is not readable".



As  said earier in this message, examples of almost all these benefits
canbe found in the code of FXSL itself.



--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play




On 1/24/07, Abel Braaksma <abel(_dot_)online(_at_)xs4all(_dot_)nl> wrote:
Hi people,

During the ongoing discussion about XSLT 2 today and considering/not
considering the switch, I thought: why isn't there a nice
all-encompassing example that shows the merits of XSLT 2 over XSLT 1?
It'll come as no surprise that there's no trivial answer to that, so I
figured: why not ask the masses (some people claim that the masses are
always right, though that is debatable).

The target audience is: XSLT 1 users that would like to know more /
understand more of XSLT 2 and are considering the switch.

Before we start discussing the template itself, let me throw in some rules:

    1. The template must be 100% compliant to the REC
    2. There can be no extensions used of whatever kind
    3. The template must be rather simple, easy, explainable.
    4. It must be run on itself (i.e., no hassle with input files etc)
    5. It must show some key concepts, without showing too much detail
    6. Does not use functions that call or write resources
(xsl:result-document, unparsed-text etc)
    7. (optional) it should be runnable on the available xslt 2 processors

Apart from (6) and (7), I think it is fairly trivial. I put in (7) so
that people that want to see other tools in action (Saxon, Gestalt,
Altova) can see them in action (it follows that this means no SA
behavior, sorry). I put in (6) to keep the example rather trivial. If
users of mentioned and/or missing tools would be so kind as to answer
with a one-liner to call the template below from a command line?

About the details that should be in the example. I thought of a nice
example that can possibly be made infinitely better. Consider it a first
draft, and I invite everyone to shoot at it (you may even blast it away ;)

This what I put in so far:
  a) badly designed xml as input (in a variable, see rule 4)
  b) a micro pipeline
  c) for-each-group based on value to show groups without Muenchian
  d) xsl:function for camelcasing a string
  e) ranges, like "2 to 3" and comparison
  f) tokenize() and matches()
  g) for ... in .... return
  h) next-match
  i) the use of the 'as' attribute on basic processors

The example is rather trivial (it should be, I believe). It takes a list
of users of XSLT products, and groups them per product:

 <james-johnsson>Saxon, c, xslt 2</james-johnsson>
 <super-troopers>xsltproc, nc, xslt 1</super-troopers>

Here: the node name is the user. Then follows a CSV string. The first
part is the processor, the second says Compliant or NonCompliant, the
third says the language (I am pretty sure the input is not correct,
sorry about my lack of knowledge of the compliancy level).

The output groups per processor as follows, where some processing is
done on the strings and the users are comma-concatenated under <users>:

<processor name="Xsltproc">
  <level>processor is non-compliant</level>
  <language>XSLT 1</language>
  <users>George Williams Geraldson, Super Troopers</users>
</processor>


I understand this is a rather superficial example. If anybody can make
it better, clearer, input is welcome. Keep in mind that it should be
kept easy as well as showing the power of XSLT 2 (so it can be used as a
showcase).

Here's the XSLT so far, any ideas, complaints, suggestions, rewrites,
opinions etc are welcome:

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
   xmlns:xs = "http://www.w3.org/2001/XMLSchema";
   xmlns:my = "urn:my"
   version="2.0"
   exclude-result-prefixes="#all">

   <xsl:output indent="yes" />

   <!--
       the input, just in a variable
       ready to use, easy for testing, no need
       for exslt:node-set()
   -->
   <xsl:variable name="preferences">
       <james-johnsson>Saxon, c, xslt 2</james-johnsson>
       <george-williams-geraldson>xsltproc, nc, xslt
1</george-williams-geraldson>
       <super-troopers>xsltproc, nc, xslt 1</super-troopers>
       <merry-mirriams>libxslt, nc, xslt 1</merry-mirriams>
       <john-ronald-reuel-tolkien>saxon, c, xslt
2</john-ronald-reuel-tolkien>
       <sir-tomald-richards>gestAlt, nc, XSLT 2</sir-tomald-richards>
       <agatha-kirsten>saxon, c, xslt 2</agatha-kirsten>
       <mollie-jollie>saxon, c, xslt 2</mollie-jollie>
   </xsl:variable>

   <xsl:template match="/" name="main">
       <xsl:variable name="micro-pipeline">
           <xsl:apply-templates select="$preferences/*" />
       </xsl:variable>

       <!-- group by processor -->
       <xsl:for-each-group
           select="$micro-pipeline/processor"
           group-by="token[1]/upper-case(text())">

           <processor name="{my:camel-case(token[1])}" >
               <xsl:apply-templates select="token[position() = 2 to 3]" />
               <users>
                   <!--
                       join the users in one string
                       and camel case their names
                   -->
                   <xsl:value-of select="
                       string-join(
                       my:camel-case(current-group()/user)
                       , ', ')" />
               </users>
           </processor>
       </xsl:for-each-group>

   </xsl:template>

   <!--
       matches for $preferences nodes
   -->
   <xsl:template match="*" priority="0">
       <processor>
           <xsl:next-match />
       </processor>
   </xsl:template>

   <xsl:template match="*">
       <user><xsl:value-of select="local-name(.)" /></user>
       <xsl:next-match />
   </xsl:template>


   <xsl:template match="text()">
       <xsl:for-each select="tokenize(., ',')">
           <token><xsl:value-of select="normalize-space(.)" /></token>
       </xsl:for-each>
   </xsl:template>


   <!--
       what follows: matches for micro pipeline
       all matches are case-insensitive, with no
       need for translate() and trouble with more complex
       characters
   -->
   <xsl:template match="token[matches(., '^c$', 'i')]">
       <level>processor is compliant</level>
   </xsl:template>

   <xsl:template match="token[matches(., '^nc$', 'i')]">
       <level>processor is non-compliant</level>
   </xsl:template>

   <xsl:template match="token[matches(., '^xslt', 'i')]">
       <language><xsl:value-of select="upper-case(.)" /></language>
   </xsl:template>

   <!--
       put the nasty bit aside in a function
       it camel-cases a dashed or space delimited string
   -->
   <xsl:function name="my:camel-case" as="xs:string*">
       <xsl:param name="string" as="xs:string*"/>
       <xsl:sequence select="for $s in $string
           return string-join(
               for $word in tokenize($s, '-| ')
               return
                   concat(
                       upper-case(substring($word, 1, 1)),
                       substring($word, 2))
               , ' ')" />
   </xsl:function>
</xsl:stylesheet>



Cheers,
-- Abel Braaksma
  http://www.nuntia.nl

--~------------------------------------------------------------------
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>
--~--