我正在为我正在开发的项目编写XSD架构。下面的模式是我从微软示例中获取的模式,并略有修改。
我正在尝试使用key和keyref为一组项目声明一个唯一键,然后在另一个部分中引用该键。
我无法让它长时间工作。我会编写架构并设置一个测试文档,该文档应该通过验证失败,因为(1)重复键和(2)引用不存在键但不断传递的refkeys。
经过一系列的修补工作和一个例子,我得到了它的工作。因此,我试图将其缩小到示例中的功能,但导致它在我原来的尝试中无效。
我正在验证使用.NET XmlDocument和XmlSchema。我会将测试验证代码粘贴在底部。
我的问题是,为什么关键的工作如果声明它在下面,但如果在评论中声明它就不起作用?
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));
}
答案 0 :(得分:7)
我不是百分百肯定,但我非常自信地猜测selector
元素中的XPath表达式并不关心目标命名空间,只关注您使用xmlns
声明的命名空间属性。因此,由于您尚未声明默认命名空间,因此它会尝试确保无命名空间中的元素part
是唯一的。由于文档中的part
元素似乎位于namespace1
命名空间中,因此没有任何名称空间中没有part
元素,因此此唯一性约束成功。
您可以通过在schema
元素中添加属性xmlns="namespace1"
来验证我的猜测。 (由于架构文档中的所有元素都有前缀,因此这是您唯一需要做的事情。)如果您的注释掉的key
元素有效,那么这似乎是正确的解释。
编辑:好的,我找到了答案。事实证明,在XPath 1.0中,当您拥有一个非前缀名称时,它会被自动解释为没有名称空间。无法在XPath 1.0中设置默认命名空间,因此当它们位于某个命名空间中时,您始终需要在XPath表达式中为所有名称添加前缀。因此,无论您是否在架构文档中声明了默认命名空间,注释掉的key
定义都会尝试匹配无命名空间中的名称,这与您的文档不匹配。