At least one XML element with no duplicates in XSD
Asked Answered
B

2

6

I'm trying to create a validation scenario where I want to choose at least one non-repeating element from a list.

Somewhere along the lines of:

<xs:choice minOccurs="1" maxOccurs="7">
    <xs:element name="Sunday"/>
    <xs:element name="Monday"/>
    <xs:element name="Tuesday"/>
    <xs:element name="Wednesday"/>
    <xs:element name="Thursday"/>
    <xs:element name="Friday"/>
    <xs:element name="Saturday"/>
</xs:choice>

However the above solution allows duplicate elements to appear in a list, which I don't want.

Example of a valid XML:

<Monday/>
<Tuesday/>
<Friday/>

Example of an invalid XML:

<Monday/>
<Monday/>

Can this be achieved with an XSD without having to hardcode all the possible sequences? If so how?

Benares answered 28/1, 2016 at 14:10 Comment(0)
N
4

XSD 1.0 Solution

I do not believe your constraint can be expressed in XSD 1.0 "without having to hardcode all the possible sequences" (but see C. M. Sperberg-McQueen's clever solution that cuts down the combinatorics considerably) . The values of elements could be forced to be unique using xsd:unique, but subset of XPath used by xsd:unique does not include name(), which could otherwise help make a uniqueness statement about the names of the elements.

XSD 1.1 Solution

Your constrain can be expressed in XSD 1.1 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" elementFormDefault="qualified"
  vc:minVersion="1.1">
  <xs:element name="Days">
    <xs:complexType>
      <xs:choice minOccurs="1" maxOccurs="7">
        <xs:element name="Sunday"/>
        <xs:element name="Monday"/>
        <xs:element name="Tuesday"/>
        <xs:element name="Wednesday"/>
        <xs:element name="Thursday"/>
        <xs:element name="Friday"/>
        <xs:element name="Saturday"/>
      </xs:choice>
      <xs:assert test="count(*[name() = following-sibling::*/name()]) = 0"/>
    </xs:complexType>
  </xs:element>  
</xs:schema>
Nicker answered 28/1, 2016 at 15:26 Comment(0)
A
2

You don't say whether the sequence of elements carries meaning or not. For your application, does

<Monday/>
<Thursday/>

mean the same thing, or something different, from what is meant by

<Thursday/>
<Monday/>

? If it means the same thing, then there is no need to allow both forms, and you can get what you want with

<xs:complexType>
  <xs:sequence>
    <xs:element name="Sunday" minOccurs="0"/>
    <xs:element name="Monday" minOccurs="0"/>
    <xs:element name="Tuesday" minOccurs="0"/>
    <xs:element name="Wednesday" minOccurs="0"/>
    <xs:element name="Thursday" minOccurs="0"/>
    <xs:element name="Friday" minOccurs="0"/>
    <xs:element name="Saturday" minOccurs="0"/>
  </xs:choice>
</xs:complexType>

[Addendum]. Oops; overlooked the requirement that at least one element be selected. The obvious XSD 1.0 solution is kind of clunky, but does require at least one and allow up to seven elements, all different. It uses a seven-way choice among sequences starting with Sunday, Monday, ...

<xs:complexType>
  <xs:choice>
    <xs:sequence>
      <xs:element name="Sunday"/>
      <xs:element name="Monday" minOccurs="0"/>
      <xs:element name="Tuesday" minOccurs="0"/>
      <xs:element name="Wednesday" minOccurs="0"/>
      <xs:element name="Thursday" minOccurs="0"/>
      <xs:element name="Friday" minOccurs="0"/>
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Monday"/>
      <xs:element name="Tuesday" minOccurs="0"/>
      <xs:element name="Wednesday" minOccurs="0"/>
      <xs:element name="Thursday" minOccurs="0"/>
      <xs:element name="Friday" minOccurs="0"/>
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Tuesday"/>
      <xs:element name="Wednesday" minOccurs="0"/>
      <xs:element name="Thursday" minOccurs="0"/>
      <xs:element name="Friday" minOccurs="0"/>
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Wednesday" />
      <xs:element name="Thursday" minOccurs="0"/>
      <xs:element name="Friday" minOccurs="0"/>
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Thursday"/>
      <xs:element name="Friday" minOccurs="0"/>
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Friday" />
      <xs:element name="Saturday" minOccurs="0"/>
    <xs:sequence>
    <xs:sequence>
      <xs:element name="Saturday" />
    <xs:sequence>
  </xs:choice>
</xs:complexType>
Avunculate answered 28/1, 2016 at 15:59 Comment(1)
This solution allows an empty list. The scenario requires at least one element. As to your question, yes both forms mean the same thing in my application.Admeasurement

© 2022 - 2024 — McMap. All rights reserved.