I’m writing an XSD schema for a project I’m working on. The schema below is one I took from a microsoft example and modified slightly.
I am trying to use the key and keyref to declare a unique key for one set of items and then refer to that key in another section.
I couldn’t get it to work for a long time. I would write the schema and setup a test doc which should fail validation because of (1) duplicate keys and (2) refkeys that refer to non-existant keys but it kept passing.
After a bunch of tinkering and working off of an example, I got it to work. So I tried to narrow it down to what worked in the example but was causing it to not work in my original attempt.
I am validating using the .NET XmlDocument and XmlSchema. I’ll paste my test validation code at the bottom.
My question is, why does the key work if declared as it is below but not work if declared as it is in the comment?
XSD:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="namespace1"
xmlns="namespace1"
xmlns:r="namespace1"
elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="A" type="r:AType" maxOccurs="unbounded">
<xs:keyref name="dummy" refer="r:pNumKey">
<xs:selector xpath="part"/>
<xs:field xpath="@ref-number"/>
</xs:keyref>
</xs:element>
<xs:element name="B" type="r:BType"/>
</xs:sequence>
</xs:complexType>
<!-- This works. -->
<xs:key name="pNumKey">
<xs:selector xpath="r:B/r:part"/>
<xs:field xpath="@key-number"/>
</xs:key>
<!--
This doesn't work.
<xs:key name="pNumKey">
<xs:selector xpath="B/part"/>
<xs:field xpath="@key-number"/>
</xs:key>
-->
</xs:element>
<xs:complexType name="AType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="ref-number" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="BType">
<xs:sequence>
<xs:element name="part" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="key-number" type="xs:integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
Vaidation Code:
private static void ValidateXml(string root, string xsdFileName, string xmlFileName)
{
ValidationEventHandler veh = new ValidationEventHandler(Program_ValidationEventHandler);
XmlSchema schema = XmlSchema.Read(new XmlTextReader(root + xsdFileName), veh);
XmlDocument xdoc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(schema);
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler +=
new ValidationEventHandler(Program_ValidationEventHandler);
XmlReader reader = XmlReader.Create(root + xmlFileName, settings);
xdoc.Load(reader);
Console.WriteLine(xdoc.SchemaInfo.Validity);
}
private static void Program_ValidationEventHandler(object sender, ValidationEventArgs e)
{
Console.WriteLine(string.Format("-Message:{0}", e.Message));
}
I’m not 100 % sure, but my pretty confident guess is that the XPath expression in the
selectorelement does not care about the target namespace, just the namespaces you’ve declared withxmlnsattributes. So, since you haven’t declared a default namespace, it tries to ensure elementspartin no namespace are unique. And since thepartelements in your document seem to be in thenamespace1namespace, you don’t have anypartelements in no namespace, so this uniqueness constraint succeeds.You can verify my guess by adding to your
schemaelement the attributexmlns="namespace1". (Since all your elements in the schema document have prefixes, this is the only thing you need to do.) If your commented-outkeyelement works then, this would seem to be the correct explanation.EDIT: Okay, I found the answer. Turns out that, in XPath 1.0, when you have a non-prefixed name, it is automatically interpreted as being in no namespace. There is no way to set the default namespace in XPath 1.0, so you always need to prefix all names in XPath expressions when they are in some namespace. So no matter whether you’ve declared a default namespace in your schema document, the commented out
keydefinition is trying to match names in no namespace, which doesn’t match your document.