XSD Unique Implementation and XPath
-
Firstly, if anyone could send me a link that explains everything that is allowed in XSD xpath expressions, I would be very grateful. I have searched for hours, and still have no idea what subset of xpath is allowed for either the selector or the field nodes. Great thanks to anyone who knows where I can find some documentation on this feature of xsd. On to my problem... I am attempting to have an element, "parent", that contains a key attribute called "key". Every such element may have 0 or more child elements, called "Child", such that they contain a keyref attribute called "key" as well. I am wondering if there is a way to enforce through the XSD that the value of "key" for the child elements cannot be equivalent to the value of "key" for the parent node. So, for example: <!-- XSD File -->
<xsd:element name="Example" type="ExampleType">
<xsd:key name="ParentKey">
<xsd:selector xpath="Parent"/>
<xsd:field xpath="@key" />
</xsd:key>
<xsd:keyref name="ChildKeyRef" refer="ParentKey">
<xsd:selector xpath="Parent/Child"/>
<xsd:field xpath="@key" />
</xsd:keyref>
</xsd:element><xsd:complexType name="ExampleType">
xsd:sequence
<xsd:element name="Parent" type="ParentType" maxOccurs="unbounded">
<!-- This unique portion is where I need the help. It almost works in that it prevents me from
giving a child element the parent's key, but it also has the unfortunate side effect of not
allowing me to have duplicate key references in the child elements. How can this be done? -->
<xsd:unique name="UniqueKeyRef">
<xsd:selector xpath=".|Child"/>
<xsd:field xpath="@key" />
</xsd:unique>
</xsd:element>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ParentType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
xsd:sequence
<xsd:element name="Child" type="ChildType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ChildType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
</xsd:complexType><-- XML File -->
<Example>
<Parent key="A">
<Child key="B"/> -
Firstly, if anyone could send me a link that explains everything that is allowed in XSD xpath expressions, I would be very grateful. I have searched for hours, and still have no idea what subset of xpath is allowed for either the selector or the field nodes. Great thanks to anyone who knows where I can find some documentation on this feature of xsd. On to my problem... I am attempting to have an element, "parent", that contains a key attribute called "key". Every such element may have 0 or more child elements, called "Child", such that they contain a keyref attribute called "key" as well. I am wondering if there is a way to enforce through the XSD that the value of "key" for the child elements cannot be equivalent to the value of "key" for the parent node. So, for example: <!-- XSD File -->
<xsd:element name="Example" type="ExampleType">
<xsd:key name="ParentKey">
<xsd:selector xpath="Parent"/>
<xsd:field xpath="@key" />
</xsd:key>
<xsd:keyref name="ChildKeyRef" refer="ParentKey">
<xsd:selector xpath="Parent/Child"/>
<xsd:field xpath="@key" />
</xsd:keyref>
</xsd:element><xsd:complexType name="ExampleType">
xsd:sequence
<xsd:element name="Parent" type="ParentType" maxOccurs="unbounded">
<!-- This unique portion is where I need the help. It almost works in that it prevents me from
giving a child element the parent's key, but it also has the unfortunate side effect of not
allowing me to have duplicate key references in the child elements. How can this be done? -->
<xsd:unique name="UniqueKeyRef">
<xsd:selector xpath=".|Child"/>
<xsd:field xpath="@key" />
</xsd:unique>
</xsd:element>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ParentType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
xsd:sequence
<xsd:element name="Child" type="ChildType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ChildType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
</xsd:complexType><-- XML File -->
<Example>
<Parent key="A">
<Child key="B"/> -
Firstly, if anyone could send me a link that explains everything that is allowed in XSD xpath expressions, I would be very grateful. I have searched for hours, and still have no idea what subset of xpath is allowed for either the selector or the field nodes. Great thanks to anyone who knows where I can find some documentation on this feature of xsd. On to my problem... I am attempting to have an element, "parent", that contains a key attribute called "key". Every such element may have 0 or more child elements, called "Child", such that they contain a keyref attribute called "key" as well. I am wondering if there is a way to enforce through the XSD that the value of "key" for the child elements cannot be equivalent to the value of "key" for the parent node. So, for example: <!-- XSD File -->
<xsd:element name="Example" type="ExampleType">
<xsd:key name="ParentKey">
<xsd:selector xpath="Parent"/>
<xsd:field xpath="@key" />
</xsd:key>
<xsd:keyref name="ChildKeyRef" refer="ParentKey">
<xsd:selector xpath="Parent/Child"/>
<xsd:field xpath="@key" />
</xsd:keyref>
</xsd:element><xsd:complexType name="ExampleType">
xsd:sequence
<xsd:element name="Parent" type="ParentType" maxOccurs="unbounded">
<!-- This unique portion is where I need the help. It almost works in that it prevents me from
giving a child element the parent's key, but it also has the unfortunate side effect of not
allowing me to have duplicate key references in the child elements. How can this be done? -->
<xsd:unique name="UniqueKeyRef">
<xsd:selector xpath=".|Child"/>
<xsd:field xpath="@key" />
</xsd:unique>
</xsd:element>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ParentType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
xsd:sequence
<xsd:element name="Child" type="ChildType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType><xsd:complexType name="ChildType">
<xsd:attribute name="key" type="xsd:String" use="required"/>
</xsd:complexType><-- XML File -->
<Example>
<Parent key="A">
<Child key="B"/>The Essential XML Quick Reference[^] is an excellent (and free) XML (+ XSD + XPath + XSLT) reference. On page 349, it defines the available XPath selectors (I'd copy them here, but it disallows copying - grrrr). However, I don't think you can do what you want with the 'unique' relation. The correctness 'uniqueness' set would be '..|.' using the Child element as the context node. But you can't do that with XML Schemas. Using the Parent as context node, there's no way to define the uniqueness set, I don't think, as there are n sets, where n==number of Child nodes. However - using Schematron[^], you can validate this rule using this Schema:
<schema xmlns="http://www.ascc.net/xml/schematron" >
<pattern name="Check CHild/Parent keys">
<rule context="Child">
<assert test="@key!=../@key">Child key should differ from Parent key.</assert>
<report test="@name">Child key should differ from Parent key.</report>
</rule>
</pattern>
</schema>This should be used in addition to a schema describing the basic structure of the XML. Using xmllint (which comes with libxml2), I can confirm that this Schematron schema meets your requirements. XML files can be validated against Schematron schemas using an XSLT processor, so even if your XML parser doesn't have Schematron support, you can still use Schematron.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
The Essential XML Quick Reference[^] is an excellent (and free) XML (+ XSD + XPath + XSLT) reference. On page 349, it defines the available XPath selectors (I'd copy them here, but it disallows copying - grrrr). However, I don't think you can do what you want with the 'unique' relation. The correctness 'uniqueness' set would be '..|.' using the Child element as the context node. But you can't do that with XML Schemas. Using the Parent as context node, there's no way to define the uniqueness set, I don't think, as there are n sets, where n==number of Child nodes. However - using Schematron[^], you can validate this rule using this Schema:
<schema xmlns="http://www.ascc.net/xml/schematron" >
<pattern name="Check CHild/Parent keys">
<rule context="Child">
<assert test="@key!=../@key">Child key should differ from Parent key.</assert>
<report test="@name">Child key should differ from Parent key.</report>
</rule>
</pattern>
</schema>This should be used in addition to a schema describing the basic structure of the XML. Using xmllint (which comes with libxml2), I can confirm that this Schematron schema meets your requirements. XML files can be validated against Schematron schemas using an XSLT processor, so even if your XML parser doesn't have Schematron support, you can still use Schematron.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Yeah, that is what I was afraid of... I know I could do it using XSD 1.1 or, as you suggested, Schematron, but validating against either of those options isn't well supported (at least as far as I can tell) in Java or C. I actually tried what you suggested with the parent element, saw it wasn't supported, and figured that there must just be some other well-hidden way to go about it. I don't want to have a second definition file, so embedded Schematron may be the answer right now (if I can figure out how to validate against it), or I could just wait until next April when the XSD 1.1 specification is finalized. Anyway, thank you very much for the help!
Sounds like somebody's got a case of the Mondays -Jeff
-
Yeah, that is what I was afraid of... I know I could do it using XSD 1.1 or, as you suggested, Schematron, but validating against either of those options isn't well supported (at least as far as I can tell) in Java or C. I actually tried what you suggested with the parent element, saw it wasn't supported, and figured that there must just be some other well-hidden way to go about it. I don't want to have a second definition file, so embedded Schematron may be the answer right now (if I can figure out how to validate against it), or I could just wait until next April when the XSD 1.1 specification is finalized. Anyway, thank you very much for the help!
Sounds like somebody's got a case of the Mondays -Jeff
Schematron is supported by libxml2, so (therefore) is accessible to C or C++ or anything else that exposes that part of libxml2 through a binding. The Schematron website describes the steps needed to perform Schaematron validation:
xslt -stylesheet iso_dsdl_include.xsl theSchema.sch > theSchema1.sch
xslt -stylesheet iso_abstract_expand.xsl theSchema1.sch > theSchema2.sch
xslt -stylesheet iso_svrl_for_xsltn.xsl theSchema2.sch > theSchema.xsl
xslt -stylesheet theSchema.xsl myDocument.xml > myResult.xmlBasically, generate an XSLT file from your Schematron schema (the first three steps). Then process the input XML file using your XSLT processor and the generated XSLT file to output something that tells you if the XML is valid per the Schematron schema.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p