Page 1 of 1

Unique attribute value within grandparent element

Posted: Thu Jan 08, 2015 4:27 pm
by sorush12
Hi!
Please consider the following XML document described in Relax NG(Root element- Country, contains of one or more cities; Each city has one or more streets; then each street has one children: info. Info element has text and zero or more fact elements within the text (mixed). Fact element has an ID attribute);

Code: Select all


<element name="country">
<oneOrMore>
<element name="city">
<oneOrMore>
<element name="street">
<element name="info">
<mixed>
<zeroOrMore>
<element name="fact">
<attribute name="id"/>
<text/>
</element>
<zeroOrMore>
</mixed>
</element>
</element>
</oneOrMore>
</element>
</oneOrMore>
</element>
I want that fact elements had unique ID values at the city level (grand-grandparent). The following Schematron rule does not work;

Code: Select all


<iso:rule context="city">
<iso:assert test="count(//street//fact)=count(//street//fact[not(@id=preceding- sibling::fact/@id)])">Error!
</iso:assert>
</iso:rule>
Would you please help me on this issue?
P.S. If it was possible to write: preceding-sibling:://street/fact/@id), it may had worked, but it is not!
Thank you in advance

Re: Unique attribute value within grandparent element

Posted: Tue Jan 13, 2015 5:51 pm
by radu_pisoi
Hi,

One of the problems that I have seen is that you use absolute XPath expressions in the assert/@test attribute, for instance '//street//fact'. The previous expression will returns all the 'fact' elements from the entire document not only from the current 'city' element matched by the rule.

Another solution for your case could be the next rule:

Code: Select all


<iso:rule context="fact">
<iso:let name="factID" value="@id"/>
<iso:let name="parentCity" value="ancestor::*[local-name() = 'city']"/>

<iso:let name="elemsWithSameId" value="
preceding::fact[ancestor::* = $parentCity][@id = $factID]"/>

<iso:assert test="count($elemsWithSameId) = 0">
Duplicate ID: <iso:value-of select="$factID"/>
</iso:assert>
</iso:rule>
This rule matches a 'fact' element and verifies that there is no other previous 'fact' element with the same ID in the context of the city element.