Search code examples
schematron

Schematron / preceding-sibling and following-sibling are the same element


Desperately trying to get Schematron to alert only if the EFFECT element resides between two SUBTASK elements - they are siblings to each other. Greatly appreciate any assistance and please let me know if more information is needed.

Here is some simple sample code:

<TOPIC>
 <SUBTASK></SUBTASK>
 <EFFECT></EFFECT>
 <SUBTASK></SUBTASK>
</TOPIC>

Here are two of my Schematron attempts - the problem is its alerting on every EFFECT within the document instead of just between the two SUBTASK. *note - EFFECT is a wildcard and allowed everywhere.

<rule context="EFFECT">
 <assert test="preceding-sibling::*[position()[1]][SUBTASK] = following-sibling::*[position()[1]][SUBTASK]" role="error" id="error_EFFECT_between_SUBTASK" 
   >EFFECT not allowed between two SUBTASKs</assert>
</rule>

<rule context="EFFECT">
 <assert test="count(preceding-sibling::*[position()>0]) and preceding-sibling::*[position()[1]][SUBTASK] = following-sibling::*[position()[1]][SUBTASK]" role="error" id="error_EFFECT_between_SUBTASKs" 
  >EFFECT not allowed between two SUBTASK</assert>
</rule>

Solution

  • You had most of the pieces, but lacked self:: for the 'self' axis. Try (untested):

    <rule context="EFFECT">
     <assert test="preceding-sibling::*[1][self::SUBTASK] and
                   following-sibling::*[1][self::SUBTASK]"
             role="error" id="error_EFFECT_between_SUBTASKs" 
      >EFFECT not allowed between two SUBTASK</assert>
    </rule>
    

    [SUBTASK] is true if there is a SUBTASK child, not if the context element is a SUBTASK.

    [position()[1]] would probably be an error is XPath 1.0, but in XPath 2.0 or XPath 3.0, it would be true every time because position() returns a non-zero number, and the [1] reduces the singe-item sequence of numbers to the first (and only) number in the sequence.