Unique attribute value within grandparent element

This should cover W3C XML Schema, Relax NG and DTD related problems.
sorush12
Posts: 3

Unique attribute value within grandparent element

Thu Jan 08, 2015 4:27 pm

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: 328
Location: Craiova

Re: Unique attribute value within grandparent element

Tue Jan 13, 2015 5:51 pm

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

Return to “XML Schemas”

Who is online

Users browsing this forum: No registered users and 2 guests