使用XSD进行XML验证:未声明属性。但它是 - 见例子

时间:2013-12-10 11:07:52

标签: c# xml xsd xsd-validation

我遇到了针对架构验证XML的问题。简化的代码和示例:

验证码:

    public static void ValidateXmlAgainstSchema(StreamReader xml, XmlSchema xmlSchema)
    {
        var settings = new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true };
        settings.Schemas.Add(xmlSchema);

        settings.ValidationType = ValidationType.Schema;
        settings.ValidationEventHandler += (obj, args) => { if (args.Exception != null) throw args.Exception; };

        using (var reader = XmlReader.Create(xml, settings))
        using (XmlReader validatingReader = XmlReader.Create(reader, settings))
        {
            while (validatingReader.Read()){}
        }
    }

架构:

  <?xml version="1.0"?>
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://foo.com/"
           xmlns="http://foo.com/">

  <xs:simpleType name="myBool">
    <xs:restriction base="xs:string">
      <xs:enumeration value="true"/>
      <xs:enumeration value="false"/>
      <xs:enumeration value="file_not_found"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="dataType">
    <xs:sequence>
      <xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1" />
      <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>

  <xs:element name="foo">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="data" type="dataType" minOccurs="0" maxOccurs="unbounded" />
      </xs:sequence>
      <xs:attribute name="myBool" type="myBool" use="optional" />
    </xs:complexType>
  </xs:element>

</xs:schema>

XML:

1

<?xml version="1.0"?>
<foo xmlns="http://foo.com/" myBool="true">
  <data>
    <id>1</id>
    <name>abc</name>
  </data>
</foo>

此示例抛出异常:

System.Xml.Schema.XmlSchemaValidationException:名称空间“http://foo.com/”中的元素“foo”具有无效的子元素“数据” 在命名空间“http://foo.com/”中。预期可能元素列表:'数据'。

我的理解是,如果为元素定义了名称空间,除非另外定义,否则所有子元素都将具有相同的名称空间。它不起作用。我可以通过将elementFormDefault =“qualified”添加到模式来使其验证,这使得所有元素都默认为targetNamespace。这是一个很好的方式吗?

2

<?xml version="1.0"?>
<a:foo xmlns:a="http://foo.com/" a:myBool="true">
  <a:data>
    <a:id>1</a:id>
    <a:name>abc</a:name>
  </a:data>
</a:foo>

此示例失败,并显示以下消息:

未声明“http://foo.com/:myBool”属性。

每个元素和属性都有一个显式的命名空间,因此xml应该是有效的。甚至错误消息也表明解析器正在寻找我期望它的属性,但却找不到它。我可以通过将myBool更改为myBool来使其验证。为什么它不以第一种形式起作用而在另一种形式起作用?

1 个答案:

答案 0 :(得分:1)

elementFormDefault无法对属性做任何事情,为您需要的人attributeFormDefault设置等值。但是,默认情况下,这两个都设置为&#34;不合格&#34;。

原因方法2 - a:myBool="true" - 失败是因为attributeFormDefault值未被覆盖。如果要命名空间属性,可以将其设置为&#34; qualified&#34; 将属性声明本身的form属性设置为&#34; qualified&#34;,如下所示:

<xs:attribute name="myBool" type="myBool" use="optional" form="qualfied"/>

这应该使这成为方法2的有效元素开始:

<a:foo xmlns:a="http://foo.com/" a:myBool="true">

至于为什么方法1失败,我不确定,你的XSD和XML匹配。可能值得添加将根XSD元素上的attributeFormDefault属性设置为&#34;不合格&#34;,以防万一XSLT引擎在它们不是时不识别它们的默认设置声明。像这样:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
       targetNamespace="http://foo.com/"
       attributeFormDefault="unqualified"
       xmlns="http://foo.com/">