XML Schema强制执行0或1个默认值

时间:2012-10-27 14:39:45

标签: xml schema constraints

我正在尝试实现一个XML Schema,它将强制执行以下XML;

<databases>
    <database>
        <name>"Test A"</name>
        <host>"192.168.0.100"</host>
        <default>yes</default>
    </database>
    <database>
        <name>"Test B"</name>
        <host>"192.168.0.200"</host>
        <default>no</default>        
    </database>
    <database>
        <name>"Test C"</name>
        <host>"localhost"</host>
        <default>no</default>        
    </database>
</databases>

除了一个关键问题,我能够自己实现XML Schema;那就是最多只能将一个数据库标记为默认值。这意味着可以将零数据库标记为默认值,这也应该被认为是有效的。

例如,XML Schema应认为以下XML无效,因为多个数据库被标记为默认值。

<databases>
    <database>
        <name>"Test A"</name>
        <host>"192.168.0.100"</host>
        <default>yes</default>
    </database>
    <database>
        <name>"Test B"</name>
        <host>"192.168.0.200"</host>
        <default>no</default>        
    </database>
    <database>
        <name>"Test C"</name>
        <host>"localhost"</host>
        <default>yes</default>        
    </database>

以下XML应被XML Schema视为有效,因为没有(零)数据库被标记为默认值;

<databases>
    <database>
        <name>"Test A"</name>
        <host>"192.168.0.100"</host>
        <default>no</default>
    </database>
    <database>
        <name>"Test B"</name>
        <host>"192.168.0.200"</host>
        <default>no</default>        
    </database>
    <database>
        <name>"Test C"</name>
        <host>"localhost"</host>
        <default>no</default>        
    </database>

有没有人知道是否可以使用XML Schema强制执行此类约束?我觉得它应该是,但我不确定如何实施它。

对此事的任何帮助都将非常感激。

提前致谢。

1 个答案:

答案 0 :(得分:1)

检查只有一个数据库被标记为默认值的最简单方法可能是以不同方式构造XML:如上所述记录数据库,但删除default元素,并将属性或子元素添加到databases元素,用于标识默认数据库。您的XML变为:

<databases default="Test A">
    <database>
        <name>Test A</name>
        <host>"192.168.0.100"</host>
   </database>
    <database>
        <name>Test B</name>
        <host>"192.168.0.200"</host>
   </database>
    <database>
        <name>Test C</name>
        <host>"localhost"</host>
   </database>
</databases>

(我已经删除了name元素中的引号,理论上它们实际上并不是数据库名称的一部分。如果它们是名称的一部分,则默认属性需要是某种东西例如default='"Test A"',包括引号。)

您需要确保database/name元素是唯一的;在xs:key元素的声明中使用databases构造执行此操作。您还需要确保可选的default属性指向数据库名称;使用xs:keyref执行此操作。 databases的声明可能如下所示:

<xs:element name="databases" type="databases">
  <xs:key name="dbname">
    <xs:selector xpath="database"/>
    <xs:field xpath="name"/>
  </xs:key>
  <xs:keyref refer="dbname" name="defaultdb">
    <xs:selector xpath="."/>
    <xs:field xpath="@default"/>
  </xs:keyref>
</xs:element>

第二种方法略微使用xs:unique,但同样需要重构XML。不要让database的第三个孩子成为值defaultyes no,而是让第三个孩子成为名为default-database的元素或名为non-default-database的元素default-database(当然,更改名称以满足您的偏好)。以确保default-database的每个实例具有相同的简单类型值的方式定义它们。

然后使用xs:unique指定<xs:unique name="dbname"> <xs:selector xpath="database"/> <xs:field xpath="default-database"/> </xs:unique> 不会出现两次相同的字符串值:

default-database

由于<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> 的每个实例都具有相同的值,因此该唯一性约束确保只能存在一个这样的元素。整个架构可能看起来像这样。首先是簿记:

databases

现在 <xs:element name="databases" type="databases"> <xs:unique name="dbname"> <xs:selector xpath="database"/> <xs:field xpath="default-database"/> </xs:unique> </xs:element> 的元素声明:

  <xs:complexType name="databases">
    <xs:sequence minOccurs="0" maxOccurs="unbounded">
      <xs:element ref="database"/>
    </xs:sequence>
    <xs:attribute name="default" type="xs:string" use="optional"/>
  </xs:complexType>

其复杂类型:

database

现在更多的簿记: <xs:element name="database" type="database"/> <xs:complexType name="database"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="host" type="xs:string"/> <xs:choice> <xs:element name="default-database" type="empty"/> <xs:element name="non-default-database" type="empty"/> </xs:choice> </xs:sequence> </xs:complexType> 的声明,只是为了让我们诚实。

default-database

最后一点簿记:确保 <xs:simpleType name="empty"> <xs:restriction base="xs:string"> <xs:enumeration value=""/> </xs:restriction> </xs:simpleType> </xs:schema> 的每个实例具有相同值的类型。 (当然,还有其他方法可以实现这一目标;这只是首先想到的那个。)

databases

如果您与现有设计完全结合,那么我不知道如何在XSD 1.0中做您想做的事情;如果你可以使用XSD 1.1,当然,你可以在<xs:assert test="count(database[default = 'yes']) = 1"/> 上添加一个说明

的断言
{{1}}

但正如上面的替代解决方案所示,该设计和断言的使用并非您唯一的选择。