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: Fri, 15 May 2015 03:40:58 -0000
>>   <xsl:variable name="vSorted" as="xs:string*">
>>      <xsl:perform-sort select="distinct-values($vTypes)">
>>       <xsl:sort select="."/>
>>      </xsl:perform-sort>
>>      </xsl:variable>
>>
>>      <xsl:value-of select=
>>       "$vSorted/concat('...Some other text (', ., ') More Text....')"
>> separator="&#xD;&#xA;"/>
>
> OK, looking at this, I don't think the / operator is allowed on a
> sequence of strings -- it is allowed only on a sequence of nodes.
>
> However I used XML-SPY -- the only XSLT 2.0 processor I have at work,
> and it worked OK.
>
>
> I will need to get back home and try using Saxon.

Hi Joseph,
Yes, you are right that it is close to impossible in XSLT 2.0 to
process a sequence of atomic items (strings in this case) in a
polymorphic way.

Here is one solution that avoids using <xsl:for-each> or using
recursively called named templates:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
   <xsl:output method="text"/>
   <xsl:key name="kTextByVal" match="t" use="."/>
   <xsl:template match="/*">
     <xsl:variable name="vTypes">
       <xsl:apply-templates select="*/@type"/>
     </xsl:variable>

     <xsl:apply-templates mode="distinct-text" select=
      "$vTypes/*[generate-id()
              =generate-id(key('kTextByVal', ., $vTypes)[1])]">
       <xsl:sort/>
      </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="text()" mode="distinct-text">
...Some other text (<xsl:value-of select="."/>) More Text....)
  </xsl:template>

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

When this transformation is applied on the previously supplied 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>

the wanted result is produced:

...Some other text (a) More Text....)

...Some other text (b) More Text....)

...Some other text (c) More Text....)

...Some other text (d) More Text....)

You can certainly spot that I cheated, and the intermediate results
are not just sequences of strings, but sets of elements, whose
text-node children have as value the wanted strings. And also, I am
not using the distinct-values() function, but Muenchiam grouping
(<xsl:for-each-group> can also be used) to avoid getting as result a
sequence of strings.

This allows us to apply templates on the elements and to use an
<xsl:sort/> child of the <xsl:apply-templates> instruction, to perform
the sorting.

In contrast, see how easy is to do the same in XSLT 3.0:

<xsl:stylesheet version="3.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:apply-templates select="distinct-values($vTypes)">
      <xsl:sort/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match=".[. instance of xs:string]">
...Some other text (<xsl:value-of select="."/>) More Text....')
  </xsl:template>

  <xsl:template match="property/@type[. eq 'foo']">
    <xsl:sequence select="'c', 'd'"/>
  </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="'b', 'a'"/>
  </xsl:template>
</xsl:stylesheet>


Here we really apply templates on a the sequence of strings:

    <xsl:apply-templates select="distinct-values($vTypes)">
      <xsl:sort/>
    </xsl:apply-templates>

and the processing is done in the template:

 <xsl:template match=".[. instance of xs:string]">
...Some other text (<xsl:value-of select="."/>) More Text....')
  </xsl:template>

which matches any string.

This is a powerful new feature of XSLT 3.0, among many other amazing features.


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