How to define mutually exclusive attributes in XSD?
Asked Answered
R

3

10

###First the code fragment...

<tag name="default" abc="10" def="20"> <!-- not valid, abc and def should be mutually exclusive -->

<tag name="default1" abc="10"> <!-- valid -->

<tag name="default2" def="20"> <!-- valid -->

###What I want to do...

What can I put into my XSD so that @abc and @def cannot coexist as attributes on the same element?

So that validation would fail if they coexisted on the same element?

Rowlandson answered 17/11, 2015 at 3:10 Comment(3)
You don't say whether <tag name="default3"/> should be valid (ie when neither attribute is present).Whipstitch
Yeah I guess that would be invalid, it needs one of themRowlandson
@Rowlandson see my answer.Amedeo
W
8

XSD 1.0

Can be done with clever trick using xs:key. See @Kachna's answer.

Note that some parsers may allow both attributes if they fail to fail for multiple selected values in xs:key. There is at least one known case of this happening in the past.

XSD 1.1

Can be done using xs:assert:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           vc:minVersion="1.1">
  <xs:element name="tag">
    <xs:complexType>
      <xs:sequence/>
      <xs:attribute name="name" type="xs:string"/>
      <xs:attribute name="abc" use="optional" type="xs:integer"/>      
      <xs:attribute name="def" use="optional" type="xs:integer"/>
      <xs:assert test="(@abc and not(@def)) or (not(@abc) and @def)"/>      
    </xs:complexType>
  </xs:element>
</xs:schema>
Whipstitch answered 17/11, 2015 at 3:51 Comment(1)
Another approach in XSD 1.1 is to use conditional type assignment: have one type that allows abc but not def, a second type that allows def but not abc, and choose between them using xs:alternative.Marucci
A
7

With XSD 1.0, you can use xs:keyelement.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="tag">
    <xs:complexType>
        <xs:attribute name="name" type="xs:string" use="required"/>
        <xs:attribute name="abc"  type="xs:integer"/>      
        <xs:attribute name="def"  type="xs:integer"/>
     </xs:complexType>
    <xs:key name="attributeKey">
        <xs:selector xpath="."/>
        <xs:field xpath="@abc|@def"/>
    </xs:key>
</xs:element>   

Edit: If both attributes are present (even with different values), this creates two keys, so the XML validation will fail. On the other hand, the <xs: key> requires that a key is defined for the element, and therefore one of the two attributes must be present.

the following XML doc is not valid using the above XSD. (I'am using oXygen 17.0):

<tag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="stack3.xsd" name="" abc="12" def="13"/>

Error:

cvc-identity-constraint.3: Field "./@abc|./@def" of identity constraint "attributeKey" matches more than one value within the scope of its selector; fields must match unique values
Amedeo answered 17/11, 2015 at 18:18 Comment(1)
In Visual Studio 2015, the error may be misleading: The field 'def' is expecting at the most one value.Incandesce
H
0

According to https://www.w3.org/TR/xmlschema-1/#Selector page, I guess doing with the mutex between attributes with xs:key wouldn't work in other solutions.

It says, "When tokenizing, the longest possible token is always returned."

Harberd answered 11/9, 2020 at 12:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.