Unique attribute value within grandparent element

This should cover W3C XML Schema, Relax NG and DTD related problems.
sorush12
Posts: 3
Joined: Thu Dec 18, 2014 3:35 pm

Unique attribute value within grandparent element

Post 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
radu_pisoi
Posts: 404
Joined: Thu Aug 21, 2003 11:36 am
Location: Craiova
Contact:

Re: Unique attribute value within grandparent element

Post 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.
Radu Pisoi
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com
Post Reply