6.6. XSLT to XSieve

The main XSieve commands are x:eval and x:apply-templates which correspond to the XSLT functions xsl:copy-of and xsl:apply-templates. To make a stress test for the XSieve commands, we can take an XSLT program, convert the XSLT program to an XSieve program and compare results of the XSLT and XSieve programs. Results should be same.

The XSieve program xslt2xsieve.xsl automatically converts XSLT to XSieve. There are several tests.

6.6.1. Converting XSLT elements to XSieve

Example 21. Converting xsl:copy-of

XSLT fragment:

<x:copy-of select="xpath"/>

XSieve fragment:

<s:scheme>(x:eval "escaped-xpath")</s:scheme>

Example 22. Converting xsl:value-of

XSLT fragment:

<x:value-of select="xpath"/>

XSieve fragment:

<s:scheme>(x:string (x:eval "escaped-xpath"))</s:scheme>

XSieve doesn't support the attribute disable-output-escaping, so xslt2xsieve skips xsl:value-of elements with this attribute.

Example 23. Converting xsl:apply-templates

XSLT fragment:

<x:apply-templates mode="mode" select="xpath">
  <x:with-param name="param1" select="xpath1"/>
  ...
  <x:with-param name="paramN" select="xpathN"/>
</x:apply-templates>

XSieve fragment:

(x:apply-templates
  'mode 'mode
    'with-param 'param1 (x:eval "escaped-xpath1")
    ...
    'with-param 'paramN (x:eval "escaped-xpathN")
  (x:eval "escaped-xpath"))

The attribute mode and the elements with-param can be missed. In this case the XSieve code doesn't contain the corresponding fragments.

To be converted to XSieve, an element xsl:apply-templates should satisfy all the following requirements.

  • An attribute select is present.

  • There is no element xsl:sort.

  • All xsl:with-param elements have an attribute select.

Example 24. Converting xsl:variable, xsl:param, xsl:with-param

XSLT fragment:

<x:variable name="varname" select="xpath"/>

XSLT with XSieve fragment:

<x:variable name="varname">
  <s:scheme>(x:eval "escaped-xpath")</s:scheme>
</x:variable>

For xsl:param and xsl:with-param, translation is similar.

Note

This conversion is disabled for two reasons;

  • It makes the DocBook test very slow.

  • Sometimes it's incorrect to use a content template instead of the attribute select.

Example 25. Moving select is not correct

<x:template match="/*">
  <x:variable name="v1" select="false()"/>
  <x:variable name="v2"><x:copy-of select="false()"/></x:variable>
  <x>
    <t1><x:value-of select="not($v1)"/></t1>
    <t2><x:value-of select="not($v2)"/></t2>
  </x>
</x:template>

Result is the following.

<x><t1>true</t1><t2>false</t2></x>

Variable v2 is a nodeset, not a value, so not($v2) is false.

6.6.2. Issue of escaping

In a naive approach, when the value of an attribute select contains quotes, the corresponding x:eval raises an error.

Example 26. Incorrect transformation of the attribute select

<x:text>(x:eval "</x:text>
<x:value-of select="@select"/>
<x:text>")</x:text>

Consider the following source XML.

<... select="concat(&quot;'&quot;,d,'&quot;')" .../>

Result of the transformation is an incorrect Scheme program.

(x:eval "concat("'",d,'"')")

To make the program correct, it's required to escape quotes. The task is not easy for the plain XSLT, so the xslt2xsieve program is an XSieve program. The right transformation uses a function written in Scheme.

Example 27. Correct transformation of the attribute select

<x:text>(x:eval "</x:text>
<s:scheme>(xlib:escape-for-string (x:string (x:eval "@select")))</s:scheme>
<x:text>")</x:text>

The function xlib:escape-for-string is defined in the file xslt2xsieve.scm.

6.6.3. Issue of namespace-alias

The simplest way to create elements is to write them literally. Unfortunately, it's not an option for xslt2xsieve.xsl because it is an XSieve program, and literal XSieve elements are executed instead of been copied to output.

Example 28. Executing instead of copying

<x:stylesheet ... xmlns:s="http://xsieve.sourceforge.net"
        extension-element-prefixes="s" ... >
...
<x:template match="hello">
  <s:scheme>                    1
    (display "Hello, <x:value-of select="@object"/>")
  </s:scheme>
</x:template>
1

This s:scheme is not copied to output, but is executed, which raises an error.

The XSLT specification recommends to use the xsl:namespace-alias element to workaround the problem.

Example 29. Using xsl:namespace-alias

<x:stylesheet ... xmlns:s="http://xsieve.sourceforge.net"
        extension-element-prefixes="s"
        xmlns:sa="http://xsieve.sourceforge.netAlias" ... >      1
<x:namespace-alias stylesheet-prefix="sa" result-prefix="s"/>    2
...
<x:template match="hello">
  <sa:scheme>                                                    3     
    (display "Hello, <x:value-of select="@object"/>")
  </sa:scheme>
</x:template>
1

Defining auxiliary namespace with any prefix and any URI.

2

Defining that the auxiliary namespace will be the XSieve namespace in the result document.

3

Writing an XSieve element literally.

Unfortunately, in the xslt2xsieve program, using xsl:namespace-alias doesn't help. Applying the program to itself gives namespace collision, and it's not the fault of XSieve, but the fault of libxslt. A simplified example is submitted as a bug to the libxslt team.

As result, instead of the literal form, the real xslt2xsieve program uses xsl:element to create XSieve elements.

Example 30. Using xsl:element instead of the literal form

<x:stylesheet ... xmlns:s="http://xsieve.sourceforge.net"
        extension-element-prefixes="s" ... >
...
<x:template match="hello">
  <x:element name="s:scheme">
    (display "Hello, <x:value-of select="@object"/>")
  </x:element>
</x:template>

6.6.4. Issue of extension-element-prefixes

A part of generating a correct XSieve program is

  • defining the XSieve namespace and

  • and making this namespace an extension namespace.

The corresponding fragment of xslt2xsieve.xsl follows.

Example 31. Creating an XSieve program heading

<x:template match="x:stylesheet">                    1
  <x:copy>                                           2
    <x:copy-of select="@*"/>                         3
    <x:attribute name="extension-element-prefixes">  4
      <x:value-of select="concat('s ',@extension-element-prefixes)"/>
    </x:attribute>
    <x:attribute name="s:dummy"/>                    5
    <x:apply-templates select="node()"/>             6
  </x:copy>
</x:template>
1

The template is matched against the root stylesheet element xsl:stylesheet.

2

Element xsl:stylesheet is created in the output.

3

All attributes of the original xsl:stylesheet are copied to the output.

4

The attribute extension-element-prefixes specifies that the namespace with the prefix s is an extension namespace. An original XSLT stylesheet might use XSLT extensions (such as exsl), so old value of the attribute is retained.

5

The XSieve namespace should be defined in the element xsl:stylesheet, otherwise extension-element-prefixes raises an error. Adding a dummy attribute from the XSieve namespace forces XSLT processor to create a corresponding namespace definition.

6

The rest of an input file is processed.

Unfortunately, the code isn't 100%-correct. Imagine a situation when input file uses the prefix s with some URI other than XSieve URI. In this case we get namespace prefix collision, which in general can't be resolved (consider content of extension-element-prefixes). Hopefully, the possibility of the situation should be very very small.