Reputation: 11
I've made an XSD for a project, and this XSD should be able to catch errors related to missing structures on XML code but that's not the case. For example, when I try to validate an incorrect XML like:
<Course number="1">
<Subject idSub="s8" type="core">
<Name>PII</Name>
<Student>
<Name>John White</Name>
<ID>12345601A</ID>
<Grade>9.27</Grade>
</Student>
</Subject>
</Course>
where parent element Degree
and its subelements Name
and Scope
are missing, validator informs me that XML is valid when it should be wrong.
I've already tried to create a parent class as:
<xsd:element name="Degrees">
<xs:complexType>
<xs:sequence>
<xs:element ref="Degree" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xsd:element>
but it seems that does nothing.
This is an example of a valid XML:
<Degree location="London">
<Name>Industrial Engineering</Name>
<Scope>technology</Scope>
<Course number="1">
<Subject idSub="ts1" type="core">
<Name>Thermodynamics</Name>
<Student>
<Name>Michael Williams</Name>
<ID>89345601A</ID>
<Grade>7.37</Grade>
</Student>
</Subject>
</Course>
</Degree>
Here is of my full XSD code:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Degree">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element ref="Scope"/>
<xsd:element ref="Course" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="location" use="optional">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="London"/>
<xsd:enumeration value="Oxford"/>
<xsd:enumeration value="Cambridge"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="Scope">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="humanities"/>
<xsd:enumeration value="science"/>
<xsd:enumeration value="technology"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Course">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="Subject" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="number" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:pattern value="[1-4]{1}" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
<xsd:unique name="IDSubUnique">
<xsd:selector xpath="./Subject" />
<xsd:field xpath="@idSub" />
</xsd:unique>
</xsd:element>
<xsd:element name="Subject">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element ref="Student" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="type" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="core" />
<xsd:enumeration value="specialty" />
<xsd:enumeration value="optional" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="idSub" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="Student">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:choice>
<xsd:element ref="ID" minOccurs="0"/>
<xsd:element ref="Resident" minOccurs="0"/>
</xsd:choice>
<xsd:element ref="Grade"/>
<xsd:element ref="EAML" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="StudentAddress" use="optional">
<xsd:simpleType>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="ID">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{8}[A-Z]{1}"></xsd:pattern>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Resident">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{1}[0-9]{7}"></xsd:pattern>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Grade">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="EAML" type="xsd:anyURI"/>
</xsd:schema>
Upvotes: 1
Views: 225
Reputation: 163458
It's part of the philosophy of XSD - and this has been much criticised - that the schema defines the validity of elements, not of documents. If an element is valid against the schema, and the element is the root element of the document, then the document is considered valid.
Some schema processors give you an API that allows you to say, when requesting validation, what element declaration you want the root to be valid against. For example, with the Saxon XSD validator invoked from the command line, you could use the option -top:Degree to say that the outermost element must be valid against the declaration of Degree
. (Note, it doesn't actually have to be named Degree
, it can be a member of the substitution group of Degree
). If your processor doesn't offer that option, then complaining to the vendor isn't likely to do much good, and you'll have to adopt some different strategy for checking the outermost element.
If you look at the XSD spec, it says (in §5.2)
Three primary approaches to this are possible:
1 The user or application identifies a complex type definition from among the {type definitions} of the schema, and appeals to Schema-Validity Assessment (Element) (§3.3.4) (clause 1.2);
2 The user or application identifies a element declaration from among the {element declarations} of the schema, checks that its {name} and {target namespace} match the [local name] and [namespace name] of the item, and appeals to Schema-Validity Assessment (Element) (§3.3.4) (clause 1.1);
3 The processor starts from Schema-Validity Assessment (Element) (§3.3.4) with no stipulated declaration or definition, and either ·strict· or ·lax· assessment ensues, depending on whether or not the element information and the schema determine either an element declaration (by name) or a type definition (via xsi:type) or not.
That is, you either say (1) I want the root to be valid against type T, (2) I want the root to be valid against element declaration E, or (3) I want the root to be valid against something in this schema, and I don't care what.
Unfortunately many processors only seem to offer (3).
Upvotes: 0
Reputation: 111686
When an element such as Course
is defined globally in XSD (as is done in the Salami Slice Design you've adopted), it may appear as the root element of an XML document. Ways of prohibiting this include the redesigning the XSD or using implementation-dependent validation options:
Nest the non-local element declarations (Russian Doll Design):
Replace
<xsd:element name="Degree">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="Course" minOccurs="1" maxOccurs="unbounded"/>
...
with
<xsd:element name="Degree">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Course">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="Subject" maxOccurs="unbounded"/>
...
Notice that the declaration of Course
has been migrated from having global to having local scope.
Nest the non-local element declarations but declare types globally (Venetian Blind Design).
Rely on implementation-dependent validation options such as is given by Saxon's schema validator's -top:Degree
parameter.
Upvotes: 1