views:

176

answers:

0

I work with some XML files on a regular basis and want to have better validation then a DTD can provide. So I started reading about schemas to see if would help me out. So far I've been able to create something that works almost like I need except for one piece. I want to be able to restrict the attribute of an element to the values of a different attribute of sibling or ancestor elements that are of the same element type. Is this even possible with XML Schema key/keyref constrictions?

I've got a document that looks something like this:

<nodeContainer>
    <node name="Table">
    </node>

    <node name="MyHouse">
        <node name="RoomWithDoor">
        </node>
        <node name="DiningRoom" extends="RoomWithDoor">
            <node name="DiningTable" extends="Table">
            </node>
        </node>
    </node>

    <node name="MySummerHouse">
        <node name="DiningRoom">
            <node name="DiningTable" extends="Table">
            </node>
        </node>
    </node>
</nodeContainer>

In this document, nodes can "extend" other nodes that are :

  • siblings
  • siblings of parents

however, nodes should not "extend":

  • parents
  • children nodes of parent's siblings

This means that MyHouse can "extend" Table, which does not make sense, but I'm okay with that.

Also important is that both house nodes should be able to have their own nodes named DiningRoom.

And my current schema is similar to this:

<xs:complexType name="node">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="node"/> <!-- node can have other nodes inside it -->
        <xs:element ref="leaf"/>
    </xs:choice>
    <xs:attribute name="name"       type="xs:anySimpleType" use="required"/>
    <xs:attribute name="extends"    type="xs:anySimpleType"/>
</xs:complexType>

<!-- document root -->
<xs:element name="root">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="nodeContainer">
                <xs:complexType>
                    <xs:choice minOccurs="0" maxOccurs="unbounded">
                        <xs:element ref="node"/>    
                    </xs:choice>
                </xs:complexType>
            </xs:element>
            <xs:element ref="otherType"/>
        </xs:choice>
    </xs:complexType>

    <!-- create constrictions -->
    <xs:unique name="UniqueNodes">
        <xs:selector xpath="nodeContainer/node"/>
        <xs:field xpath="@name"/>
    </xs:unique>
    <xs:keyref refer="UniqueNodes" name="ValidNodeExtends">
        <xs:selector xpath=".//node"></xs:selector>
        <xs:field xpath="@extends"></xs:field>
    </xs:keyref>
</xs:element>

This schema does part of what I'm looking for. It sets the keys to be the names of the first level of nodes in nodeContainer, and those keys can be used to "extend" any node at any level at or below nodeContainer. And that works as long as I don't want to "extend" siblings at lower levels. The example document above does not validate because of this line:

<node name="DiningRoom" extends="RoomWithDoor">

In the schema I've created RoomWithDoor is not a valid key to assign to "extends" since it's not part of the first level of nodes in nodeContainer. But is there anyway to write the keys/keyrefs to make them valid keys? Does placement of the keys/keyref definitions make a difference? Are my xpaths too specific (how can they be less specific)?