Search code examples
xsltxpathschematron

SchemaTron Date Comparison


<ROOTNODE>
   <Blocks>
     <Block>
    <Ref/>
      <BlockDates Start="2015-10-20" End="2015-10-25" />
      <Types>
        <Type TypeCode="SGL">
         <TypeAllocations>
        <TypeAllocation Start="2015-10-26" End="2015-10-27" />
        <TypeAllocation Start="2015-10-26" End="2015-10-25" />
      </TypeAllocations>
       </Type>
         <Type TypeCode="SGL">
         <TypeAllocations>
        <TypeAllocation Start="2015-10-28" End="2015-10-29" />
        <TypeAllocation Start="2015-10-26" End="2015-10-27" />
      </TypeAllocations>
       </Type>
      </Types>
    </Block>

    <Block>
      <Ref/>
      <BlockDates Start="2015-10-26" End="2015-10-30"/>
       <Types>
        <Type TypeCode="SG">
         <TypeAllocations>
        <TypeAllocation Start="2015-10-31" End="2015-11-01" />
        <TypeAllocation Start="2015-10-25" End="2015-10-24" />
      </TypeAllocations>
       </Type>
         <Type TypeCode="SG">
         <TypeAllocations>
        <TypeAllocation Start="2015-10-21" End="2015-10-25" />
        <TypeAllocation Start="2015-10-23" End="2015-11-27" />
      </TypeAllocations>
       </Type>
      </Types>
    </Block>
   </Blocks>
   </ROOTNODE>

I'm trying to find a way to tell if the <TypeAllocation @Start and @End> dates are outside the <BlockDates @Start and @End> dates. There can be any number of <TypeAllocation> elements and <Type> elements. The above should fail in all cases. Below is what I tried. However I feel that its way off as it only finds the first one. Any help is greatly appreciated!

   <sch:pattern name="Testing Start and End dates">
                                                                                <sch:rule context="blk:InvBlock">
                                                                                    <sch:report test="translate(blk:InvBlockDates/@Start, '-', '') &lt;= translate(blk:RoomTypes/blk:RoomType/blk:RoomTypeAllocations/blk:RoomTypeAllocation/@Start, '-', '') or translate(blk:InvBlockDates/@End, '-', '') &lt;= translate(blk:RoomTypes/blk:RoomType/blk:RoomTypeAllocations/blk:RoomTypeAllocation/@End, '-', '')"> Allocation @Start and @End dates can not be outside the Block @Start and @End dates. </sch:report>
                                                                                </sch:rule>
                                                                            </sch:pattern> 

Solution

  • I am not sure whether you want to report an validation error if there is at least one TypeAllocation with the wrong Start or End or if you want to check all of them. If you only want to check that at least one of them is wrong then you can use

    <sch:pattern>
        <sch:rule context="Block">
            <sch:report test="Types/Type/TypeAllocations/TypeAllocation[
                                translate(@Start, '-', '') > translate(current()/BlockDates/@Start, '-', '')
                                or
                                translate(@End, '-', '') > translate(current()/BlockDates/@End, '-', '')]"> Allocation @Start and @End dates can not be outside the Block @Start and @End dates. </sch:report>
        </sch:rule>
    </sch:pattern> 
    

    I think. If your version of Schematron does not support the use of the current() function then in the context of your example respectively my suggestion you can use ancestor::Block instead of current():

    <sch:pattern>
        <sch:rule context="Block">
            <sch:report test="Types/Type/TypeAllocations/TypeAllocation[
                                translate(@Start, '-', '') > translate(ancestor::Block/BlockDates/@Start, '-', '')
                                or
                                translate(@End, '-', '') > translate(ancestor::Block/BlockDates/@End, '-', '')]"> Allocation @Start and @End dates can not be outside the Block @Start and @End dates. </sch:report>
        </sch:rule>
    </sch:pattern>