phax / ph-schematron

Java Schematron library that supports XSLT and native application
Apache License 2.0
116 stars 36 forks source link

XSLT functions called from assertions cause compile fail #59

Closed fviolette closed 5 years ago

fviolette commented 7 years ago

With preprocess or not, assertions that rely on custom XSLT functions will fail to compile.

In the same file:

<sch:ns prefix="foo" uri="http://foo/bar/baz"/>
<sch:pattern id="foo-pattern">
    <sch:rule context="prodinfo/module">
        <sch:assert test="foo:hasZ(.)"/>
    </sch:rule>
</sch:pattern>
<xsl:function name="foo:hasZ" as="xs:boolean">
     <xsl:param name="id" as="xs:string"/>
     <xsl:value-of select="contains($id, 'z')"/>
</xsl:function>

Log:

check.map:
[schematron] Error in Schematron: [error] in PSAssertReport @ C:\git\test.sch
Failed to compile XPath expression in <assert>:
'foo:hasZ(.)' with the following variables: {} (javax.xml.xpath.XPathExpressionE
xception: net.sf.saxon.trans.XPathException: Cannot find a 1-argument function n
amed {http://foo/bar/baz}hasZ())
[schematron] Error in Schematron: [error] @ C:\git\test.sch
Error creating bound schema (java.lang.IllegalArgumentException: c
om.helger.schematron.pure.binding.SchematronBindException: Failed to precompile
the supplied schema.)
[schematron] The provided Schematron file contains errors. See log for details.

I have other examples with nested function calls (utils).

phax commented 7 years ago

That is correct :) You must provide the external functions somehow. It looks like you are using the pure version - in this case you must provide a custom function resolver via SchematronResourcePure.setFunctionResolver

phax commented 7 years ago

Did you manage to get it working?

fviolette commented 7 years ago

I planned to move these functions to abstract patterns as much as possible but haven't had time to look into this yet. If you can point me to a sample file, I'll be trying this by next week.

phax commented 7 years ago

I see the problem. The custom function resolver is only available for the pure version but not for the SCH/XSLT based version. So I will try to find a solution for this on SCH/XSLT basis.

phax commented 7 years ago

Maybe you can include the XSLT functions from your SCH? https://github.com/Schematron/schematron/issues/42 might be in this direction?

fviolette commented 7 years ago

Using pure validation engine, with SCH containing <xsl:function>, <xsl:param> and one two <xsl:template> (which have worked so far without any issues). Removing them does not help but I am going to dig deeper.

Other than that, I've just tested the adapted sample from https://github.com/Schematron/schematron/issues/42 with pure engine again.

If I <sch:value-of select="$test"/>, I get:

[schematron] 1 Schematron error for XML file 'C:\git\documentation-dita\developm
ent\configuration\fr\dm-use_secured_kafka_studio.ditamap'
[schematron]   [error] in /map/title @ C:\git\documentation-dita\development\con
figuration\fr\dm-use_secured_kafka_studio.ditamap
Failed to compile XPath expression in <value-of>
: '$test' (javax.xml.xpath.XPathExpressionException: net.sf.saxon.trans.XPathExc
eption: Variable is used in XPath expression, but no JAXP VariableResolver is av
ailable)

Expected from your previous post if I understand correctly?

If I <xsl value-of select="$test"/>, I get a blank value:

[schematron] 1 Schematron error for XML file 'C:\git\documentation-dita\developm
ent\configuration\fr\dm-use_secured_kafka_studio.ditamap'
[schematron]   [error] in /map/title @ C:\git\documentation-dita\development\con
figuration\fr\dm-use_secured_kafka_studio.ditamap This rule will always fire, de
monstrating how XSLT instructions seem to be executed without problems in Schema
tron. For example, the named template "get.test" will execute the function "loca
l:get.test()" which will retrieve the value of the variable $test, namely: ''
phax commented 7 years ago

Well the pure implementation has a method setVariableResolver where you can provide an javax.xml.xpath.XPathVariableResolver - a map based implementation of this is available at com.helger.xml.xpath.MapBasedXPathVariableResolver

For the XSLT based version you can use setParameters and directly pass in a Map<String,?> which will be used to resolve custom parameters/values. A test is available for #8 - hth

fviolette commented 6 years ago

Thanks for your help, I am validating through ANT so the integration process sounds convoluted for me given my lack of focus on this lately. Can you briefly describe the steps which would be required to achieve this, sticking with ANT?

By the way, I have been able to:

Given the following DITA XML file...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
<map id="module-product" xml:lang="en">
 <title>Module in product</title>
 <topicmeta>
  <author>
    <data conref="../../../../reuse/metadata_Authors.dita#topic/fviolette"/>
  </author>
  <category>
   <data conref="../../../../reuse/metadata_Tasks.dita#topic/128"/>
  </category>
  <prodinfo>
   <prodname>
    <data conref="../../../../reuse/metadata_Products.dita#topic/13"/>
   </prodname>
   <vrmlist>
    <vrm version="-dita-use-conref-target"
     conref="../../../../reuse/metadata_Versions.dita#topic/core"/>
   </vrmlist>
   <platform>
      <data conref="../../../../reuse/metadata_Modules.dita#topic/184"/>
   </platform>
   <platform>
    <data conref="../../../../reuse/metadata_Modules.dita#topic/194"/>
   </platform>
  </prodinfo>
  <othermeta name="hub" content="isHub"/>
  </topicmeta>
  <mapref href="../../../../common/taxonomy/subjectscheme.ditamap"/>
</map>

...RDF fragments...

<rdf:Description rdf:about="https://company.foobar.org/coretaxonomy/184">
    <contributor xmlns="http://purl.org/dc/terms/" rdf:resource="https://company.foobar.org/user/joe"/>
    <created xmlns="http://purl.org/dc/terms/" rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2016-11-07T11:13:24Z</created>
    <creator xmlns="http://purl.org/dc/terms/" rdf:resource="https://company.foobar.org/user/jane"/>
    <modified xmlns="http://purl.org/dc/terms/" rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2017-11-27T16:50:18Z</modified>
    <inScheme xmlns="http://schema.semantic-web.at/ppt/" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
    <rdf:type rdf:resource="https://company.foobar.org/ontology/Module"/>
    <altLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="en">FOOBARBAZ</altLabel>
    <inScheme xmlns="http://www.w3.org/2004/02/skos/core#" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="en">FOO BAR BAZ EN</prefLabel>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="fr">FOO BAR BAZ FR</prefLabel>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="ja">FOO BAR BAZ JA</prefLabel>
    <topConceptOf xmlns="http://www.w3.org/2004/02/skos/core#" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <inProduct xmlns="https://othercompany.foobar.org/ontology/" rdf:resource="https://company.foobar.org/coretaxonomy/13"/>
</rdf:Description>

<rdf:Description rdf:about="https://company.foobar.org/coretaxonomy/194">
    <contributor xmlns="http://purl.org/dc/terms/" rdf:resource="https://company.foobar.org/user/joe"/>
    <created xmlns="http://purl.org/dc/terms/" rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2016-11-18T15:35:51Z</created>
    <creator xmlns="http://purl.org/dc/terms/" rdf:resource="https://company.foobar.org/user/jane"/>
    <modified xmlns="http://purl.org/dc/terms/" rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2017-03-06T11:09:43Z</modified>
    <inScheme xmlns="http://schema.semantic-web.at/ppt/" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
    <rdf:type rdf:resource="https://company.foobar.org/ontology/Module"/>
    <inScheme xmlns="http://www.w3.org/2004/02/skos/core#" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="en">AZE QSD WXC EN</prefLabel>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="fr">AZE QSD WXC FR</prefLabel>
    <prefLabel xmlns="http://www.w3.org/2004/02/skos/core#" xml:lang="ja">AZE QSD WXC JA</prefLabel>
    <topConceptOf xmlns="http://www.w3.org/2004/02/skos/core#" rdf:resource="https://company.foobar.org/coretaxonomy/1"/>
    <inProduct xmlns="https://othercompany.foobar.org/ontology/" rdf:resource="https://company.foobar.org/coretaxonomy/205"/>
</rdf:Description>

...and pattern:

<sch:ns prefix="ontl" uri="https://othercompany.foobar.org/ontology/"/>

<sch:pattern id="is-module-inProduct">
        <sch:rule context="prodinfo/platform[count(data/@conref) = 1 and count(../prodname/data/@conref) = 1]">
            <sch:let name="taxonomy" value="doc('../../common/taxonomy/pp_project_coretaxonomy_concepts.rdf')"/>
            <sch:let name="taxonomy-ns" value="'https://company.foobar.org/coretaxonomy/'"/>
            <sch:let name="module" value="tokenize(data/@conref, '/')[last()]"/>
            <sch:let name="product" value="tokenize(../prodname/data/@conref, '/')[last()]"/>
            <sch:assert test="
                $taxonomy//rdf:Description[@rdf:about = concat($taxonomy-ns, $module)
                and
                ontl:inProduct/@rdf:resource = concat($taxonomy-ns, $product)]"
                role="warning">
                Tagging is inconsistent.
            </sch:assert>
        </sch:rule>
    </sch:pattern>

With the sch engine and in-editor validation, I get 1 shout for using:

<platform>
    <data conref="../../../../reuse/metadata_Modules.dita#topic/184"/>
</platform>
<platform>
    <data conref="../../../../reuse/metadata_Modules.dita#topic/194"/>
</platform>

But in pure mode I get 2 shouts but 184 is valid there. The number goes up with as many platform/data elements which are added.

At this point in time and as I am waiting for your answer on my very first question, my base option is to use the sch engine – hopefully the base-uri() can be fixed. But still very much up for pure too :-)

Thanks a lot!

fviolette commented 6 years ago

Bumping just in case my edit wasn't seen - thanks!

phax commented 6 years ago

Unfortunately I currently don't have too much time for ph-schematron :(

phax commented 6 years ago

Hi. Basically the pure version cannot be used as soon as XSLT is needed. Instead use the sch version only. To pass in variables, we're again with issue #62 - right?

fviolette commented 6 years ago

Yes 👍 I'll catch up on this.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

phax commented 5 years ago

@fviolette Even though it was a long time ago - do you know if I can close this one?

fviolette commented 5 years ago

Yes, no problem.