XML模式仍然允许重复的id具有唯一性

时间:2013-02-15 11:11:22

标签: xml xsd

我正在尝试为书籍设计XML架构,其中需要为每个书籍条目指定唯一ID。然而它似乎没有用。以下是我正在使用的XSD,

<?xml version="1.0"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">

  <xs:element name="BookShelf">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Description" type="xs:string" minOccurs="0"/>
        <xs:element name="Shelf" type="ShelfType" minOccurs="1" maxOccurs="10"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="ShelfType">
    <xs:sequence>
      <xs:element ref="Book" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>


<xs:element name="Book">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Title" type="xs:token"/>
      <xs:element name="Language" type="xs:language"/>
    </xs:sequence>
    <xs:attribute name="id" type="xs:string" use="required"/>
  </xs:complexType>
  <xs:unique name="unique-bookId">
    <xs:selector xpath="Book"/>
    <xs:field xpath="@id"/>
  </xs:unique>
</xs:element>
</xs:schema>

我试图用此验证的XML是

<?xml version="1.0"?>

<BookShelf>
    <Description>My bookshelf</Description>
    <Shelf>
        <Book id="1">
            <Title>Seitsemän veljestä</Title>
            <Language>fi</Language>
        </Book>
        <Book id="1">
            <Title>Another title</Title>
            <Language>en</Language>
        </Book>
    </Shelf>
</BookShelf>

即使它不应该验证罚款(我已经为2个条目使用了相同的id)。我是XML的新手,如果有人能指出我在这里做错了什么,我会很高兴吗?

2 个答案:

答案 0 :(得分:10)

你有<xs:unique>在错误的地方 - 它需要在祖先元素的定义内,其中Book元素应该是唯一的,而不是在Book元素定义本身。以下将强制Book ID在每个架子中是唯一的,但在不同的架子上允许相同的ID:

  <xs:element name="BookShelf">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Description" type="xs:string" minOccurs="0"/>
        <xs:element name="Shelf" type="ShelfType" minOccurs="1" maxOccurs="10">
          <xs:unique name="unique-bookId">
            <xs:selector xpath="Book"/><!-- selects books on this shelf -->
            <xs:field xpath="@id"/>
          </xs:unique>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

如果您想让ID在所有货架上全局唯一,那么将唯一约束放在BookShelf级别并适当调整选择器:

  <xs:element name="BookShelf">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Description" type="xs:string" minOccurs="0"/>
        <xs:element name="Shelf" type="ShelfType" minOccurs="1" maxOccurs="10"/>
      </xs:sequence>
    </xs:complexType>
    <xs:unique name="unique-bookId">
      <xs:selector xpath="Shelf/Book"/><!-- selects books on all shelves -->
      <xs:field xpath="@id"/>
    </xs:unique>
  </xs:element>

为了将来参考,请注意,如果您的架构有targetNamespace,那么这些选择器将无法正常工作,因为选择器XPath中的无前缀名称始终意味着“无命名空间”。您需要将xmlns:tns="<target namespace URI>"添加到xs:schema元素,然后使用tns:Shelf/tns:Book的选择器。

答案 1 :(得分:3)

您是否特别需要使用数字作为ID值?如果没有,则有一种可能性是使用xs:ID作为id属性类型而不是xs:string

<xs:attribute name="id" type="xs:ID" use="required"/>

这样只允许unique XML identifiers作为id属性的值。但是,有效的XML标识符不能以数字开头,因此您必须将ID类型更改为id-1之类的内容。