Predefined attributes/constants in xsd enumeration - attributes

I have the following xml:
<animals>
<animal name="Pongo" animalType="Dog" />
<animal name="Marie" animalType="Cat" />
<animal name="Skippy" animalType="Kangaroo" />
</animals>
I know it is possible to restrict the type of animals using an enum like this:
<xs:simpleType name="animalType">
<xs:restriction base="xs:string">
<xs:enumeration value="Cat" />
<xs:enumeration value="Dog" />
<xs:enumeration value="Kangaroo" />
</xs:restriction>
</xs:simpleType>
What I whould like is to know automatically, based on the animalType value, how many shoes does the animal need, after the xml parsing.
And, when a new animal type is being added, to add also the number of walking legs for that animal.
For instance, it would be great to be possible to define something like
<xs:simpleType name="animalType">
<xs:restriction base="xs:string">
<xs:enumeration value="Cat" nbOfShoes="4" />
<xs:enumeration value="Dog" nbOfShoes="4" />
<xs:enumeration value="Kangaroo" nbOfShoes="2" />
</xs:restriction>
</xs:simpleType>
Is it possible to achieve this using xsd, or I have to implement the numberOfShoes logic after the xml is being parsed?
Thank you.

It depends. In XSD you can define xml from structure point of view. The relation between structure and content is more difficult to express in XSD 1.0.
You could use substitution of types using xsi:type attribute. The XSD could look like
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- Let be Animals root element -->
<xs:element name="Animals" type="animals" />
<!-- type for Animals elemes -->
<xs:complexType name="animals">
<xs:sequence>
<xs:element name="Animal" maxOccurs="unbounded" type="animal"/>
</xs:sequence>
</xs:complexType>
<!-- Define an abstract type for animal (abstract = there shouldn't occure element of this type only of its childs). It has no attributes. -->
<xs:complexType name="animal" abstract="true">
<xs:simpleContent>
<xs:extension base="xs:string"/>
</xs:simpleContent>
</xs:complexType>
<!-- Define a type for cat... -->
<xs:complexType name="catType">
<xs:simpleContent>
<!-- ... it extends abstract animal type ... -->
<xs:extension base="animal">
<!-- ... and add some attributes with fixed values -->
<xs:attribute name="name" fixed="cat" />
<xs:attribute name="nbOfLegs" fixed="4" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- similar definition like catType -->
<xs:complexType name="kangarooType">
<xs:simpleContent>
<xs:extension base="animal">
<xs:attribute name="name" fixed="kangaroo" />
<xs:attribute name="nbOfLegs" fixed="2" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
Following XML should validate
<?xml version="1.0" encoding="UTF-8"?>
<Animals xsi:noNamespaceSchemaLocation="animals.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- xsi:type is saying what type is actually used -->
<Animal xsi:type="catType" name="cat" nbOfLegs="4" />
<Animal xsi:type="kangarooType" name="kangaroo" nbOfLegs="2" />
</Animals>
Following not
<?xml version="1.0" encoding="UTF-8"?>
<Animals xsi:noNamespaceSchemaLocation="animals.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Animal xsi:type="catType" name="cat" nbOfLegs="2" />
</Animals>
(with error like Value '2' of attribute 'nbOfLegs' is not equal to the fixed default value '4').

Related

How to declare an xs:element with two different sets of attributes?

My new XML private language includes elements <figure>, representing illustrations (image + caption).
Whenever illustrations refer to some image in the local database I just want to type
<figure id="9809" width="full" />
to identify image number 9809 and its associated caption.
On the other side, if images come from outside I will need a slightly different syntax:
<figure href="https://some-url-here" width="full">Some ad hoc catpion</figure>
So far I have declared an element that combine both behaviours, like this:
<!-- Figures -->
<xs:simpleType name="FigureWidthEnum">
<xs:restriction base="xs:token">
<xs:enumeration value="center" />
<xs:enumeration value="half" />
<xs:enumeration value="full" />
</xs:restriction>
</xs:simpleType>
<xs:element name="figure">
<xs:complexType mixed="true">
<xs:complexContent>
<xs:extension base="Inline">
<xs:attribute name="href" type="URI" />
<xs:attribute name="id" type="xs:nonNegativeInteger" />
<xs:attribute name="width" type="FigureWidthEnum" default="full" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
It works fine but a fresh editor can mess with the 3 attributes and type impossible things I don't want to pass the Schema Validator that easy. For example:
<figure id="9809" width="full" href="https://some-unexpected-url">Some unexpected caption that should not be here</figure>
I want to have two completely separate sintaxes for <figure>, as if I could declare these two elements with the same name:
<xs:element name="figure">
<xs:complexType mixed="true">
<xs:complexContent>
<xs:extension base="Inline">
<xs:attribute name="href" type="URI" />
<xs:attribute name="width" type="FigureWidthEnum" default="full" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="figure">
<xs:complexType>
<xs:attribute name="id" type="xs:nonNegativeInteger" />
<xs:attribute name="width" type="FigureWidthEnum" default="full" />
</xs:complexType>
</xs:element>
In fact it is not possible.
Can it be done somehow?
Yes, it is possible with XSD 1.1, which provides <xs:alternative> element intended specifically for such requirements. Here's a complete XML schema I've designed to validate exactly as you need:
<?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">
<!-- Figures -->
<xs:simpleType name="FigureWidthEnum">
<xs:restriction base="xs:token">
<xs:enumeration value="center" />
<xs:enumeration value="half" />
<xs:enumeration value="full" />
</xs:restriction>
</xs:simpleType>
<!-- stub definition -->
<xs:complexType name="Inline"/>
<!-- 'figure' element is declared once, but its type has two alternatives -->
<xs:element name="figure">
<!-- The first alternative is selected, when the condition specified
in 'test' attribute is true. The condition must be a boolean XPath
expression. The '#id' returns the value of 'id' attribute. However,
when converted to boolean, it indicates whether 'id' attribute is
specified at all. The anonymous complexType inside <xs:alternative>
provides the element type valid for this case.
-->
<xs:alternative test="#id">
<xs:complexType>
<xs:attribute name="id" type="xs:nonNegativeInteger" />
<xs:attribute name="width" type="FigureWidthEnum" default="full" />
</xs:complexType>
</xs:alternative>
<!-- The second alternative has no 'test' attribute. That means, it must
be selected by default, when all other alternatives (with a specified
test condition) do not pass. Here, the anonymous complexType inside
<xs:alternative> defines the element type in case of reference:
when 'href' is present.
-->
<xs:alternative>
<xs:complexType mixed="true">
<xs:complexContent>
<xs:extension base="Inline">
<xs:attribute name="href" type="xs:anyURI" />
<xs:attribute name="width" type="FigureWidthEnum" default="full" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:alternative>
</xs:element>
<!-- this element is defined just to test the whole schema in XML below -->
<xs:element name="figures">
<xs:complexType>
<xs:sequence>
<xs:element ref="figure" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
A complete XML file this schema validates:
<?xml version="1.0" encoding="UTF-8"?>
<figures>
<!-- passes validation -->
<figure id="9809" width="full" />
<!-- passes validation -->
<figure width="full" href="https://some-unexpected-url">Some ad hoc caption</figure>
<!-- does not pass the validation -->
<figure id="9809" width="full" href="https://some-unexpected-url">
Some unexpected caption that should not be here
</figure>
</figures>
The validation was done with Apache Xerces 2.11.0 (XSD 1.1 aware).
Promo add-on. These links may be interesting for those working with XML schemas and WSDL: FlexDoc/XML XSDDoc & WSDLDoc – High-performance universal XML Schema / WSDL Documentation Generators with Diagrams

Using keyRef in XSD : How to refer a key located in a different XSD (out of scope error)

My system parses two XML files (via JAXB unmarshalling and xjc generated code)
componentModel.xml : generated from a modeling tool
detailedDesign.xml : manual, to add informations
In order to avoid to code checks upon content and structures, each file is validated with its own XSD
componentModel.xsd
detailedDesign.xsd
Both of these xsd inclulde "utilities.xsd" where common complex and simple types are defined
All works well
I now want to add consistency check :
unicity of Ids (names of components)
components in "detailsDesign" must refers one of the components in "componentModel" via the "name" and "nameRef" attributes
Here are the structures (i've simlplified names and structures in files to show only relevant informations)
Note : as you can see, i don't use any namespace except the default one
componentModel.xml
<?xml version="1.0" encoding="UTF-8"?>
<componentModel>
<components>
<component name="id1"> ... </component>
<component name="id1"> ... </component>
<component name="id2"> ... </component>
</components>
</componentModel>
componentModel.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:include schemaLocation="utilities.xsd" />
<xs:complexType name="CMComponent">
<xs:complexContent>
...
<xs:attribute name="name" type="MUUpperFirstName" use="required" />
</xs:complexContent>
</xs:complexType>
<xs:complexType name="CMComponents">
<xs:sequence>
<xs:element name="component" type="CMComponent" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="CMComponentModel">
<xs:complexContent>
<xs:sequence>
<xs:element name="components" type="CMComponents">
<!-- Key used to check "name" unicity and as a ref by nameRef attribute in detailedDesign model -->
<xs:key name="componentNameKey">
<xs:selector xpath="component" />
<xs:field xpath="#name" />
</xs:key>
</xs:element>
<xs:element name="functionalChains" minOccurs="0" maxOccurs="1" />
</xs:sequence>
<xs:attribute name="name" type="MUModelName" use="required" />
</xs:complexContent>
</xs:complexType>
<xs:element name="componentModel" type="CMComponentModel" />
</xs:schema>
utilities.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="MUString">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="MUUpperFirstName">
<xs:restriction base="MUString">
<xs:pattern value="([A-Z]+[a-zA-Z0-9]*[.])*[A-Z]+[a-zA-Z0-9]*"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="MUReferenceName">
<xs:restriction base="MUString">
<xs:pattern value="([A-Z]+[a-zA-Z0-9]*[.])*[a-zA-Z]+[a-zA-Z0-9]*"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
detailedDesign.xml
<?xml version="1.0" encoding="UTF-8"?>
<detailedDesignModel>
<components>
<component nameRef="id1"> ... </component>
<component nameRef="id2"> ... </component>
<component nameRef="id3"> ... </component>
</components>
</detailedDesignModel>
detailedDesign.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="utilities.xsd" />
<xs:include schemaLocation="componentModel.xsd" />
<xs:complexType name="DDMComponent">
<xs:complexContent>
...
<xs:attribute name="nameRef" type="MUReferenceName" use="required" />
</xs:complexContent>
</xs:complexType>
<xs:complexType name="DDMComponents">
<xs:sequence>
<xs:element name="component" type="DDMComponent" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="DDMDetailDesignModel">
<xs:complexContent>
<xs:sequence>
<xs:element name="components" type="DDMComponents">
<xs:keyref name="componentNameKeyRef" refer="componentNameKey">
<xs:selector xpath="component" />
<xs:field xpath="#nameRef" />
</xs:keyref>
</xs:element>
</xs:sequence>
</xs:complexContent>
</xs:complexType>
<xs:element name="detailDesignModel" type="DDMDetailDesignModel" />
</xs:schema>
It works for unicity of 'name' attribute among components (error retrieved from ValidationEventHandler set on unmarshaller) :
Duplicate key value [id1] declared for identity constraint of element "components".
But i can't get the "keyref" functionnality working (error retrieved from ValidationEventHandler set on unmarshaller) :
Identity Constraint error: identity constraint "KeyRef#272ed83b" has a keyref which refers to a key or unique that is out of scope.
How can i make the keyRef to see the Key defined in the orther XSD file
Thanks
Matth

How to use condition in XSD [duplicate]

I need a required attribute or element only if a specific value of an enumeration is chosen. Example below:
<xs:element name="TYPE" type="TestEnum" />
<!-- // This Element should only required when TYPE = INTERNATIONAL -->
<xs:element name="IBAN"/>
</xs:complexType>
<xs:simpleType name="TestEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="NATIONAL"/>
<xs:enumeration value="INTERNATIONAL"/>
</xs:restriction>
</xs:simpleType>
XSD 1.1
Here's how use xs:assert to make IBAN be mandatory when TYPE = 'INTERNATIONAL':
<?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="root">
<xs:complexType>
<xs:sequence>
<xs:element name="TYPE" type="TestEnum" />
<!-- // This Element should only required when TYPE = INTERNATIONAL -->
<xs:element name="IBAN" minOccurs="0"/>
</xs:sequence>
<xs:assert test="not(TYPE = 'INTERNATIONAL') or IBAN"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="TestEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="NATIONAL"/>
<xs:enumeration value="INTERNATIONAL"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

How to add restriction to a restricted attribute in XSD

My requirement is like:
I need to validate an xml which has an element "Term" and its attributes as termType, ValueName, Value.
I need to add a restriction to termType such that, when I get the termType attribute value as "expression", the ValueName should only be IF or ELSE or THEN, and if the valueName value is "IF" the value should be "1" only.
How can I achieve this?
The xml looks like:
<Term termType="Input" value="97397D89-C044-47CC-8153-267CBBE71D29" valueName="PolicyType"/>
**<Term termType="expression" value="1" valueName="IF"/>**
<Term termType="mask" value="" valueName=""/>
Corresponding XSD I tried is:
<xs:simpleType name="termType">
<xs:restriction base="xs:string">
<xs:enumeration value="expression" />...
</xs:restriction>
</xs:simpleType>
<xs:complexType name="TermType">
<xs:attribute name="termType" use="required" type="termType" />
<xs:attribute name="value" use="required" type="xs:string" />
<xs:attribute name="valueName" use="required" type="xs:string" />
</xs:complexType>
This kind of conditional restriction is a fairly common requirement but is not supported by XSD.

Xerces reports error when giving attribute to top-level element

I have the following schema which works fine:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bindings">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="bind">
<xs:complexType>
<xs:attribute name="trigger" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute> <!-- trigger -->
<xs:attribute name="command" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute> <!-- command -->
</xs:complexType>
</xs:element> <!-- bind -->
</xs:sequence>
</xs:complexType>
</xs:element> <!-- bindings -->
</xs:schema>
However, when I try to define an attribute for the top level bindings element, I get an error no matter where I place the attribute code. What am I missing or doing wrong?
EDIT: It looks like there's some problem with either my Java XML code or Xerces. If I change the XSD to give the top-level element the optional "parent" attribute, Xerves gives me the error "Problem: schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>." However, if I give the attribute any name //other// than "parent", it reports Attribute 'parent' is not allowed to appear in element 'bindings'., just as you'd expect.
My Java code regarding XSD and Xerces is:
bindingsDocumentBuilderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilderFactory bdbf = bindingsDocumentBuilderFactory;
bdbf.setValidating(true);
// I get the input stream here as "is"
bdbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
bdbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", is);
EDIT 2:
The XML file which is being validated:
<bindings parent="game/movement">
<bind trigger="i" command="INVENTORY"/>
</bindings>
This works (see attribute named code):
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bindings">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="bind">
<xs:complexType>
<xs:attribute name="trigger" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<!-- trigger -->
<xs:attribute name="command" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<!-- command -->
</xs:complexType>
</xs:element>
<!-- bind -->
</xs:sequence>
<xs:attribute name="code"/>
</xs:complexType>
</xs:element>
<!-- bindings -->
</xs:schema>

Resources