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

发布于 2024-07-10 12:54:25 字数 235 浏览 4 评论 0原文

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

我想要其中之一

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

,但没有

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

I'm trying to make two XML attributes to be mutually exclusive. How can one create an XSD schema to capture this kind of scenario?

I would like to have one of these

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

but not

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

说谎友 2024-07-17 12:54:25

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

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

You can't do with attributes, but you can with child elements...

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

This way you can have...

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

or...

<elem>
    <rel>something else</rel>
</elem>
沉溺在你眼里的海 2024-07-17 12:54:25

不幸的是,据我所知,您无法使用 XML Schema 做到这一点,我自己也遇到了同样的问题。

我看到它建议,如果您需要两者:

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

那么 本身应该分为两种类型,因为它们显然具有不同的属性......

Unfortunately AFAIK you can't do that with XML Schema, I've had the same problem myself.

I've seen it suggested that if you need both of:

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

then <elem> itself should be split into two types, since they've clearly got different attributes...

指尖上得阳光 2024-07-17 12:54:25

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

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

Since RelaxNG was mentioned in Alnitak's answer, here is a solution
with RelaxNG (a language which is, in most cases, better than W3C
Schema). Do note the OR (|) in the definition of elem:

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

If I have this XML file:

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

It is accepted by rnv and xmlint:

 % rnv attributes-exclusive.rnc attributes-exclusive.xml             
 attributes-exclusive.xml

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

If I add in the XML file:

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

I get validation errors, as I want (do note that the error messages
are suboptimal):

% 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
睡美人的小仙女 2024-07-17 12:54:25

实际上,可以通过 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>

Actually, it is possible to define this in XSD 1.0 using identity constraints via xs:unique or xs:key. Which one you choose depends on how elements without either of the two attributes shall be treated: They're valid with xs:unique but invalid with xs:key. The code sample below contains both variants; make sure to remove one of them, otherwise the "stricter" xs:key takes precedence over xs:unique, i.e., one of the two attributes is required.

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

This validates the following XML file:

<?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>
不弃不离 2024-07-17 12:54:25

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

基本上,您为手头的元素提供一个抽象、复杂类型,并在其中定义它的公共属性,即 对于所有不同的用例完全相同(您的示例不需要)。

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

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

不是直接的,而是灵活的,众所周知:越灵活,事情就会变得越困难。

XSD has abstract types for this: http://www.tek-tips.com/viewthread.cfm?qid=1364846 (see post by tsuji)

Basically, you give the element at hand an abstract, complex type and define it's common attributes in there, which are exactly the same for all different use cases (not needed for your example).

Then you create 2 (or more) additional complex types which extend the abstract type I've just mentioned. Within these new types you define the differing sets of attributes between each use case. That's it for the XSD part.

Finally, you need to add a XSI type attribute to the resulting element in the schema instance document. So to be valid, the element must now have either one set of attributes or the other.

Not straight-forward, but flexible, and as we all know: the more flexible, the more difficult something becomes.

酒解孤独 2024-07-17 12:54:25

对于稍后阅读此内容的读者,请注意,该问题可以在 XSD 1.1 中使用“条件类型赋值”或断言来解决。

For readers coming to this later, note that the problem can be solved in XSD 1.1 using either "conditional type assignment" or assertions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文