Tuesday, January 22, 2008

Portability of a stylesheet across schema-aware and non-schema-aware processors

I came across this today, which I thought was really cool and worth a post. It basically allows you to code a transform that is only schema-aware if a schema-aware processor is running it, otherwise it's just a standard transform.

In this case I want to do input and output validation, so first I sort out the schemas:

<xsl:import-schema schema-location="input.xsd"
    namespace="http://www.foo.com"
    use-when="system-property('xsl:is-schema-aware')='yes'"/>

<xsl:import-schema schema-location="output.xsd"
    use-when="system-property('xsl:is-schema-aware')='yes'"/>

Note the use-when...

Next define two root matching templates, one for schema-aware, one for basic:

<xsl:template match="/"
    use-when="system-property('xsl:is-schema-aware')='yes'"
    priority="2">
    
    <xsl:variable name="input" as="document-node()">
        <xsl:document validation="strict">
            <xsl:copy-of select="/"/>
        </xsl:document>
    </xsl:variable>
    
    <xsl:result-document validation="strict">
        <xsl:apply-templates select="$input/the-root-elem"/>
    </xsl:result-document>
    
</xsl:template>

<xsl:template match="/">
    <xsl:apply-templates select="the-root-elem"/>
</xsl:template>    
    
<xsl:template match="the-root-elem">
    ...
</xsl:template>

The root matching template for schema-aware processing uses xsl:document to validate the input, and xsl:result-document to validate the output. Validation can also be controlled from outside the transform, but this way forces it on.

I think this is great :)

4 comments:

David said...

Interestingly making code work for both schema aware and basic processors was one of the motivating reasons for use-when

Old comment on xslt 2 draft

(it's not called use-when there, but that's what it became)

Wouldn't you normally want to run the templates on the validated (type annotated) $input/the-root-elem
rather than the original (unvalidated?) node?
perhaps not if the other templates assume that the input tree doesn't have typed nodes, for compatibility with basic processors....

Andrew Welch said...

So you're responsible... :)

I'm not quite with you on the last point - how else would I do it?

David said...

I'd have expected

<xsl:result-document validation="strict">
<xsl:apply-templates select="$input/the-root-elem"/>
</xsl:result-document>


as you have it, $input isn't actually used, so saxon presumably may not even evaluate it at all, so the input might not get validated at all, and even if it is, the templates that are applied will only see untyped nodes not nodes with type annotations from the schema.

This is assuming that the input is not schema validated before processing starts if it is, then the

<xsl:document validation="strict">
<xsl:copy-of select="/"/>

isn't doing anything is it?

This is all theoretical, I haven't actually got a schema aware system to try....

Andrew Welch said...

Ah well spotted - a typo when converting the real stylesheet to something suitable for here.

Now corrected - thanks.