[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Defining variables as sequence of strings


Subject: Re: [xsl] Defining variables as sequence of strings
From: "Dimitre Novatchev dnovatchev@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 14 May 2015 02:13:31 -0000

Hi Joseph,

>> I typically recommend to avoid using explicit XSLT conditional
>
>> instructions. This said, here is an example as requested:
>
>
>
> Hi Dimitre,
>
> Thanks for the recommendation, I am certainly inclined to take your
>
> advice however just so I understand can you elaborate on why?
>

The reason is the same as for recommending to prefer
<xsl:apply-templates> to <xsl:for-each>

In the latter case the sequence constructor (code) of the
<xsl:for-each> instruction is hardcoded and the transformation isn't
polymorphic.

In the former case, the author generally doesn't know which matching
template will be selected for execution, and in fact, such templates
can be written years apart by people that  the author doesn't know.
This is similar to the difference between a virtual function and a
non-virtual function in an object-oriented language, such as C++,
Java, C#, etc.

The recommendation to try to avoid conditionals is part of the DRY
(Don't Repeat Yourself) principle -- exactly on the same grounds.

So, following this principle, it is preferable to avoid even XPath 2.0
(and above) conditional expressions, and use templates exclusively.

Here is an example, based on the code that you provided.

Suppose we have this XML document:

<object>
  <property name="name" type="foo"/>
  <property name="key" type="bar"/>
  <property name="size" type="baz"/>
  <property name="age" type="bof"/>
  <property name="grade" type="goo"/>
</object>

then this transformation does the wanted processing without having any
conditional instruction at all:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output method="text"/>

 <xsl:template match="/*">
   <xsl:variable name="vTypes" as="xs:string*">
     <xsl:apply-templates select="*/@type"/>
   </xsl:variable>

   <xsl:perform-sort select="distinct-values($vTypes)">
     <xsl:sort select="."/>
   </xsl:perform-sort>
 </xsl:template>

 <xsl:template match="property/@type[. eq 'foo']">
   <xsl:sequence select="'a', 'b'"/>
 </xsl:template>
 <xsl:template match="property/@type[. = ('bar', 'baz', 'bof')]">
   <xsl:sequence select="'b', 'c'"/>
 </xsl:template>
 <xsl:template match="property/@type" priority="-1">
   <xsl:sequence select="'c', 'd'"/>
 </xsl:template>
</xsl:stylesheet>

The result is the wanted and expected:

a b c d


Do note, that different people can independently of each other import
your stylesheet module and override any of the templates matching
"property/@type" -- without having to change your stylesheet module,
and without affecting each-other's code.

This would be impossible if the imported stylesheet module contained
hardcoded conditionals (be it <xsl:choose> or XPath expressions).

Also note, that in XSLT 3.0 the polymorphic nature of the language
have been extended even further, because templates can be applied not
only on nodes, but on any atomic item or even on any function.

Cheers,
Dimitre


On Wed, May 13, 2015 at 5:57 PM, Joseph L. Casale
jcasale@xxxxxxxxxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
wrote:
>> I typically recommend to avoid using explicit XSLT conditional
>
>> instructions. This said, here is an example as requested:
>
>
>
> Hi Dimitre,
>
> Thanks for the recommendation, I am certainly inclined to take your
>
> advice however just so I understand can you elaborate on why?
>
>
>
>> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
>>  xmlns:xs="http://www.w3.org/2001/XMLSchema">
>
>>  <xsl:output method="text"/>
>
>>  <xsl:template match="/*">
>
>>    <xsl:variable name="vDays" as="xs:string*" >
>
>>      <xsl:choose>
>
>>         <xsl:when test=". eq 'Biology'">
>
>>            <xsl:sequence select="'Monday', 'Thursday'"/>
>
>>         </xsl:when>
>
>>         <xsl:when test=". eq 'Math'">
>
>>            <xsl:sequence select="'Tuesday', 'Friday'"/>
>
>>         </xsl:when>
>
>>      </xsl:choose>
>
>>    </xsl:variable>
>
>>
>
>>    <xsl:sequence select="string-join($vDays, ' and ')"/>
>
>>  </xsl:template>
>
>> </xsl:stylesheet>
>
>
>
> That was my first crack, but as it iterates through nodes I need to add
>
> each occurrence to the sequence.
>
>
>
>> This can also be written in a shorter way as:
>
>>
>
>> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
>>  xmlns:xs="http://www.w3.org/2001/XMLSchema">
>
>>  <xsl:output method="text"/>
>
>>  <xsl:template match="/*">
>
>>    <xsl:variable name="vDays" as="xs:string*" select=
>
>>     "if(. eq 'Biology')
>
>>         then ('Monday', 'Thursday')
>
>>         else if (. eq 'Math')
>
>>           then ('Tuesday', 'Friday')
>
>>           else () "/>
>
>>
>
>>    <xsl:sequence select="string-join($vDays, ' and ')"/>
>
>>  </xsl:template>
>
>> </xsl:stylesheet>
>
>
>
> I ended up not worrying about XSLT 1 support for the moment until
>
> I revisit it and used:
>
>
>
>     <xsl:variable name="MyVar" as="xs:string *">
>
>       <xsl:sequence select="for $t in distinct-values(/object/property/@type) return
>
>                     if ($t='foo')
>
>                       then 'a'
>
>                     else if ($t='bar' or $t='baz' or $t='bof')
>
>                       then 'b'
>
>                     else 'c'" />
>
>     </xsl:variable>
>
>
>
>     <xsl:for-each select="distinct-values($MyVar)">
>
>       <xsl:sort select="." />
>
>       <xsl:text>...</xsl:text>
>
>       <xsl:value-of select="." />
>
>       <xsl:text>;&#x0D;&#x0A;</xsl:text>
>
>     </xsl:for-each>
>
>
>
> Thanks a lot Dimitre,
>
> jlc
>
> 



-- 
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
To avoid situations in which you might make mistakes may be the
biggest mistake of all
------------------------------------
Quality means doing it right when no one is looking.
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
-------------------------------------
To achieve the impossible dream, try going to sleep.
-------------------------------------
Facts do not cease to exist because they are ignored.
-------------------------------------
Typing monkeys will write all Shakespeare's works in 200yrs.Will they
write all patents, too? :)
-------------------------------------
I finally figured out the only reason to be alive is to enjoy it.


Current Thread
Keywords