如何使用key/keyrefs为同一类型的嵌套元素创建xml架构

问题描述:

我定期处理一些XML文件,并希望DTD可以提供更好的验证。所以我开始阅读有关模式,看看能否帮助我。到目前为止,我已经能够创造出几乎和我需要的东西一样的作品,除了一件作品。我希望能够将元素的属性限制为具有相同元素类型的兄弟元素或祖先元素的不同属性的值。这甚至可以用XML Schema key/keyref收缩吗?如何使用key/keyrefs为同一类型的嵌套元素创建xml架构

我有一个文件,看起来像这样:

<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> 

在这份文件中,节点可以在“扩展”是其他节点:

  • 兄弟姐妹的父母
  • 兄弟姐妹

但是,节点不应该“扩展”:

  • 父母
  • 儿童父母的兄弟姐妹节点

这意味着的MyHouse可以在“扩展” ,这没有任何意义,但我可以接受这一点。

同样重要的是,两个家庭节点应该能够拥有自己的节点DiningRoom

而且我目前的架构是类似这样的:

<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> 

这个模式做什么我要找的一部分。它将密钥设置为nodeContainer中第一级节点的名称,并且这些密钥可用于“扩展”处于或低于nodeContainer的任何级别的任何节点。只要我不想“延伸”下级的兄弟姐妹,那就行得通了。示例文档上面并没有因为这条线的验证:

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

在模式我创建RoomWithDoor不分配给一个有效的关键“延伸”,因为它不是节点的第一级的一部分在nodeContainer。但无论如何要写钥匙/ keyrefs来使它们成为有效的钥匙吗?按键/ keyref定义的放置是否有所不同?我的xpath是否过于具体(它们怎么可能不那么具体)?

如果您UniqueNodes中的XPath选择更改为

<xs:selector xpath="nodeContainer//node"/> 

换句话说,会发生什么 - 在nodeContainer下的任何节点元素。 这不会允许你想实现什么吗?