I have an XML document about books:
<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<book>
<genreRef>ID000</genreRef>
</book>
<genres>
<genre xsi:type="Mystery" referenceId="ID000"/>
<genre xsi:type="Action" referenceId="ID001"/>
<genre xsi:type="Fantasy" referenceId="ID002"/>
</genres>
</books>
You can see that the <genreRef>
element points to a <genre>
element of type ‘Mystery’. That’s what I want—I want to constrain the <genreRef>
element to point exclusively to <genre>
elements of type ‘Mystery’. Pointing to a <genre>
element of type ‘Action’ or ‘Fantasy’ is an error, which I want my XSD 1.1 schema to detect.
Below is my XSD 1.1 schema. Notice the <assert>
element on the root element. The XPath expression says the <genreRef>
element in every <book>
element points to a <genre>
element with type ‘Mystery’. I confirmed that the XPath expression is correct by evaluating it in Oxygen. However, when I validate the above XML instance document against the below XSD, the SAXON schema validator reports “Element books does not satisfy assertion every $i in book satisfies some $j in genres/genre[@xsi:type = 'Mystery'] satisfies $i/genreRef eq $j/@referenceId”
What am I doing wrong? How can I fix this?
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xs:element name="books">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="genreRef" type="xs:IDREF"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="genres">
<xs:complexType>
<xs:sequence>
<xs:element name="genre" type="Genre" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:assert test="every $i in book satisfies some $j in genres/genre[@xsi:type = 'Mystery'] satisfies $i/genreRef eq $j/@referenceId" />
</xs:complexType>
</xs:element>
<xs:complexType name="Genre" abstract="true">
<xs:sequence>
</xs:sequence>
<xs:attribute name="referenceId" use="required" type="xs:ID"/>
</xs:complexType>
<xs:complexType name="Mystery">
<xs:complexContent>
<xs:extension base="Genre"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Action">
<xs:complexContent>
<xs:extension base="Genre"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Fantasy">
<xs:complexContent>
<xs:extension base="Genre"/>
</xs:complexContent>
</xs:complexType>
</xs:schema>
I think it is a type error, @xsi:type
returns a QName
, you can't compare a string to a QName, thus if you change your assert to <xs:assert test="every $i in book satisfies some $j in genres/genre[@xsi:type = QName('', 'Mystery')] satisfies $i/genreRef eq $j/@referenceId" />
you get what you want.