Schematron / schematron

Schematron "skeleton" - XSLT implementation
MIT License
93 stars 45 forks source link

Creates invalid stylesheet if attribute value templates are used in foreign elements #82

Open nkutsche opened 5 years ago

nkutsche commented 5 years ago

Hi,

the skeleton creates an invalid stylessheet for this schema:

<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"
    xmlns:sqf="http://www.schematron-quickfix.com/validator/process">
    <sch:pattern>
        <sch:rule context="any-context">
            <!--  do some test  -->
            <sqf:fix id="fix">
                <sqf:description>
                    <sqf:title>Sample fix</sqf:title>
                </sqf:description>
                <sch:let name="regex" value="'some regex'"/>
                <sqf:stringReplace match="." regex="{$regex}" select="'replacement'"/>
            </sqf:fix>
        </sch:rule>
    </sch:pattern>
</sch:schema>

The variable is not compiled as xsl:variable but the attribute value template is copied as it is, so the error is:

Error at sqf:stringReplace on line 197 column 87 of test.xsl:
  XPST0008: XPath syntax error at char 7 on line 197 in {{$regex}}:
    Variable $regex has not been declared
Failed to compile stylesheet. 1 error detected.

I think the problem is not that the variable is not compiled, but that the attribute value template is copied unchanged.

A workaround is, to add a global dummy variable with the same name:

<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"
    xmlns:sqf="http://www.schematron-quickfix.com/validator/process">
      <sch:let name="regex" value="'dummy'"/>
dmj commented 5 years ago

The provided schema is not a valid Schematron document: The sch:let appears inside the sqf:fix, this is forbidden by the schema in Annex A.

foreign = foreign-attributes, foreign-element*
foreign-empty = foreign-attributes
foreign-attributes = attribute * - (local:* | xml:*) { text }*
foreign-element =
     element * - sch:* {
         (attribute * { text }
          | foreign-element
          | schema
          | text)*
     }

That's why the variable is not bound and adding a variable helps.

nkutsche commented 5 years ago

As I wrote:

I think the problem is not that the variable is not compiled, but that the attribute value template is copied unchanged.

The QF could also contain a sqf:param or sqf:user-entry element:

<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"
    xmlns:sqf="http://www.schematron-quickfix.com/validator/process">
    <sch:pattern>
        <sch:rule context="any-context">
            <!--  do some test  -->
            <sqf:fix id="fix">
                <sqf:param name="regex" default="'some regex'"/>
                <sqf:description>
                    <sqf:title>Sample fix</sqf:title>
                </sqf:description>
                <sqf:stringReplace match="." regex="{$regex}" select="'replacement'"/>
            </sqf:fix>
        </sch:rule>
    </sch:pattern>
</sch:schema>

In this case it is a valid Schematron document, but the error is the same.

I know, that this may a conflict of use cases, because if you escape attribute values of all foreign elements, you are not able to use them any more. So one possible solution would also be, to do not have just a switch for allowing/disallowing foreign elements, but to be able to give a list of namespaces of allowed/disallowed foreign elements.

dmj commented 5 years ago

Okay, now I get it. I would extend the API with a process-foreign template that by default copies the elements if allow-foreign is true and let a user override this callback if the foreign elements need special treatment.