Могу ли я использовать schematron для проверки того, что диапазоны дат не перекрываются в XML-файле?

Представьте, что у меня есть простой xml-файл:

<intervals>
  <range from="2001-12-17T09:30:47Z" to="2001-12-19T11:35:16Z" />
  <range from="2002-12-17T09:30:47Z" to="2002-12-19T11:35:16Z" />
<intervals>

Я хотел бы убедиться, что указанные диапазоны дат не пересекаются. Я могу сделать это в коде, очевидно, но в идеале я хотел бы предоставить пакет проверки для моей схемы xml для проверки некоторых бизнес-правил.

Могу ли я использовать схему, чтобы проверить, не перекрываются ли диапазоны?


person James Berry    schedule 23.11.2011    source источник


Ответы (1)


ISO Schematron - это инструмент для вашей проблемы. Просто используйте реализацию XPath 2.0, которая позволяет вводить данные. Тогда вам нужно только проверить утверждение. Что-то вроде <assert test="@from &lt; @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 первого диапазона до даты начала второй даты, и продолжите следующую, если она истинна (в противном случае - ложь и остановитесь).

person Vincent Biragnet    schedule 23.11.2011
comment
Это выглядит великолепно. Теперь мне нужно решить вопрос, как заставить его работать в .net, но это уже другая история ... - person James Berry; 28.11.2011
comment
Рассмотрите возможность использования saxon (sourceforge.net/projects/saxon/files/Saxon-HE/9.3/), он обеспечивает реализацию XSLT 2.0 .net. - person Vincent Biragnet; 28.11.2011