user2093335
user2093335

Reputation: 219

Schematron: Test that a string matches an ID from a list of available IDs

I have an XML file that contains a list of possible question answers as well as the correct answer. I want to use schematron to verify that the correct answer value (a string) exists in the list of possible answer IDs.

I'm comparing the string value to the list IDs, but am coming up short.

XML:

<question>
    <div class="answer" id="i149">
        <div class="choice" id="i152">
            <div class="list" id="i154">
                <ol>
                    <li id="i155">Red</li>
                    <li id="i156">Blue</li>
                    <li id="i157">Green</li>
                    <li id="i158">Yellow</li>
                </ol>
            </div>
        </div>
    </div>
    <div class="response-processing" id="i159">
        <div class="condition" id="i161">
            <div class="correct" id="i162">
                <div class="response" id="i163">
                    <p>
                        <a class="answer-ref" href="#i152" id="i164">i1555</a>
                    </p>
                    <p>
                        <a class="answer-ref" href="#i152" id="i165">i156</a>
                    </p>
                    <p>
                        <a class="answer-ref" href="#i152" id="i166">i157</a>
                    </p>
                </div>
            </div>
        </div>
    </div>
</question>

Schematron rule:

<pattern id="answerIDnotLocal">
        <let name="answer" value="ancestor::question/div[@class='answer']/div[@class='choice']/div[@class='list']/ol//li/@id"/>
        <rule context="a[@class='answer-ref']">
            <assert test=". = $answer">This <value-of select="."/> doesn't match an available answer id.</assert>
        </rule>
    </pattern>

However, all 3 <a class="answer-ref">s trigger the error when only the first one should (with value i1555 - actual value should be i155).

Upvotes: 0

Views: 690

Answers (2)

user2093335
user2093335

Reputation: 219

I figured out the answer. Need to use quantified expressions:

<pattern id="answerIDnotLocal">
        <rule context="question">
            <let name="answer" value="div[@class='response-processing']/div[@class = 'condition']/div[@class = 'correct']"/>
            <let name="choice" value="div[@class = 'answer']//div[@class = 'list']//li/@id"/>
            <assert test="every $a in $answer satisfies $a = $choice">This question doesn't match an available answer id.</assert>
        </rule>
</pattern>

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167516

I think you need to move the let inside the rule to have the right context for the let:

<pattern id="answerIDnotLocal">
        <rule context="a[@class='answer-ref']">
            <let name="answer" value="ancestor::question/div[@class='answer']/div[@class='choice']/div[@class='list']/ol//li/@id"/>
            <assert test=". = $answer">This <value-of select="."/> doesn't match an available answer id.</assert>
        </rule>
</pattern>

Upvotes: 0

Related Questions