Skip to content

Improvements to reported location using SchematronResourceSCH from ph-schematron-xslt 9.1.1 #194

@jaw111

Description

@jaw111

I am using SchematronResourceSCH from ph-schematron-xslt 9.1.1 with this Schematron XML:

<schema xmlns="http://purl.oclc.org/dsdl/schematron">
    <ns prefix="ns1" uri="urn:test:namespace1"/>
    <pattern>
        <rule context="ns1:value">
            <assert test="number(.) gt 100" role="WARN">Value must be greater than 100</assert>
            <assert test="@type = ('decimal', 'integer', 'string')" subject="@type">Unknown type</assert>
        </rule>
        <rule context="ns1:value/@type">
            <assert test=". = ('decimal', 'integer', 'string')">Unknown type</assert>
        </rule>
    </pattern>
</schema>

To validate this XML:

<root xmlns="urn:test:namespace1">
    <value type="int">50</value>  <!-- This should fail validation -->
</root>

The locations that are reported are:

  • /*[local-name()='root']/*[local-name()='value'] - no namespace is specified
  • int - this is the value of the attribute, not the location

After running with debug set to show created XSLT, there are several deficiencies in the templates for modes schematron-select-full-path and schematron-get-full-path.

By modifying those templates as follows, I can get the expected locations:

<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<template match="node() | @*" mode="schematron-select-full-path">
    <apply-templates mode="schematron-get-full-path" select="."/>
</template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<template match="*" mode="schematron-get-full-path">
    <apply-templates mode="schematron-get-full-path" select="parent::*"/>
    <text>/</text>
    <choose>
        <when test="namespace-uri()=''">
            <value-of select="name()"/>
            <variable name="p_1" select="1+    count(preceding-sibling::*[name()=name(current())])"/>
            <if test="$p_1>1 or following-sibling::*[name()=name(current())]">[<value-of select="$p_1"/>]</if>
        </when>
        <otherwise>
            <text>*[local-name()='</text>
            <value-of select="local-name()"/>
            <text>' and namespace-uri()='</text>
            <value-of select="namespace-uri()"/>
            <text>']</text>
            <variable name="p_2" select="1+   count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri()=namespace-uri(current())])"/>
            <if test="$p_2>1 or following-sibling::*[local-name()=local-name(current()) and namespace-uri()=namespace-uri(current())]">[<value-of select="$p_2"/>]</if>
        </otherwise>
    </choose>
</template>
<template match="@*" mode="schematron-get-full-path">
    <apply-templates mode="schematron-get-full-path" select="parent::*"/>
    <text>/</text>
    <choose>
        <when test="namespace-uri()=''">@<value-of select="name()"/>
        </when>
        <otherwise>
            <text>@*[local-name()='</text>
            <value-of select="local-name()"/>
            <text>' and namespace-uri()='</text>
            <value-of select="namespace-uri()"/>
            <text>']</text>
        </otherwise>
    </choose>
</template>

With these changes the the locations are:

  • /*[local-name()='root' and namespace-uri()='urn:test:namespace1']/*[local-name()='value' and namespace-uri()='urn:test:namespace1']
  • /*[local-name()='root' and namespace-uri()='urn:test:namespace1']/*[local-name()='value' and namespace-uri()='urn:test:namespace1']/@type

I'm not sure exactly which file in the codebase requires modification, but if you can point me to it, I'd be happy to open a pull request.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions