phax / ph-schematron

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

Abstract patterns support (needs Schematron rewriting?) #48

Closed fviolette closed 7 years ago

fviolette commented 7 years ago

Hello,

A couple of issues with abstract patterns and schematronProcessingEngine="schematron".

The lib is working for me but I currently have many patterns and rules written in the way detailed below.

Versions tested:

Example from the ISO Schematron spec repurposed a bit.

schematron.sch

<?xml version="1.0" encoding="utf-8"?>
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron"
  xmlns:sqf="http://www.schematron-quickfix.com/validator/process"
  queryBinding="xslt2">

  <sch:pattern abstract="true" id="requiredAttribute">
    <sch:title>Required Attributes</sch:title>
    <sch:rule context="$context">
      <sch:assert test="string-length($attribute) &gt; 0">
        The <sch:name/> element should have a
       <sch:value-of select="$attribute/name()"/> attribute.
      </sch:assert>
    </sch:rule>
  </sch:pattern>
  <sch:pattern is-a="requiredAttribute">
    <sch:param name="context" value="Customer"/>
    <sch:param name="attribute" value="@type"/>
  </sch:pattern>
</sch:schema> 

topic.xml

<?xml version="1.0" encoding="utf-8"?>
<file>
  <Customer type="abc">
    <firstname>abc</firstname>
  </Customer>
  <Customer>
    <firstname>def</firstname>
  </Customer>
</file>

Log


check.topic:
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XSLT Pattern syntax error at char 0 on line -1 in {$context}:
[schematron]     Unexpected token in pattern, found "$")
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XPath syntax error at char 24 on line -1 in {string-length($attribute) >}:
[schematron]     Variable $attribute has not been declared)
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XPath syntax error at char 10 on line -1 in {$attribute/name}:
[schematron]     Variable $attribute has not been declared)
[schematron] [main] ERROR com.helger.xml.transform.XMLTransformerFactory - Failed to parse javax.xml.transform.dom.DOMSource@3c73951
[schematron] javax.xml.transform.TransformerConfigurationException: Failed to compile stylesheet. 3 errors detected.
[schematron]    at net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:176)
[schematron]    at net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:139)
[schematron]    at com.helger.xml.transform.XMLTransformerFactory.newTemplates(XMLTransformerFactory.java:263)
[schematron]    at com.helger.schematron.xslt.SchematronProviderXSLTFromSCH.<init>(SchematronProviderXSLTFromSCH.java:220)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCHCache.createSchematronXSLTProvider(SchematronResourceSCHCache.java:69)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCHCache.getSchematronXSLTProvider(SchematronResourceSCHCache.java:145)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCH.getXSLTProvider(SchematronResourceSCH.java:92)
[schematron]    at com.helger.schematron.xslt.AbstractSchematronXSLTBasedResource.isValidSchematron(AbstractSchematronXSLTBasedResource.java:187)
[schematron]    at com.helger.schematron.ant.Schematron.execute(Schematron.java:431)
[schematron]    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
[schematron]    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[schematron]    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[schematron]    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[schematron]    at java.lang.reflect.Method.invoke(Method.java:498)
[schematron]    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[schematron]    at org.apache.tools.ant.Task.perform(Task.java:348)
[schematron]    at org.apache.tools.ant.Target.execute(Target.java:435)
[schematron]    at org.apache.tools.ant.Target.performTasks(Target.java:456)
[schematron]    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393)
[schematron]    at org.apache.tools.ant.Project.executeTarget(Project.java:1364)
[schematron]    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[schematron]    at org.apache.tools.ant.Project.executeTargets(Project.java:1248)
[schematron]    at org.apache.tools.ant.Main.runBuild(Main.java:851)
[schematron]    at org.apache.tools.ant.Main.startAnt(Main.java:235)
[schematron]    at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
[schematron]    at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
[schematron] [main] WARN com.helger.schematron.xslt.SchematronResourceSCHCache - The Schematron resource 'C:\git\documentation-dita\build\validate\test\schematron.sch' is invalid!
[schematron] Successfully parsed Schematron file 'C:\git\documentation-dita\build\validate\test\schematron.sch'
[schematron] Validating XML file 'C:\git\documentation-dita\build\validate\test\fr\test.xml' against Schematron rules from 'schematron.sch' expecting success
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XSLT Pattern syntax error at char 0 on line -1 in {$context}:
[schematron]     Unexpected token in pattern, found "$")
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XPath syntax error at char 24 on line -1 in {string-length($attribute) >}:
[schematron]     Variable $attribute has not been declared)
[schematron] [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener - [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: XPath syntax error at char 10 on line -1 in {$attribute/name}:
[schematron]     Variable $attribute has not been declared)
[schematron] [main] ERROR com.helger.xml.transform.XMLTransformerFactory - Failed to parse javax.xml.transform.dom.DOMSource@16a0ee18
[schematron] javax.xml.transform.TransformerConfigurationException: Failed to compile stylesheet. 3 errors detected.
[schematron]    at net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:176)
[schematron]    at net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:139)
[schematron]    at com.helger.xml.transform.XMLTransformerFactory.newTemplates(XMLTransformerFactory.java:263)
[schematron]    at com.helger.schematron.xslt.SchematronProviderXSLTFromSCH.<init>(SchematronProviderXSLTFromSCH.java:220)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCHCache.createSchematronXSLTProvider(SchematronResourceSCHCache.java:69)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCHCache.getSchematronXSLTProvider(SchematronResourceSCHCache.java:145)
[schematron]    at com.helger.schematron.xslt.SchematronResourceSCH.getXSLTProvider(SchematronResourceSCH.java:92)
[schematron]    at com.helger.schematron.xslt.AbstractSchematronXSLTBasedResource.isValidSchematron(AbstractSchematronXSLTBasedResource.java:187)
[schematron]    at com.helger.schematron.AbstractSchematronResource.applySchematronValidationToSVRL(AbstractSchematronResource.java:255)
[schematron]    at com.helger.schematron.ant.Schematron._performValidation(Schematron.java:314)
[schematron]    at com.helger.schematron.ant.Schematron.execute(Schematron.java:475)
[schematron]    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
[schematron]    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[schematron]    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[schematron]    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[schematron]    at java.lang.reflect.Method.invoke(Method.java:498)
[schematron]    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[schematron]    at org.apache.tools.ant.Task.perform(Task.java:348)
[schematron]    at org.apache.tools.ant.Target.execute(Target.java:435)
[schematron]    at org.apache.tools.ant.Target.performTasks(Target.java:456)
[schematron]    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393)
[schematron]    at org.apache.tools.ant.Project.executeTarget(Project.java:1364)
[schematron]    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[schematron]    at org.apache.tools.ant.Project.executeTargets(Project.java:1248)
[schematron]    at org.apache.tools.ant.Main.runBuild(Main.java:851)
[schematron]    at org.apache.tools.ant.Main.startAnt(Main.java:235)
[schematron]    at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
[schematron]    at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
[schematron] [main] WARN com.helger.schematron.xslt.SchematronResourceSCHCache - The Schematron resource 'C:\git\documentation-dita\build\validate\test\schematron.sch' is invalid!
phax commented 7 years ago

When using pure mode, this is correctly handled. When the XSLT based version is used, it basically hangs with the error message "A variable reference is not allowed in an XSLT pattern".

I think this is related to https://github.com/Schematron/schematron/issues/6 - right?

phax commented 7 years ago

As a workaround, I could suggest to first manually pre-process the pattern with the "pure" component.

This leads to the following Schematron:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
  <pattern id="requiredAttribute">
    <rule context="Customer">
      <assert test="string-length(@type) > 0">
        The <name /> element should have a
       <value-of select="@type/name()" /> attribute.
      </assert>
    </rule>
  </pattern>
</schema>

and when applied with XSLT the output is:

<?xml version="1.0" encoding="UTF-8"?>
<schematron-output xmlns="http://purl.oclc.org/dsdl/svrl" title="" schemaVersion="">
  <active-pattern id="requiredAttribute" name="requiredAttribute" document=""></active-pattern>
  <fired-rule context="Customer"></fired-rule>
  <fired-rule context="Customer"></fired-rule>
  <failed-assert location="/file[1]/Customer[2]" test="string-length(@type) > 0">
    <text>
        The Customer element should have a
        attribute.
      </text>
  </failed-assert>
</schematron-output>
fviolette commented 7 years ago

Duly noted.

phax commented 7 years ago

As you are working with ANT I suggest I add a new "SchematronPreprocess" task that takes a file and writes a file? Or is this stupid?

fviolette commented 7 years ago

It's not. I am still struggling with some of my content though so maybe some other +1 would be useful. If you feel like going ahead, I am not going to say no :-)

phax commented 7 years ago

Here you go - any feedback is welcome :)

fviolette commented 7 years ago

First attempt with above samples:

BUILD FAILED
    C:\test\validate.xml:58: com.helger.schematron.
    pure.exchange.SchematronReadException: C:\test\
    topic.sch: Failed to resolve includes in resource [file=C:\test\topic.sch]
    at com.helger.schematron.pure.exchange.PSReader.readSchema(PSReader.java
    :1196)
    at com.helger.schematron.ant.SchematronPreprocess.execute(SchematronPrep
    rocess.java:142)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:62)
phax commented 7 years ago

Can you elaborate on the inckude please. I cant find it in above samples. Thx

fviolette commented 7 years ago

Me neither :-| Update: Case closed, the issue is fixed on my side.

I pointed to a file which didn't exist - plain and simple. So, maybe we can make the log clearer about that.

It does work and I can easily chain it to the previous build. Is there anything else you would like to test, precisely?

fviolette commented 7 years ago

On inspecting the preprocessed file, it tells me about the following error for <sqf:*> elements, which is normal I guess since the namespace declarations are gone:

cvc-complex-type.3.2.2: Attribute 'fix' is not allowed to appear in            element 'assert'.
--
cvc-complex-type.3.2.2: Attribute 'fix' is not allowed to appear in            element 'report'
--

In my case, I would not object to fix being removed from the preprocessed file.

Authors benefit from the live Schematron validation setup in the editor, and now with ph-schematron, we will run the validation on our full documentation set once in a while and possibly fully integrate this to our build pipeline with org.doctales.schematron after #50 and some more curation of the DITA content. So, except for the first case, fixes are not needed.

stefan-jung commented 7 years ago

I think <sqf:fix> must not be used in a <report> or <assert>. This is what the error message says or not?

<sch:pattern>
    <sch:rule>
        <sch:report test=""/>
        <!-- should go after <report>/<assert> -->
        <sqf:fix id=""/>
    </sch:rule>
</sch:pattern>
fviolette commented 7 years ago

Of course. I meant the @sqf:fix reference in the first line, which gets preprocessed. There is no error message as per ph-schematron but in the preprocessed file (so far that does not impair my progression with the testing but we could give it a thought).

This sample...

<sch:assert test="prodinfo/prodname" role="fatal" sqf:fix="insert-prodname">
    The prodname element is mandatory.
</sch:assert>
<sqf:fix id="insert-prodname" role="add">
    <sqf:description>
        <sqf:title>Insert missing prodname element</sqf:title>
    </sqf:description>
    <sqf:add node-type="element" match="prodinfo" target="prodname" position="first-child"/>
</sqf:fix>

...is preprocessed:

<assert test="prodinfo/prodname" role="fatal" fix="insert-prodname">
    The prodname element is mandatory.
</assert>

(Assert => error in the output preprocessed file: cvc-complex-type.3.2.2: Attribute 'fix' is not allowed to appear in element 'assert').

<ns0:fix xmlns:ns0="http://www.schematron-quickfix.com/validator/process" id="insert-prodname" role="add">
    <ns0:description>
        <ns0:title>Insert missing prodname element</ns0:title>
    </ns0:description>
    <ns0:add node-type="element" match="prodinfo" target="prodname" position="first-child" />
</ns0:fix>

(Fix => warning in the output preprocessed file: The ns0:fix element is not used by an assert or a report inside of this rule).

phax commented 7 years ago

The foreign elements are "optimized" away. I opened issue #51 for this.

In your case, did you add the <sch:ns ...> element to your Schematron?

fviolette commented 7 years ago

Yes, indeed.

phax commented 7 years ago

I assume this can be closed, as #51 is what is left. Any objections?

fviolette commented 7 years ago

None. Thanks again!