【问题标题】:XML schema still allowing duplicate id's with uniqueXML 模式仍然允许具有唯一性的重复 ID
【发布时间】:2013-02-15 11:11:21
【问题描述】:

我正在尝试为需要为每个书籍条目指定唯一 ID 的书籍设计 XML 模式。但是,它似乎不起作用。下面是我正在使用的 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 的新手,如果有人能指出我在这里做错了什么,我将不胜感激?

【问题讨论】:

    标签: xml xsd


    【解决方案1】:

    您将&lt;xs:unique&gt; 放在错误的位置 - 它需要位于 ancestor 元素的定义中,其中 Book 元素应该是唯一的,而不是在 @987654323 中@ 元素定义本身。以下将强制 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="&lt;target namespace URI&gt;" 添加到您的xs:schema 元素中,然后使用tns:Shelf/tns:Book 选择器。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2017-02-27
        • 2017-12-19
        • 2012-02-19
        • 1970-01-01
        • 2018-09-24
        • 1970-01-01
        • 2015-09-25
        • 1970-01-01
        相关资源
        最近更新 更多