如何在XML模式中执行互斥属性?

时间:2008-12-22 16:45:07

标签: xml xsd schema xml-attribute

我正在尝试使两个XML属性互斥。如何创建XSD架构来捕获这种场景?

我想要其中一个

<elem value="1" />
<elem ref="something else" />

但不是

<elem value="1" ref="something else" />

6 个答案:

答案 0 :(得分:9)

您不能使用属性,但可以使用子元素...

<element name="elem">
    <complexType>
        <choice>
            <element name="value"/>
            <element name="ref"/>
        </choice>
    </complexType>
</element>

这样你就可以......

<elem>
    <value>1</value>
</elem>

...或

<elem>
    <rel>something else</rel>
</elem>

答案 1 :(得分:7)

不幸的是AFAIK你不能用XML Schema做到这一点,我自己也有同样的问题。

我看过它建议如果你需要两个:

<elem type="xxx"> 
<elem ref="yyy">

然后<elem>本身应分为两种类型,因为它们显然有不同的属性......

答案 2 :(得分:5)

由于在Alnitak的回答中提及RelaxNG,这是一个解决方案 使用RelaxNG(在大多数情况下,这种语言比W3C更好 架构)。请注意elem定义中的OR(|):

start = document
document = element document {elem+}
elem = element elem {ref | value}
ref = attribute ref {text}
value = attribute value {xsd:integer}

如果我有这个XML文件:

<document>
    <elem value="1" />
    <elem ref="something else" />
</document>

rnvxmlint

接受了它
 % rnv attributes-exclusive.rnc attributes-exclusive.xml             
 attributes-exclusive.xml

 % xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml 
 attributes-exclusive.xml validates

如果我添加XML文件:

<elem value="1" ref="something else" />

我得到验证错误,正如我想的那样(请注意错误消息 不是最理想的):

% rnv attributes-exclusive.rnc attributes-exclusive.xml    
attributes-exclusive.xml
attributes-exclusive.xml:4:0: error: attribute ^ref not allowed
required:
       after

% xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml
attributes-exclusive.xml:4: element elem: Relax-NG validity error : Invalid attribute value for element elem
attributes-exclusive.xml fails to validate

答案 3 :(得分:2)

XSD有这样的抽象类型:http://www.tek-tips.com/viewthread.cfm?qid=1364846(参见tsuji发布)

基本上,你给手头的元素一个 abstract ,复杂类型并在那里定义它的公共属性,对于所有不同的用例,它们完全相同(不是你的例子需要)。

然后你创建了2个(或更多)其他复杂类型,它们扩展了我刚才提到的抽象类型。在这些新类型中,您可以在每个用例之间定义不同的属性集。这就是XSD部分。

最后,您需要将XSI type属性添加到架构实例文档中的结果元素。因此,为了有效,元素现在必须具有一组属性或另一组属性。

不是直截了当,而是灵活的,而且我们都知道:灵活性越高,事情就越困难。

答案 4 :(得分:2)

实际上, 可以通过xs:unique或xs:key使用身份约束在XSD 1.0中定义它。您选择哪一个取决于如何处理没有这两个属性之一的元素:它们对xs有效:唯一但xs:key无效。下面的代码示例包含两种变体;确保删除其中一个,否则“stricter”xs:key优先于xs:unique,即两个属性中的一个是必需的。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="container">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="elem" maxOccurs="unbounded">
          <xs:complexType>
            <xs:attribute name="value" use="optional"/>
            <xs:attribute name="ref" use="optional"/>
          </xs:complexType>
          <!-- Note: Use either xs:unique or xs:key -->
          <xs:unique name="attrsExclusiveOptional">
            <xs:annotation>
              <xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
Both may be omitted.</xs:documentation>
            </xs:annotation>
            <xs:selector xpath="."/>
            <xs:field xpath="@value | @ref"/>
          </xs:unique>
          <xs:key name="attrsExclusiveRequired">
            <xs:annotation>
              <xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
One of them is required.</xs:documentation>
            </xs:annotation>
            <xs:selector xpath="."/>
            <xs:field xpath="@value | @ref"/>
          </xs:key>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

这将验证以下XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="schema.xsd">
  <!-- Shall pass: -->
  <elem value="1" />
  <elem ref="something else" />

  <!-- Passes for xs:unique, fails for xs:key: -->
  <elem />

  <!-- Shall fail: -->
  <elem value="1" ref="something else" />
</container>

答案 5 :(得分:1)

对于稍后会议的读者,请注意,可以使用“条件类型分配”或断言在XSD 1.1中解决问题。