用于强制0或1个默认值的XML架构

用于强制0或1个默认值的XML架构,xml,schema,constraints,Xml,Schema,Constraints,我正在尝试实现一个XML模式,它将在XML中强制执行以下内容: <databases> <database> <name>"Test A"</name> <host>"192.168.0.100"</host> <default>yes</default> </database> <database>

我正在尝试实现一个XML模式,它将在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>

“测试A”
"192.168.0.100"
对
“测试B”
"192.168.0.200"
不
“测试C”
“本地主机”
不
我能够自己实现XML模式,除了一个关键问题;也就是说,最多只能将一个数据库标记为默认数据库。这意味着零数据库可以被标记为默认数据库,这也应该被认为是有效的

例如,XML模式应该认为以下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>

“测试A”
"192.168.0.100"
对
“测试B”
"192.168.0.200"
不
“测试C”
“本地主机”
对
鉴于以下XML应被XML模式视为有效,因为没有(零)个数据库被标记为默认数据库

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

“测试A”
"192.168.0.100"
不
“测试B”
"192.168.0.200"
不
“测试C”
“本地主机”
不
有人知道是否可以用XML模式强制执行这样的约束吗?我觉得应该这样做,但我不确定如何着手实施

我们将非常感谢您在这方面提供的任何帮助


提前感谢。

检查是否只有一个数据库被标记为默认数据库的最简单方法可能是以不同的方式构造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>
第二种方法稍微迂回地使用了
xs:unique
,但同样需要重构XML。与使用值
yes
no
数据库
的第三个子项设置为
默认
不同,将第三个子项设置为名为
默认数据库
的元素或名为
非默认数据库
的元素(当然,请根据您的偏好更改名称)。以确保
默认数据库
的每个实例都具有相同的简单类型值的方式定义它们

然后使用
xs:unique
,指定默认数据库的两次出现不可能具有相同的字符串值:

<xs:unique name="dbname">
  <xs:selector xpath="database"/>
  <xs:field xpath="default-database"/>
</xs:unique>
现在是
数据库的元素声明

  <xs:element name="databases" type="databases">
    <xs:unique name="dbname">
      <xs:selector xpath="database"/>
      <xs:field xpath="default-database"/>
    </xs:unique>
  </xs:element>
最后一点记账:确保
默认数据库的每个实例都具有相同的值的类型。(当然,还有其他方法可以实现这一点;这只是我首先想到的方法。)


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

检查是否只有一个数据库被标记为默认数据库的最简单方法可能是以不同的方式构造XML:如上所述记录数据库,但删除
default
元素,并向标识默认数据库的
数据库
元素添加属性或子元素。您的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>
第二种方法稍微迂回地使用了
xs:unique
,但同样需要重构XML。与使用值
yes
no
数据库
的第三个子项设置为
默认
不同,将第三个子项设置为名为
默认数据库
的元素或名为
非默认数据库
的元素(当然,请根据您的偏好更改名称)。以确保
默认数据库
的每个实例都具有相同的简单类型值的方式定义它们

然后使用
xs:unique
,指定默认数据库的两次出现不可能具有相同的字符串值:

<xs:unique name="dbname">
  <xs:selector xpath="database"/>
  <xs:field xpath="default-database"/>
</xs:unique>
现在是
数据库的元素声明

  <xs:element name="databases" type="databases">
    <xs:unique name="dbname">
      <xs:selector xpath="database"/>
      <xs:field xpath="default-database"/>
    </xs:unique>
  </xs:element>
最后一点记账:确保
默认数据库的每个实例都具有相同的值的类型。(当然,还有其他方法可以实现这一点;这只是我首先想到的方法。)


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

这绝对是一个奇妙的回答。一些很棒的建议写得很好。非常感谢。这是一个非常棒的回答。一些很棒的建议写得很好。非常感谢。
  <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>
  <xs:simpleType name="empty">
    <xs:restriction base="xs:string">
      <xs:enumeration value=""/>
    </xs:restriction>
  </xs:simpleType> 

</xs:schema>
<xs:assert test="count(database[default = 'yes']) = 1"/>