【问题标题】:xs:key, why is validation passing when key value is not member of key reference?xs:key,为什么当键值不是键引用的成员时验证通过?
【发布时间】:2010-05-18 21:19:28
【问题描述】:

我有兴趣在我的 Xsd 中定义一个键约束。 It is my understanding that using xs:key should constrain the value used to a member of a referenced list of values.

假设我们使用的是样本 Xsd,

<xs:schema
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        targetNamespace="namespace1"
        xmlns:r="namespace1"
        elementFormDefault="qualified">

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>

        <xs:element name="A" type="r:A" 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:B"/>

      </xs:sequence>
    </xs:complexType>

    <xs:key name="pNumKey">
      <xs:selector xpath="r:B/r:part"/>
      <xs:field xpath="@key-number"/>
    </xs:key>

  </xs:element>

  <xs:complexType name="A">
    <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="B">
    <xs:sequence>
      <xs:element name="part" maxOccurs="unbounded">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute name="key-number" type="xs:integer"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

样本 Xml,

<root xmlns="namespace1">
  <A>
    <!-- 
      if the ref-number is not equal to one of the key-number, 
      the validation will give error 
    -->
    <part ref-number="1"/>
  </A>
  <A>
    <!-- 
      if the ref-number is not equal to one of the key-number, 
      the validation will give error 
    -->
    <part ref-number="2"/>
  </A>
  <B>
    <part key-number="1"/>
    <part key-number="2"/>
    <part key-number="3"/>
  </B>
</root>

比如说,一些简单的验证

[TestMethod]
public void Test_Schema()
{
    string schemaFileName = @"sampleSchema.xsd";
    string xmlFileName = @"sampleXml.xml";
    XmlReaderSettings settings = new XmlReaderSettings
    {
        ValidationType = ValidationType.Schema,
        ValidationFlags = 
            XmlSchemaValidationFlags.ProcessInlineSchema |
            XmlSchemaValidationFlags.ProcessSchemaLocation | 
            XmlSchemaValidationFlags.ReportValidationWarnings,
    };
    settings.Schemas.Add (schema);
    settings.ValidationEventHandler += 
        (o, e) => { throw new Exception("CRASH"); };

    XmlSchema schema = 
        XmlSchema.Read (
        File.OpenText (schemaFileName), 
        (o, e) => { throw new Exception ("BOOM"); });

    XmlReader reader = XmlReader.Create (xmlFileName, settings);
    while (reader.Read ()) { }
}

怎么回事,当我对A/part[@ref-number] 使用错误值时,验证仍然成功?

<root xmlns="namespace1">
  <A>
    <!-- doesn't go CRASH BOOM bang! why not? :( -->
    <part ref-number="5"/>
  </A>
  <B>
    <part key-number="1"/>
    <part key-number="2"/>
    <part key-number="3"/>
  </B>
</root>

上面的 Xsd、Xml 或验证是否有任何一项或全部不正确?还是我误解了xs:key 的预期目的?

【问题讨论】:

    标签: c# .net xsd xsd-validation


    【解决方案1】:

    像往常一样,经过一夜的休息和焕然一新的面貌,在这次练习中发现不少于 2 个错误

    1. 第一个错误,验证身份约束是一个显式过程,由XmlReaderSettings.ValidationFlag 设置的XmlSchemaValidationFlags.ProcessIdentityConstraints 引发,并且
    2. 第二个错误,msdn sample 包含架构错误,&lt;xs:selector xpath="part"/&gt; 应为 &lt;xs:selector xpath="r:part"/&gt;

    完整的工作示例如下,

    <xs:schema
            xmlns:xs="http://www.w3.org/2001/XMLSchema"
            targetNamespace="namespace1"
            xmlns:r="namespace1"
            elementFormDefault="qualified">
      <xs:element name="root">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="A" type="r:A" maxOccurs="unbounded">
              <xs:keyref name="dummy" refer="r:pNumKey">
                <!-- without 'r:' below, key was not recognized, boo-urns msdn! -->
                <xs:selector xpath="r:part"/>
                <xs:field xpath="@ref-number"/>
              </xs:keyref>
            </xs:element>
            <xs:element name="B" type="r:B"/>
          </xs:sequence>
        </xs:complexType>
        <xs:key name="pNumKey">
          <xs:selector xpath="r:B/r:part"/>
          <xs:field xpath="@key-number"/>
        </xs:key>
      </xs:element>
    
      <xs:complexType name="A">
        <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="B">
        <xs:sequence>
          <xs:element name="part" maxOccurs="unbounded">
            <xs:complexType>
              <xs:simpleContent>
                <xs:extension base="xs:string">
                  <xs:attribute name="key-number" type="xs:integer"/>
                </xs:extension>
              </xs:simpleContent>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
    

    Xml 样本

    <root xmlns="namespace1">
      <A>
        <!-- goes CRASH BOOM bang! failure for the win! -->
        <part ref-number="5"/>
      </A>
      <B>
        <part key-number="1"/>
        <part key-number="2"/>
        <part key-number="3"/>
      </B>
    </root>
    

    简单的验证器

    [TestMethod]
    public void Test_Schema()
    {
        string schemaFileName = @"sampleSchema.xsd";
        string xmlFileName = @"sampleXml.xml";
    
        XmlSchema schema = 
            XmlSchema.Read(
            File.OpenText(schemaFileName), 
            (o, e) => { throw new Exception("BOOM"); });
    
        XmlReaderSettings settings = new XmlReaderSettings
        {
            ValidationType = ValidationType.Schema,
            ValidationFlags = 
                XmlSchemaValidationFlags.ProcessInlineSchema | 
                XmlSchemaValidationFlags.ProcessSchemaLocation | 
                XmlSchemaValidationFlags.ReportValidationWarnings | 
    
                // d'oh! explicit flag for processing identity constraints!
                XmlSchemaValidationFlags.ProcessIdentityConstraints,
        };
        settings.Schemas.Add(schema);
        settings.ValidationEventHandler += 
            (o, e) => { throw new Exception("CRASH"); };
    
        XmlReader reader = XmlReader.Create(xmlFileName, settings);
        while (reader.Read()) { }
    }
    

    【讨论】:

    • ProcessIdentityConstraints根据MSDN默认开启。来自System.Xml.Schema 的扩展方法XDocument.Load(inputXmlPath).Validate(schemas, null) 工作得很好。
    【解决方案2】:

    我猜你应该使用 ValidationEventHandler :

    settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
    
    private static void ValidationCallBack (object sender, ValidationEventArgs args) {}
    

    【讨论】:

    • 不错的猜测,但不是。仍然通过验证。修改了我的帖子,在设置对象上包含了一个明确的验证事件处理程序。
    猜你喜欢
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 2019-11-24
    • 2018-08-22
    相关资源
    最近更新 更多