Closed oliverunger closed 3 months ago
Is this the right way to check validation at runtime against the transpiled xslt?
final File preCompiledXSLT = ResourceUtils.getFile("classpath:arche.xslt");
ISchematronXSLTBasedResource xslt = SchematronResourceSchXslt_XSLT2.fromFile(preCompiledXSLT);
if(!xslt.isValidSchematron()) {
throw new IllegalArgumentException("Das XSLT-Dokument ist nicht gültig!");
}
// XML-Dokument laden
final Document aXML = DOMReader.readXMLDOM(xml);
if (aXML == null) {
throw new IllegalArgumentException("Das XML-Dokument ist nicht gültig!");
}
// Validierung durchführen
// final SchematronOutputType schematronOutputType = aResSCH.applySchematronValidationToSVRL(new DOMSource(aXML));
final SchematronOutputType schematronOutputType = xslt.applySchematronValidationToSVRL(new DOMSource(aXML));
if (schematronOutputType == null) {
throw new IllegalArgumentException("Fehler bei der Anwendung der Schematron-Validierung!");
}
return schematronOutputType;
So the created XSLT is totally fine. The code snippet you are highlighting is about getting the name of an element. And that makes a difference, if the namespace URI is the default one (empty string) or not:
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
And yes, the code looks good. Even though I suggest instead of wrapping it in a DOMSource
try this:
final SchematronOutputType schematronOutputType = xslt.applySchematronValidationToSVRL(aXML, (String) null);
if (schematronOutputType == null) {
throw new IllegalArgumentException("Fehler bei der Anwendung der Schematron-Validierung!");
}
the 2nd base URI parameter is relevant when you have includes to resolve etc.
Still have this issue: 17:44:38.756 [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener -- [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: Es wurde versucht, einen Knoten an einer Stelle einzufügen, an der dies nicht zulässig ist.) 17:44:38.760 [main] ERROR com.helger.schematron.schxslt.xslt2.SchematronProviderXSLTFromSchXslt_XSLT2 -- SchXslt preprocessor error net.sf.saxon.trans.XPathException: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: Es wurde versucht, einen Knoten an einer Stelle einzufügen, an der dies nicht zulässig ist.
Translation from german: It was tried to add an element at an invalid position.
Appears in this line: final SchematronOutputType schematronOutputType = xslt.applySchematronValidationToSVRL(aXML, null);
I speak German so all good :) Can you paste an example XML here as well please?
Just so that the others can understand.
This should be a valid one:
<?xml version="1.0" encoding="UTF-8"?>
<arche xmlns="http://www.schematron.info/arche"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.schematron.info/arche arche.xsd">
<ladung>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="nein">
<art>Zebra</art>
<gewicht>200</gewicht>
<alter>12</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="nein">
<art>Zebra</art>
<gewicht>250</gewicht>
<alter>13</alter>
</tier>
</zimmer>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="ja">
<art>Löwe</art>
<gewicht>200</gewicht>
<alter>14</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="ja">
<art>Löwe</art>
<gewicht>180</gewicht>
<alter>30</alter>
</tier>
</zimmer>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="nein">
<art>Elefant</art>
<gewicht>10000</gewicht>
<alter>20</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="nein">
<art>Elefant</art>
<gewicht>15000</gewicht>
<alter>40</alter>
</tier>
</zimmer>
</ladung>
<maxReproduktionsalter>
<tier_art>
<name>Elefant</name>
<männlich>80</männlich>
<weiblich>30</weiblich>
</tier_art>
<tier_art>
<name>Löwe</name>
<männlich>30</männlich>
<weiblich>15</weiblich>
</tier_art>
<tier_art>
<name>Zebra</name>
<männlich>30</männlich>
<weiblich>20</weiblich>
</tier_art>
</maxReproduktionsalter>
<nutzlast>44000</nutzlast>
</arche>
This one should violate rule 1:
<?xml version="1.0" encoding="UTF-8"?>
<arche xmlns="http://www.schematron.info/arche"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.schematron.info/arche arche.xsd">
<ladung>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="nein">
<art>Zebra</art>
<gewicht>200</gewicht>
<alter>21</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="nein">
<art>Zebra</art>
<gewicht>250</gewicht>
<alter>13</alter>
</tier>
</zimmer>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="ja">
<art>Löwe</art>
<gewicht>200</gewicht>
<alter>14</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="ja">
<art>Löwe</art>
<gewicht>180</gewicht>
<alter>30</alter>
</tier>
</zimmer>
<zimmer>
<tier geschlecht="weiblich" fleischfresser="nein">
<art>Elefant</art>
<gewicht>10000</gewicht>
<alter>20</alter>
</tier>
<tier geschlecht="männlich" fleischfresser="nein">
<art>Elefant</art>
<gewicht>15000</gewicht>
<alter>40</alter>
</tier>
</zimmer>
</ladung>
<maxReproduktionsalter>
<tier_art>
<name>Elefant</name>
<männlich>80</männlich>
<weiblich>30</weiblich>
</tier_art>
<tier_art>
<name>Löwe</name>
<männlich>30</männlich>
<weiblich>15</weiblich>
</tier_art>
<tier_art>
<name>Zebra</name>
<männlich>30</männlich>
<weiblich>20</weiblich>
</tier_art>
</maxReproduktionsalter>
<nutzlast>44000</nutzlast>
</arche>
This very simple one does not work either:
SCH:
<?xml version="1.0" encoding="utf-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron"
queryBinding="xslt2">
<pattern>
<rule context="ID">
<assert test="string-length(.) > 9">Something with chars.</assert>
</rule>
</pattern>
</schema>
Transpiled:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:saxon="http://saxon.sf.net/" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<!--Implementers: please note that overriding process-prolog or process-root is
the preferred method for meta-stylesheets to use where possible. -->
<xsl:param name="archiveDirParameter" />
<xsl:param name="archiveNameParameter" />
<xsl:param name="fileNameParameter" />
<xsl:param name="fileDirParameter" />
<xsl:variable name="document-uri">
<xsl:value-of select="document-uri(/)" />
</xsl:variable>
<!--PHASES-->
<!--PROLOG-->
<xsl:output indent="yes" method="xml" omit-xml-declaration="no" standalone="yes" />
<!--XSD TYPES FOR XSLT2-->
<!--KEYS AND FUNCTIONS-->
<!--DEFAULT RULES-->
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-select-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="." />
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-get-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="preceding" select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])" />
<xsl:text>[</xsl:text>
<xsl:value-of select="1+ $preceding" />
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="@*" mode="schematron-get-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>@*[local-name()='</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-2-->
<!--This mode can be used to generate prefixed XPath for humans-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-2">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-3-->
<!--This mode can be used to generate prefixed XPath for humans
(Top-level element has index)-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-3">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="parent::*">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: GENERATE-ID-FROM-PATH -->
<xsl:template match="/" mode="generate-id-from-path" />
<xsl:template match="text()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')" />
</xsl:template>
<xsl:template match="comment()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')" />
</xsl:template>
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.@', name())" />
</xsl:template>
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:text>.</xsl:text>
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')" />
</xsl:template>
<!--MODE: GENERATE-ID-2 -->
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
<xsl:template match="*" mode="generate-id-2" priority="2">
<xsl:text>U</xsl:text>
<xsl:number count="*" level="multiple" />
</xsl:template>
<xsl:template match="node()" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number count="*" level="multiple" />
<xsl:text>n</xsl:text>
<xsl:number count="node()" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number count="*" level="multiple" />
<xsl:text>_</xsl:text>
<xsl:value-of select="string-length(local-name(.))" />
<xsl:text>_</xsl:text>
<xsl:value-of select="translate(name(),':','.')" />
</xsl:template>
<!--Strip characters--> <xsl:template match="text()" priority="-1" />
<!--SCHEMA SETUP-->
<xsl:template match="/">
<svrl:schematron-output schemaVersion="" title="">
<xsl:comment>
<xsl:value-of select="$archiveDirParameter" />
<xsl:value-of select="$archiveNameParameter" />
<xsl:value-of select="$fileNameParameter" />
<xsl:value-of select="$fileDirParameter" />
</xsl:comment>
<svrl:active-pattern>
<xsl:attribute name="document">
<xsl:value-of select="document-uri(/)" />
</xsl:attribute>
<xsl:apply-templates />
</svrl:active-pattern>
<xsl:apply-templates mode="M0" select="/" />
</svrl:schematron-output>
</xsl:template>
<!--SCHEMATRON PATTERNS-->
<!--PATTERN -->
<!--RULE -->
<xsl:template match="ID" mode="M0" priority="1000">
<svrl:fired-rule context="ID" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="string-length(.) > 9" />
<xsl:otherwise>
<svrl:failed-assert test="string-length(.) > 9">
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>Something with chars.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M0" select="*|comment()|processing-instruction()" />
</xsl:template>
<xsl:template match="text()" mode="M0" priority="-1" />
<xsl:template match="@*|node()" mode="M0" priority="-2">
<xsl:apply-templates mode="M0" select="*|comment()|processing-instruction()" />
</xsl:template>
</xsl:stylesheet>
XML:
<?xml version="1.0" encoding="UTF-8"?>
<test>Test</test>
Error: 08:19:23.865 [main] ERROR com.helger.xml.transform.LoggingTransformErrorListener -- [fatal_error] Transformation fatal error (net.sf.saxon.trans.XPathException: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: Es wurde versucht, einen Knoten an einer Stelle einzufügen, an der dies nicht zulässig ist.) 08:19:23.869 [main] ERROR com.helger.schematron.schxslt.xslt2.SchematronProviderXSLTFromSchXslt_XSLT2 -- SchXslt preprocessor error net.sf.saxon.trans.XPathException: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: Es wurde versucht, einen Knoten an einer Stelle einzufügen, an der dies nicht zulässig ist. 08:19:23.876 [main] WARN com.helger.schematron.schxslt.xslt2.SchematronResourceSchXslt_XSLT2Cache -- The Schematron resource 'file:/C:/.../arche.xslt' is invalid! 08:19:23.876 [main] WARN com.helger.schematron.api.xslt.AbstractSchematronXSLTBasedResource -- Cannot apply the Schematron validation, due to errors in the Schematron rules
Sorry, it took me some time to figure this one out.
As you previously converted the SCH to XSLT, then you must use SchematronResourceXSLT
(from the ph-schematron-xslt
module).
SchXslt can only be used when you do "SCH -> XSLT -> SVRL" in one go.
The Maven plugin always uses the "ISO Schematron" conversion. Even if you convert with SchXslt from SCH to XSLT, you need "ph-schematron-xslt" to apply the XSLT.
Hope that makes sense
Im still confused by this. I wanted to use Schxslt because Iso Schematron requires some license, right? But I want to precompile my Schematron files using the maven plugin at build time for better performance at runtime. But theres no way to go to have both right?
No it doesn't require a fee. You are mixing things up:
So no fee included in any of this.
Ok then I go with ISO schematron to be able to use the plugin. Thank you for your investigation, quick responses and explanation!
Plugin:
arche.sch
XSLT