简体   繁体   English

XML模式强制使用0或1个默认值

[英]XML Schema to enforce 0 or 1 default values

I am trying to implement an XML Schema which will enforce the following the 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>no</default>        
    </database>
</databases>

I am able to implement the XML Schema myself except for one crucial issue; 除了一个关键问题,我自己可以实现XML模式。 and that is that a maximum of only one database should be marked as the default. 也就是说,最多只能将一个数据库标记为默认数据库。 This means that zero databases could be marked as the default and this should also be considered valid. 这意味着可以将零个数据库标记为默认数据库,这也应被视为有效。

As an example, the following XML should be considered invalid by the XML Schema, since more than one database is marked as default. 例如,由于多个数据库被标记为默认数据库,因此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>

Whereas the following XML should be considered valid by the XML Schema since no (zero) databases are marked as default ; 由于XML架构应将以下XML视为有效,因为没有(零)数据库被标记为default;

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

Does anyone know if it is possible to enforce such a constraint with XML Schemas? 有谁知道是否可以使用XML模式实施这种约束? I feel as though it should be, but I'm not sure how to go about implementing it. 我觉得好像应该这样,但是我不确定如何去实现它。

Any assistance with respect to this matter would be immensely appreciated. 在此问题上的任何协助将不胜感激。

Thanks in advance. 提前致谢。

The easiest way to check that only one database is marked as the default is probably to structure your XML differently: record the databases as above, but drop the default element, and add an attribute or child element to the databases element which identifies the default database. 检查只有一个数据库标记为默认数据库的最简单方法可能是采用不同的XML结构:如上所述记录数据库,但是删除default元素,并向databases元素添加一个属性或子元素,以标识默认数据库。 Your XML becomes: 您的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>

(I have dropped the quotation marks in the name elements, on the theory that they are not actually part of the database name. If they are part of the name, then the default attribute will need to be something like default='"Test A"' , including the quotes.) (从理论上讲,它们实际上并不是数据库名称的一部分,因此我在name元素中删除了引号。如果它们是名称的一部分,则默认属性将需要类似于default='"Test A"' ,包括引号。)

You will need to ensure that the database/name element is unique; 您将需要确保database/name元素是唯一的; do this with an xs:key construct in the declaration of the databases element. databases元素的声明中使用xs:key构造执行此databases You will also need to ensure that the optional default attribute points at a database name; 您还需要确保可选的default属性指向数据库名称。 do this with xs:keyref . 使用xs:keyref做到这xs:keyref The declaration of databases might look something like this: 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>

A second approach makes a slightly devious use of xs:unique , but again requires refactoring your XML. 第二种方法稍微使用xs:unique ,但是再次需要重构XML。 Instead of making the third child of database be default with values yes or no , make the third child be either an element named default-database or an element named non-default-database (change the names to suit your preferences, of course). 不要使database的第三个子项成为default值为yesno default ,而是使第三个子项成为名为default-database的元素或名为non-default-database的元素(当然,可以更改名称以适合您的首选项)。 Define these in such a way as to ensure that every instance of default-database has the same simple-type value. 以确保default-database每个实例都具有相同的简单类型值的方式定义它们。

Then specify that no two occurrences of default-database may have the same string value, using xs:unique : 然后使用xs:unique指定没有两次出现的default-database可以具有相同的字符串值:

<xs:unique name="dbname">
  <xs:selector xpath="database"/>
  <xs:field xpath="default-database"/>
</xs:unique>

Since every instance of default-database has the same value, this uniqueness constraint ensures that there can only ever be one such element. 由于default-database每个实例都具有相同的值,因此这种唯一性约束确保只能有一个这样的元素。 The schema as a whole might look something like this. 整个架构可能看起来像这样。 First the bookkeeping: 首先记账:

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

Now the element declaration for databases : 现在, databases的元素声明:

  <xs:element name="databases" type="databases">
    <xs:unique name="dbname">
      <xs:selector xpath="database"/>
      <xs:field xpath="default-database"/>
    </xs:unique>
  </xs:element>

And its complex type: 及其复杂类型:

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

Now some more bookkeeping: declaration for database , just to keep us honest. 现在再进行一些记账:为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>

And a final bit of bookkeeping: a type that ensures that every instance of default-database has the same value. 最后一点簿记:一种类型,可确保default-database每个实例都具有相同的值。 (There are other ways to achieve this, of course; this is just the one that came to mind first.) (当然,还有其他方法可以实现;这只是最先想到的一种。)

  <xs:simpleType name="empty">
    <xs:restriction base="xs:string">
      <xs:enumeration value=""/>
    </xs:restriction>
  </xs:simpleType> 

</xs:schema>

If you are absolutely married to your existing design, then I don't know how to do what you want to do in XSD 1.0; 如果您绝对喜欢现有的设计,那么我不知道如何执行XSD 1.0中的操作。 if you can use XSD 1.1, of course, you can add an assertion on databases that says 如果可以使用XSD 1.1,则可以在databases上添加一个断言

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

But as the alternative solutions above illustrate, that design and the use of assertions is not your only option. 但是,正如上面的替代解决方案所说明的那样,断言的设计和使用不是您唯一的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM