Page 1 of 1

xs:unique in nested tags

Posted: Fri Aug 12, 2005 5:34 pm
by amsmota
Hello all:

I was trying to define nodes with unique values, something like

Code: Select all


                <xs:unique name="nodeName">
<xs:selector xpath="Menu"/>
<xs:field xpath="Name"/>
</xs:unique>
that is working when my <Menu> nodes are on the same "level". However i have a nested structure where <Menu> can appear at any level, being child of other <Menu>s.

Since i can't use <xs:selector xpath="//Menu"/>, what cai i do? Or am i doomed to failure?

Thanks a lot.

Posted: Fri Aug 12, 2005 6:22 pm
by george
Hi,

In XML Schema you can solve the problem if you know a maximum depth for your menus. Then you can have something like:

Code: Select all


<xs:unique name="MenuUnique">
<xs:selector xpath="Menu|Menu/Menu|Menu/Menu/Menu|Menu/Menu/Menu/Menu"/>
<xs:field xpath="Name"/>
</xs:unique>
This will work for a max depth of 4.

If you want to solve the general problem then embedding Schematron in XML Schema is your friend and the good news is that oXygen supports that.
See the sample schema and instance below:

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sch="http://www.ascc.net/xml/schematron">
<xs:annotation>
<xs:appinfo>
<sch:title>Schematron validation schema for nested Menus</sch:title>
</xs:appinfo>
</xs:annotation>
<xs:element name="test">
<xs:complexType>
<xs:sequence>
<xs:element ref="Menu"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Menu">
<xs:annotation>
<xs:appinfo>
<sch:pattern name="Check that the menus are unique.">
<sch:rule context="Menu">
<sch:assert test="not(Name[.=following::Menu/Name])">Menu names should be
unique.</sch:assert>
</sch:rule>
</sch:pattern>
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element ref="Name"/>
<xs:element ref="Menu" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Name" type="xs:string"> </xs:element>
</xs:schema>

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<?oxygen SCHSchema="test.xsd"?>
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="test.xsd">
<Menu>
<Name>M1</Name>
<Menu>
<Name>M2</Name>
<Menu>
<Name>M3</Name>
<Menu>
<Name>M4</Name>
<Menu>
<Name>M2</Name>
</Menu>
</Menu>
</Menu>
</Menu>
</Menu>
</test>
If you save the above files on your machine as test.xsd and test.xml then you can use the Validate action to validate the instance both against the XML Schema and against the embedded schematron rules.

Setting the context node in a Menu is important as you get the location of the error pointing to that element, in the above sample pointing to
/test/Menu[1]/Menu[1]

Best Regards,
George

Posted: Fri Aug 12, 2005 8:30 pm
by amsmota
Thanks, i had figured out thye first option, but since there's at least 8 leves in my XML it seems a little clumsy. I wonder why the XPath Schema subset doesen't support the axis...

As per the second, while i'm developing in Oxygen the users probably use other tools, so i have to be generic. But it's a good reference for the future.

Thanks a lot.