1
votes

I want to compare two XML files using Schematron. I have a template that looks as follows:

  <action name="thirdAction" id="3">      
<return-values>
  <return-value name="communication-profile-id" />
  <return-value name="messaging-profile-id" />
</return-values>

And when one creates an instance of the action it looks something like this:

  <instanceOfAction name="thirdAction" id="3">     
    <results>
     <result name="communication-profile-id" />
     <result name="messaging-profile-id" />
    </results>
 </instanceOfAction>

I want to map the instanceOfAction to the given action based on the id and then check if the child elements' names correspond. In my hierarchy I have a lot of actions which makes this more difficult. Does somebody have a suggestion for implementing this? I succeeded checking to see if the results in the instanceOfAction are in SOME defined action, but not specifically in the action with the same id, by doing the following:

   <sch:rule context="//ts:instanceOfAction/ts:results/ts:result">  
      <sch:assert test="$testspecification//(ts:actions/ts:action/ts:return-values/ts:return-value)[@name= current()/@key]">
        The keys from the results do not match with the names from the return-values.
      </sch:assert>
    </sch:rule>

where the variable $testspecification is the path to the root hierarchy, which contains all the XML files.

Any help or ideas would be appreciated. :)

1

1 Answers

1
votes

You can use an xPath predicate to find the matching action, like you did to find the matching return-value. You can use .. to go up a level (or use the ancestor:: axis).

<sch:rule context="//ts:instanceOfAction/ts:results/ts:result">  
  <sch:assert test="$testspecification//ts:actions/ts:action[@id= current()/../../@id]/ts:return-values/ts:return-value[@name= current()/@key]">
    The keys from the results do not match with the names from the return-values.
  </sch:assert>
</sch:rule>

The weakness of the rule as written above is that it will not catch cases where results is missing a result specified by the template. If I were writing the rule, I might approach it by setting the context to be ts:instanceOfAction, and then use asserts to verify that instanceOfAction contains everything specified by Action, like this:

<sch:rule context="ts:instanceOfAction">  
  <sch:assert test="every $returnValue in $testspecification//ts:actions/ts:action[@id= current()/@id]/ts:return-values/ts:return-value satisfies $returnValue/@name = current()/ts:results/ts:result/@name and
                    every $result in ts:results/ts:result satisfies $result/@name = $testspecification//ts:actions/ts:action[@id= current()/@id]/ts:return-values/ts:return-value/@name">
    The keys from the results should match with the names from the return-values.
  </sch:assert>
</sch:rule>

(I haven't tested the above sample, so it might require some modification.)

From the question title, it sounds like you might also be interested in asserting that the result elements are in the correct sequence compared to the template. You can use the XPath position() function to help check that.