A J Qarshi
A J Qarshi

Reputation: 2992

Schematron - Element validation based on its position

I am using Schematron to do some business rule validations. My xml data looks like:

<labtests>  
    <test>
        <observation>
            <code code="TT900" name="NMCK"/>
            <outcome value="074042"/>
        </observation>            
    </test>

    <test>
        <observation>
            <code code="TT500" name="LVCT"/>
            <outcome value="852417"/>
        </observation>            
    </test>
    <test>
        <observation>
            <code code="TT500" name="LVCT"/>
            <outcome value="36542"/>
        </observation>            
    </test>
    <test>
        <observation>
            <code code="TT100" name="GVMC"/>
            <outcome value="874541"/>
        </observation>            
    </test>
    <test>
        <observation>
            <code code="TT500" name="LVCT"/>
            <outcome value="369521"/>
        </observation>            
    </test>
</labtests>

The current context is set to labtests/test/observation like below:

<iso:rule context="labtests/test/observation">
    <!--perform all validations here-->


</iso:rule>               

I want to perform some special business validation checks on the <outcome> node for the first <observation> block having code/@code="TT500".

I think I can use the following expression to get the position of first intended <observation> block

count(../../test/observation/code[@code="TT500"]/preceding-sibling::*)+1

but I don't know how to compare this position with the node in the current context to perform special validation.

UPDATE:

For the sake of simplicity let's assume that the special validation to be performed in this case is that the length of outcome/@value must be greater than or equal to 6. i.e.

<iso:report test="not(string-length(outcome/@value) >= 6">
    outcome/@value should have at least 6 characters for the first TT500 observation
</iso:report>

Upvotes: 1

Views: 651

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22647

The following Schematron document does exactly what you have asked. There is no real difference between assert and report, you can invert any rule to fit both.

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
    <pattern>
        <rule context="observation[code/@code = 'TT500' and not(preceding::observation[code/@code = 'TT500'])]">
            <assert test="string-length(outcome/@value) ge 6"> outcome/@value should have at least 6 characters for the first TT500 observation </assert>
        </rule>
    </pattern>
</schema>

When the following (invalid) XML document is validated with this SCH rule:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="sample.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<labtests>  
    <test>
        <observation>
            <code code="TT900" name="NMCK"/>
            <outcome value="07442"/>
        </observation>            
    </test>
    <test>
        <observation>
            <code code="TT500" name="LVCT"/>
            <outcome value="85417"/>
        </observation>            
    </test>
    <test>
        <observation>
            <code code="TT500" name="LVCT"/>
            <outcome value="36542"/>
        </observation>            
    </test>           
</labtests>

A Schematron processor will issue a warning along the lines of

E [ISO Schematron] outcome/@value should have at least 6 characters for the first TT500 observation

Upvotes: 2

Related Questions