我正在为我正在进行的项目编写 XSD 架构。下面的架构是我从一个微软示例中提取并稍作修改的架构。
我正在尝试使用 key 和 keyref 为一组项目声明一个唯一的键,然后在另一部分中引用该键。
我无法让它工作很长时间。我会编写模式并设置一个测试文档,该文档应该无法通过验证,因为 (1) 重复键和 (2) refkeys 引用不存在的键,但它一直通过。
在对一个示例进行了大量的修改和修改之后,我让它开始工作了。因此,我试图将其缩小到在示例中起作用但导致它在我最初的尝试中不起作用的范围。
我正在使用 .NET XmlDocument 和 XmlSchema 进行验证。我将在底部粘贴我的测试验证代码。
我的问题是,为什么 key 在如下声明时有效,但在评论中声明时无效?
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>
验证码:
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));
}
最佳答案
我不是 100% 确定,但我非常有把握的猜测是 selector
元素中的 XPath 表达式不关心目标命名空间,只关心你用 声明的命名空间>xmlns
属性。因此,由于您尚未声明默认命名空间,它会尝试确保任何命名空间中的元素 part
都是唯一的。由于文档中的 part
元素似乎在 namespace1
命名空间中,因此您没有任何 part
元素在任何命名空间中,所以此唯一性约束成功。
您可以通过将属性 xmlns="namespace1"
添加到您的 schema
元素来验证我的猜测。 (因为架构文档中的所有元素都有前缀,这是您唯一需要做的事情。)如果您注释掉的 key
元素可以正常工作,这似乎是正确的解释。
编辑: 好的,我找到了答案。结果是,在 XPath 1.0 中,当您有一个无前缀的名称时,它会被自动解释为不在命名空间中。无法在 XPath 1.0 中设置默认 namespace ,因此当它们位于某些 namespace 中时,您始终需要在 XPath 表达式中为所有名称添加前缀。因此,无论您是否在架构文档中声明了默认命名空间,注释掉的 key
定义都会尝试匹配没有命名空间的名称,这与您的文档不匹配。
关于.net - 在 xsd 中使用 key 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1545101/