Project

Profile

Help

type safe xslt, how to address the type?

Added by Jos van den Oever over 9 years ago

I'd like to write type-safe xslt. I've written a small test to try this out with Saxon EE 9.5. Unfortunately, this gives me this error message:

<pre>
Description: XTTE0505: Required item type of result of template shouldPass1 is element(a, type1); supplied value has item type element(a, xs:untyped)
Start location: 19:0 
</pre>

Am I addressing the type in the wrong way?

<pre>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
  xmlns="urn:valtest"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="urn:valtest"
  elementFormDefault="qualified">

  <xs:complexType name="type1">
    <xs:sequence minOccurs="1" maxOccurs="1">
      <xs:element name="a" type="type2" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="type2">
    <xs:sequence/>
  </xs:complexType>

  <xs:element name="a" type="type1"/>

</xs:schema>
</pre>

<pre>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:v="urn:valtest"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">

        <xsl:import-schema namespace="urn:valtest"
                schema-location="valtest.xsd" />

        <xsl:template match="/" as="element(test)">
                <test>
                        <xsl:call-template name="shouldPass1" />
                        <xsl:call-template name="shouldPass2" />
                        <xsl:call-template name="shouldFail1" />
                        <xsl:call-template name="shouldFail2" />
                </test>
        </xsl:template>

        <xsl:template name="shouldPass1" as="element(v:a, v:type1)">
                <v:a>
                        <v:a />
                </v:a>
        </xsl:template>

        <xsl:template name="shouldPass2" as="element(v:a, v:type2)">
                <v:a />
        </xsl:template>

        <xsl:template name="shouldFail1" as="element(v:a, v:type1)">
                <v:a />
        </xsl:template>

        <xsl:template name="shouldFail2" as="element(v:a, v:type2)">
                <v:a>
                        <v:a />
                </v:a>
        </xsl:template>
</xsl:stylesheet>
</pre>

Replies (8)

Please register to reply

RE: type safe xslt, how to address the type? - Added by Michael Kay over 9 years ago

XSLT coding questions that are not specific in any way to Saxon are probably best posted on StackOverflow, to reach the widest audience.

Your template name="shouldPass1" creates an untyped element named v:a. This will not satisfy the type element(v:a, v:type1). To create an element with that type annotation you need to ensure it is validated, which you could do by writing

<pre>
<v:a xsl:validation="strict">
</pre>

or

<pre>
<v:a xsl:type="v:type1">
</pre>

RE: type safe xslt, how to address the type? - Added by Jos van den Oever over 9 years ago

Assigning the type helps to solves the error.

I'll add a Saxon specific observation: the templates @shouldFail1@ and @shouldFail2@ both give errors now. @shouldFail1@ only gives an error at runtime, @shouldFail2@ gives an error at compile time in Saxon 9.5.1.7.

<pre><code class="xml">
	<xsl:template name="shouldFail1" as="element(v:a, v:type1)">
		<v:a xsl:type="v:type1"/>
	</xsl:template>
</code></pre>

<pre><code class="xml">
	<xsl:template name="shouldFail2" as="element(v:a, v:type2)">
		<v:a xsl:type="v:type2">
				<v:a />
		</v:a>
	</xsl:template>
</code></pre>

RE: type safe xslt, how to address the type? - Added by Michael Kay over 9 years ago

It would be useful to say what the errors are...

Saxon detects some type errors at compile time, but not all. That's sometimes because there is a good theoretical reason why the error can't be detected statically, and it's sometimes because Saxon's static analyzer is not powerful enough and could (in theory) be improved.

RE: type safe xslt, how to address the type? - Added by Jos van den Oever over 9 years ago

Obviously not all errors can be detected at compile-time; my observation was not meant as complaint or bug finding. I'm glad now know that xslt can be run with some compile-time error detection. The most common errors are probably the ones where an element is created in a context where it is not allowed and those are probably detected by Saxon. And as far as I know, Saxon EE is the only xslt processor that can find such problems at compile time.

The error that is detected at compile time says that a particular nesting is not allowed. The error that is detected by Saxon at runtime says that a particular required element is missing from another element.

RE: type safe xslt, how to address the type? - Added by Michael Kay over 9 years ago

I think that if a template can be statically analyzed to show that it creates a child or descendant element that is not allowed by its parent, Saxon will detect this statically. But failure to create a child element that is required by the parent is not something we attempt to detect. (Similarly, we don't detect when the sequence or cardinality of child elements is incorrect).

RE: type safe xslt, how to address the type? - Added by Jos van den Oever over 9 years ago

That's a level of static checking close to what statically typed programming languages could achieve if they had the data model for the specific xml schema available as language specific data types.

One relatively simple static check that could be done is to see if an element in a template has any xsl descendant elements, attributes or xpath expressions. If it does not, and if the type is known, the element could be fully validated statically.

RE: type safe xslt, how to address the type? - Added by Jos van den Oever over 9 years ago

Is there a way to run an xsl with @xsl:import-schema/@ or @@xsl:type@ with Saxon PE or EE? The inverse of @-sa@ if you will.

Not all the software we use has a full Saxon EE available. One method to fix this is to strip from the xsl before running it on these other systems, but perhaps there is a configuration option in Saxon that helps here.

RE: type safe xslt, how to address the type? - Added by Michael Kay over 9 years ago

I think the only way is to use the @use-when attribute.

    (1-8/8)

    Please register to reply