Sorting and Looping within Schematron-Rule

This should cover W3C XML Schema, Relax NG and DTD related problems.
Thomas W
Posts: 2
Joined: Mon Mar 05, 2018 2:02 pm

Sorting and Looping within Schematron-Rule

Post by Thomas W »

Hello Oxygen Team

I have the following XML structure and I need to validate it with Schematron so that the time periods do not overlap:

Code: Select all

<periods>
<period start='2018-02-01' end '2018-02-14' />
<period start='2018-01-01' end '2018-01-22' />
<period start='2018-04-01' end '2018-04-25' />
<period start='2018-03-01' end '2018-01-22' />
<period start='2018-04-24' end '2018-04-28' />
</periods>
So what actually needs to be done is to sort the list descending by start date, loop through the sorted list and check in every iteration whether the end date of the current period is smaller than the start date of the period from the previous iteration. That said, in the second iteration of such a loop the validation logic would check if '2018-04-25' < '2018-04-24' which is false. Thus, we could set a variable "HasOverlappings" to true in this case which is then invoked after the loop within a schematron rule check.

Any idea if this can be done in Schematron and if yes how?

Thank you very much.
Best
Thomas
tavy
Posts: 365
Joined: Thu Jul 01, 2004 12:29 pm

Re: Sorting and Looping within Schematron-Rule

Post by tavy »

Hello Thomas,

A solution for this is to use XSLT functions in the Schematron file. Something like the function below:

Code: Select all


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

<sch:ns prefix="fct" uri="localFunctions"/>

<sch:pattern>
<sch:rule context="periods">
<sch:let name="overlapping" value="fct:checkOverlaping((),period)"/>
<sch:assert test="$overlapping=''">
Overlapping period: <sch:value-of select="$overlapping"/></sch:assert>
</sch:rule>
</sch:pattern>

<xsl:function name="fct:checkOverlaping" >
<xsl:param name="currentEndDate" as="xs:date?"/>
<xsl:param name="periods" as="node()*"/>
<xsl:choose>
<xsl:when test="not(exists($currentEndDate))">
<xsl:variable name="orderedPeriods" as="node()*">
<xsl:for-each select="$periods">
<xsl:sort select="@start"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="fct:checkOverlaping(xs:date($orderedPeriods[position()=1]/@end),$orderedPeriods[position()>1])"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="
if (not(exists($periods))) then '' else
if ($currentEndDate > $periods[position()=1]/@start)
then concat('End: ', $currentEndDate, ' Start: ', $periods[position()=1]/@start) else
fct:checkOverlaping($periods[position()=1]/@end,$periods[position()>1])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</sch:schema>
Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com
Thomas W
Posts: 2
Joined: Mon Mar 05, 2018 2:02 pm

Re: Sorting and Looping within Schematron-Rule

Post by Thomas W »

Hi Octavian

That looks cool. Thank you very much. I will try this.

All the best
Thomas
Post Reply