Let's say I have a schema to define a list of articles. Each of these articles has a list of long names, one for each known language. The language is an attribute at the level of an individual long name.
I want to assure 2 things:
- The language attribute can only have one of several pre-determined values (solved using an enumeration).
- Within each list of long names, a given value for the language attribute can only occur once. For each article I can only have one English long name, one German long name, one French long name etc.
Following another post (link) I implemented a unique constraint at the longName-level. It will satisfy #1, but not #2. If I have 'EN' twice as longName attribute within the same longNames element, it will consider the xml valid.
Original sample XML
<article>
<articleNumber>3019</articleNumber>
<longNames>
<longName language="EN">
<description>A French Omelette with Cheese</description>
</longName>
<longName language="FR">
<description>Un omelette DU(???) fromage</description>
</longName>
</longNames>
</article>
Original XSD schema
<xs:complexType name="ArticleType">
<xs:sequence>
<xs:element name="articleNumber" type="xs:integer" />
<xs:element type="bl:LongNamesType" name="longNames" />
<xs:element type="bl:ShortNameType" name="shortName" maxOccurs="3" />
<xs:element type="bl:AllergensType" name="allergens" maxOccurs="3" />
<xs:element type="bl:IngredientsType" name="ingredients" maxOccurs="3" />
<xs:element type="bl:PictureType" name="picture" maxOccurs="3" />
<xs:element name="barcode" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LongNamesType">
<xs:sequence>
<xs:element name="longName" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<!-- <xs:element type="bl:LanguageType" name="language" /> -->
<xs:element name="description" type="xs:string" />
</xs:sequence>
<xs:attribute name="language" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="EN" />
<xs:enumeration value="FR" />
<xs:enumeration value="DE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
<xs:unique name="uniqueLongNameLanguage">
<xs:selector xpath="longNames" />
<xs:field xpath="@language" />
</xs:unique>
</xs:element>
</xs:sequence>
</xs:complexType>
Could anyone help me figure out what I'm doing wrong?
Edit: thanks to Yitzak Khabinsky and Michael Kay I managed to find below working solution. Admittedly it's a bit of a mixture of styles. Thanks to all who replied!
Improved XSD
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns:bl="urn:inventoryinput"
targetNamespace="urn:inventoryinput">
<xs:element name="inventory" type="bl:InventoryType" />
<xs:complexType name="InventoryType">
<xs:sequence>
<xs:element type="bl:ArticleType" name="article" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArticleType">
<xs:sequence>
<xs:element name="articleNumber" type="xs:integer" />
<xs:element ref="bl:longNames" minOccurs="0" />
<xs:element name="barcode" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:element name="longNames">
<xs:complexType>
<xs:sequence>
<xs:element ref="bl:longName" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueLongNameLanguage">
<xs:selector xpath="bl:longName" />
<xs:field xpath="@language" />
</xs:unique>
</xs:element>
<xs:element name="longName" >
<xs:complexType>
<xs:sequence>
<xs:element name="description" type="xs:string" />
</xs:sequence>
<xs:attribute name="language" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="NL" />
<xs:enumeration value="FR" />
<xs:enumeration value="DE" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
...
Reworked XML example
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<inventory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:inventoryinput">
<article>
<articleNumber>3019</articleNumber>
<longNames>
<longName language="NL">
<description>DE TROG Ardeens bruin brood Bio 600g</description>
</longName>
<longName language="FR">
<description>DE TROG pain ardennais complet Bio 600g</description>
</longName>
</longNames>
CodePudding user response:
Please try the following solution.
Input XML
<article>
<articleNumber>3019</articleNumber>
<longNames>
<longName language="EN">
<description>A French Omelette with Cheese</description>
</longName>
<longName language="FR">
<description>Un omelette DU(???) fromage</description>
</longName>
</longNames>
</article>
XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="article">
<xs:complexType>
<xs:sequence>
<xs:element ref="articleNumber"/>
<xs:element ref="longNames"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="articleNumber" type="xs:integer"/>
<xs:element name="longNames">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="longName"/>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueLongNameLanguage">
<xs:selector xpath="longName"/>
<xs:field xpath="@language"/>
</xs:unique>
</xs:element>
<xs:element name="longName">
<xs:complexType>
<xs:sequence>
<xs:element ref="description"/>
</xs:sequence>
<xs:attribute name="language" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="EN"/>
<xs:enumeration value="FR"/>
<xs:enumeration value="DE"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="description" type="xs:string"/>
</xs:schema>