xml
XSD 1.1 - Alternative Test Xpath on Child Element
Im trying to use the XSD 1.1 framework to test that the child element of the current scope element contains an attribute. If true I want one schema validation for the element, if false i want another. Example XML <!-- XML 1 --> <GrandParent name="Sam"> <Parent name="Kevin"> <Child name="Kyle" id="10" dob="1989-05-02"/> </Parent> </GrandParent> <!-- XML 2 --> <GrandParent name="Sam"> <Parent name="Kevin" id="10" dob="1975-10-11"/> </GrandParent> XSD 1.1 used for above xml examples <?xml version="1.0" encoding="utf-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" > <xs:element name="GrandParent"> <xs:complexType> <xs:sequence> <xs:element ref="Parent" /> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required" /> </xs:complexType> </xs:element> <xs:element name="Parent"> <xs:alternative test="./Child/#id" type="ParentType1" /> <xs:alternative type="ParentType2" /> </xs:element> <xs:element name="Child"> <xs:complexType> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="id" type="xs:integer" use="required" /> <xs:attribute name="dob" type="xs:date" use="required" /> </xs:complexType> </xs:element> <xs:complexType name="ParentType1"> <xs:sequence> <xs:element ref="Child" /> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="ParentType2"> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="id" type="xs:integer" use="required" /> <xs:attribute name="dob" type="xs:date" use="required" /> </xs:complexType> </xs:schema> Im using Xerces xsd 1.1 validation functionality XSD Validation Error XML 1 [Error] 1:46: cvc-complex-type.4: Attribute 'id' must appear on element 'Parent'. [Error] 1:46: cvc-complex-type.4: Attribute 'dob' must appear on element 'Parent'. [Error] 1:100: cvc-complex-type.2.1: Element 'Parent' must have no character or element information item [children], because the type's content type is empty. XML 2 Validates The Xpath doesn't seem wrong to me, i've tried a few variations including //Child/#id and boolean(Child/#id) but no joy. I dont care what the value of the attribute is, only that it exists in the child element. Update Thanks to the answer below provided by Michael Kay, I rewrote my schema use asserts instead of alternatives. Here is the updated schema: <?xml version="1.0" encoding="utf-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="GrandParent"> <xs:complexType> <xs:choice> <xs:element ref="Parent" /> </xs:choice> <xs:attribute name="name" type="xs:string" use="required" /> </xs:complexType> </xs:element> <xs:element name="Child"> <xs:complexType> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="id" type="xs:integer" use="required" /> <xs:attribute name="dob" type="xs:date" use="required" /> </xs:complexType> </xs:element> <xs:element name="Parent"> <xs:complexType> <xs:sequence> <xs:element ref="Child" minOccurs="0"/> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="id" type="xs:integer" use="optional" /> <xs:attribute name="dob" type="xs:date" use="optional" /> <xs:assert test="if (Child/#id) then not(#id or #dob) else (#id and #dob and not(Child))"/> </xs:complexType> </xs:element> </xs:schema> The schema seems to work much better, I tested it with the following XML all of which passed or failed as expected PASS <GrandParent name="Sam"><Parent name="Kevin"><Child name="Kyle" id="10" dob="1989-05-02"/></Parent></GrandParent> PASS <GrandParent name="Sam"><Parent name="Kevin" id="10" dob="1975-10-11"/></GrandParent> FAIL <GrandParent name="Sam"><Parent name="Kevin" id="10"/></GrandParent> FAIL <GrandParent name="Sam"><Parent name="Kevin" dob="1975-10-11"/></GrandParent> FAIL <GrandParent name="Sam"><Parent name="Kevin"/></GrandParent>
The condition tests in a type alternative construct can only access attributes of the element in question, not children or descendants. The way this is achieved in the spec is by defining that the XPath expression is evaluated against a data model instance constructed as a shallow copy of the element being validated, where the shallow copy includes copies of attributes but not of children. As a result, attempting to access a child doesn't give an error, it just gives false. The reason for the restriction is to avoid the problems that could occur if you have to look at invalid data in order to determine whether it is invalid: you can easily end up with a liar's paradox. For this validation you need the more general capability of assertions, rather than type alternatives.
Related Links
rearranging of XML elements and extracting relevant data from its values
XML Interpreter
XML UTF-8 encoding what is the correct way to represent the non-ascii data
XLINQ: string vs Convert.ToString() when extracting element values
Scala, combining filters on XML node
XML digital signature - wrongly computed digest
Zoho API inserRecord using Curl and XML, not returning an error and not adding the “Potential”
Magento - Move cart dropdown plugin to top.links. Reference name=“top.Links” not changing location
Read an include file using XSL
Convert flat xml string to tree structure
Why is JSON more lightweight than XML?
Adding a Large XML Element to an XML File Always Fails
How to extract day-of-the-week from datetime format from XML document
How to convert rows of a database query to a XML file?
convert string in to encoded xml document
Merge 2 XML files with matching 'id' attribute using XSLT