xs:key,当键值不是键引用的成员时,为什么验证通过?

时间:2010-05-18 21:19:28

标签: c# .net xsd xsd-validation

我有兴趣在我的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的预期目的?

2 个答案:

答案 0 :(得分:4)

像往常一样,经过一夜安眠和新面貌,在这次练习中发现了不少于 2个错误

  1. 第一个错误,验证身份约束是一个明确的过程,由XmlSchemaValidationFlags.ProcessIdentityConstraints设置的XmlReaderSettings.ValidationFlag引起,
  2. 第二个错误,msdn sample包含架构中的错误,<xs:selector xpath="part"/>应该读取<xs:selector xpath="r:part"/>
  3. 完整的工作样本如下,

    <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()) { }
    }
    

答案 1 :(得分:0)

我想你应该使用ValidationEventHandler:

settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);

private static void ValidationCallBack (object sender, ValidationEventArgs args) {}