代码之家  ›  专栏  ›  技术社区  ›  Filip Frącz

如何在XML模式中实现互斥属性?

  •  14
  • Filip Frącz  · 技术社区  · 16 年前

    我试图使两个XML属性相互排斥。如何创建XSD模式来捕获这种场景?

    我想要一个这个

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

    但不是

    <elem value="1" ref="something else" />
    
    6 回复  |  直到 7 年前
        1
  •  5
  •   bortzmeyer    16 年前

    自从 RelaxNG 在阿尼塔克的回答中提到,这里有一个解决方案 轻松(在大多数情况下,这种语言比W3C更好) 模式)。请注意elem定义中的或():

    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>
    

    它被接受了 rnv xmlint :

     % 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
    
        2
  •  9
  •   Daniel Silveira    16 年前

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

    <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>
    
        3
  •  7
  •   Alnitak    16 年前

    不幸的是,对于XML模式,您不能这样做,我自己也有同样的问题。

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

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

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

        4
  •  2
  •   DanMan    12 年前

    XSD具有以下抽象类型: http://www.tek-tips.com/viewthread.cfm?qid=1364846 (见tsuji的帖子)

    基本上,你给手头的元素 摘要 ,并定义其中的公共属性 确切地 对于所有不同的用例都是相同的(您的示例不需要)。

    然后创建两个(或更多)附加的复杂类型,扩展我刚才提到的抽象类型。内 这些 新类型定义了每个用例之间的不同属性集。这就是XSD部分。

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

    不是直截了当,而是灵活,正如我们所知:越灵活,事情就越困难。

        5
  •  2
  •   Burkart Rutger Nijlunsing    7 年前

    实际上,它 可以通过xs:unique或xs:key使用标识约束在xsd 1.0中定义这个。您选择哪一个取决于如何处理没有这两个属性的元素:它们对xs:unique有效,但对xs:key无效。下面的代码示例包含两个变量;请确保删除其中一个变量,否则“更严格的”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>
    
        6
  •  1
  •   Michael Kay    10 年前

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