I am trying to add an assertion to a XSD (1.1) schema that will check an element's attribute for equality against its children element's value.
I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<CarList Maker="Tesla">
<Car>
<Year>2010</Year>
<Color>Blue</Color>
<Price>40000</Price>
<Maker>Tesla</Maker>
</Car>
<Car>
<Year>2011</Year>
<Color>White</Color>
<Price>20000</Price>
<Maker>Tesla</Maker>
</Car>
<Car>
<Year>2012</Year>
<Color>Black</Color>
<Price>55000</Price>
<Maker>Tesla</Maker>
</Car>
</CarList>
I want to make sure that the Maker
attribute of the CarList
element is the only maker used in the subsequent Car elements. I use XSD 1.1 so I tried to do it with an xs:assert
as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1">
<xs:element name="Year" type="xs:positiveInteger"/>
<xs:element name="Color" type="xs:string"/>
<xs:element name="Price" type="xs:positiveInteger"/>
<xs:element name="Maker" type="MakerType"/>
<xs:simpleType name="MakerType">
<xs:restriction base="xs:string">
<xs:enumeration value="Tesla"/>
<xs:enumeration value="GM"/>
<xs:enumeration value="Ford"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="Car">
<xs:complexType>
<xs:sequence>
<xs:element ref="Year"/>
<xs:element ref="Color"/>
<xs:element ref="Price"/>
<xs:element ref="Maker"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CarList">
<xs:complexType>
<xs:sequence>
<xs:element ref="Car" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="Maker" type="MakerType" use="required"/>
<xs:assert test="Car/Maker eq @Maker"/>
</xs:complexType>
</xs:element>
</xs:schema>
but when I try to validate it (using python xmlschema library) I get the following error:
'/' operator at line 1, column 4: [err:XPTY0004] atomized operand is a sequence of length greater than one
It seems like there is an error with the XPath format of the test
attribute in the xs:assert
element, more specifically with the way I try to access the sub element Maker
of the Car
element.
What am I doing wrong? any idea how can I accomplish this assertion?
The Car/Maker
XPath in your xs:assert
is selecting multiple elements, which cannot be compared directly against an attribute value, @Maker
.
To fix, change your xs:assert
from
<xs:assert test="Car/Maker eq @Maker"/>
to
<xs:assert test="every $maker in Car/Maker satisfies $maker eq @Maker"/>