xsl-list
[Top] [All Lists]

Re: XSLT 2.0 *and* XSLT 1.0 validation -- how to?

2004-10-24 12:39:47
Hi Dimitre,

The trouble is that XSLT allows regions of a stylesheet to belong
to different versions. In XSLT 1.0, you can put an xsl:version
attribute on any literal result element to indicate the version of
XSLT used in the content of that element. In XSLT 2.0, any XSLT
element can have a version attribute, and any other element can
have a xsl:version attribute that does the same thing.

Oh, I didn't know that... My first reaction is to wonder if such a
feature can be really useful.

The rationale is that it allows you to upgrade part of your stylesheet
without having to upgrade all of it. The parts of an XSLT 2.0
stylesheet that are marked as XSLT 1.0 run under
backwards-compatibility mode, which means that (in general) things
work as they did under XSLT 1.0 (e.g. you have weak typing, first-item
semantics, numeric comparisons). This is handy if you have a big XSLT
1.0 stylesheet, and you want a little bit of XSLT 2.0 functionality
but don't want to upgrade the entire thing just now.

Personally, I don't think that it's worth validating XSLT stylesheets
against a schema. It's simpler, quicker, more accurate and more
helpful to get an XSLT processor to check your stylesheet instead.

I also thought so in the past, but one can quickly get a powerful
language construction/editing environment -- by simply providing a
schema to an intelligent editor one can get correct
structure/intellisense support. And this is an example of really
good use of schemas.

Right: using a schema to *validate* XSLT stylesheets isn't worthwhile
(and that's what the subject line indicated you were asking about),
but using a schema for other reasons (such as intellisense, or when
querying/generating XSLT using XSLT 2.0) could be, potentially.

The usual way to get around the lack of support for co-occurrence
constraints in WXS is to use xsi:type. So... you could design a schema
in which there were version 1.0 and version 2.0 types for each
element. Then use the xsi:type attribute to indicate the version
you're using in the stylesheet. For example:

<xs:element name="stylesheet" type="stylesheet" />

<!-- general type allows anything allowed by XSLT (incorporating
     forwards-compatibility) -->
<xs:complexType name="stylesheet">
  <xs:sequence>
    <xs:element name="import" type="import"
                minOccurs="0" maxOccurs="unbounded" />
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:any namespace="##targetNamespace" processContents="lax" />
      <xs:any namespace="##other" processContents="lax" />
    </xs:choice>
  </xs:sequence>
  <xs:attribute name="version" use="required" type="xs:decimal" />
  ...
</xs:complexType>

<!-- restricted type only allows XSLT 1.0 stylesheets -->
<xs:complexType name="stylesheet-v1.0">
  <xs:complexContent>
    <xs:restriction base="stylesheet">
      <xs:sequence>
        <xs:element name="import" type="import-v1.0"
                    minOccurs="0" maxOccurs="unbounded" />
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="template" type="template-v1.0" />
          ...
          <xs:any namespace="##other" />
        </xs:choice>
      </xs:sequence>
      <xs:attribute name="version" fixed="1.0" />
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>

<!-- restricted type only allows XSLT 2.0 stylesheets -->
<xs:complexType name="stylesheet-v2.0">
  <xs:complexContent>
    <xs:restriction base="stylesheet">
      <xs:sequence>
        <xs:element name="import" type="import-v2.0"
                    minOccurs="0" maxOccurs="unbounded" />
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="template" type="template-v2.0" />
          ...
          <xs:any namespace="##other" />
        </xs:choice>
      </xs:sequence>
      <xs:attribute name="version" fixed="2.0" />
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>

and then use:

<xsl:stylesheet version="1.0" xsi:type="stylesheet-v1.0" ...>

in your stylesheet.

The trouble with this approach (aside from its complexity) is that
once you use a literal result element in your stylesheet, its content
can't be constrained based on the version of XSLT you're using. You
could declare all the literal result elements that you use in your
stylesheet, or you could use <xsl:element> and <xsl:attribute>
instead.

Other possibilities are just using an XSLT 2.0 schema all the time,
and relying on your knowledge of XSLT 1.0 to prevent you using XSLT
2.0 elements in an XSLT 1.0 stylesheet; or you could use a fake
namespace for your XSLT 2.0 stylesheets (changing it on load and on
save) and get different schemas for different stylesheets. If the
software picks up on the xsi:schemaLocation attribute, then you could
use that to indicate the schema that you wanted to use with a
particular stylesheet.

If the software supports RELAX NG, you're in better luck, because you
can use co-occurrence constraints with RNG, and wildcards in RNG are a
lot more flexible than those in WXS.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



<Prev in Thread] Current Thread [Next in Thread>