ISO Schematron - инструмент для вашей проблемы.Просто используйте реализацию для XPath 2.0, которая позволяет вводить данные.Тогда вам нужно только проверить утверждение.Что-то вроде <assert test="@from < @to"/>
См .: http://www.schematron.com/implementation.html
Относительно перекрытия: вы можете кодировать функцию XSLT, которая возвращает логическое значение в схеме схемы, и вызывать ее из вашего атрибута теста.
Schematron со встроенной функцией XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fct="localFunctions" queryBinding="xslt2"
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<ns prefix="fct" uri="localFunctions"/>
<pattern>
<rule context="intervals">
<assert test="fct:checkOverlaping((),range)" >OVERLAPING</assert>
</rule>
</pattern>
<xsl:function name="fct:checkOverlaping" as="xs:boolean">
<xsl:param name="currentEndDate" as="xs:dateTime?"/>
<xsl:param name="ranges" as="node()*"/>
<xsl:choose>
<xsl:when test="not(exists($currentEndDate))">
<xsl:variable name="orderedRanges" as="node()*">
<xsl:for-each select="$ranges">
<xsl:sort select="@from"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="fct:checkOverlaping(xs:dateTime($orderedRanges[position()=1]/@to),$orderedRanges[position()>1])"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="
if (not(exists($ranges))) then true() else
if ($currentEndDate > $ranges[position()=1]/@from) then false() else
fct:checkOverlaping($ranges[position()=1]/@to,$ranges[position()>1])
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</schema>
Используйте следующую реализацию: http://www.schematron.com/tmp/iso-schematron-xslt2.zip, которая реализует allow-foreign
и использует XPath 2.0.Когда для этого параметра allow-foreign
установлено значение true, реализация будет встраивать указанную выше функцию.
Как работает функция: первый цикл (currentEndDate не задан), элементы range
отсортированы по дате from
.Другой рекурсивный цикл (после сортировки): проверить, находится ли дата to
первого диапазона перед датой начала второй даты, и перейти к следующей, если она истинна (в противном случае - ложь и остановка).