【问题标题】:Why is XmlReader not validating restriction constraint为什么 XmlReader 不验证限制约束
【发布时间】:2014-02-10 17:25:06
【问题描述】:

我正在尝试使用架构验证 xml 字符串,但遇到了一个问题,即它无法使用 facets 识别 xsd 中的限制。我创建了一个单元测试,在其中将对象序列化为 xml,使用我的模式验证 xml 并将 xml 反序列化回对象。一切都很好,但由于某种原因,当我的纬度在架构中指定的范围内时,我没有收到错误。我已经定义了一个纬度在 -90 到 90 之间,但是当我超出界限时我没有收到错误。这是我序列化后得到的xml:

<?xml version="1.0" encoding="utf-8"?>
<Messages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Message>    
    <Blocks>
      <Location>
        <Latitude>110.5</Latitude>
        <Longitude>11.5</Longitude>
        <IsValid>true</IsValid>
        <PrecisionKilometers>1</PrecisionKilometers>
      </Location>      
    </Blocks>
  </Message>  
</Messages>

我正在使用的架构如下所示。与纬度相关的部分在中间。 (我知道这有点难看,我正试图让他们优化他们的架构生成代码)

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:VL="http://customUri" elementFormDefault="qualified" targetNamespace="http://customUri" id="MessageList" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Messages">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="unbounded" name="Message" nillable="true">
          <xs:complexType>
            <xs:sequence>
              <xs:element minOccurs="1" maxOccurs="unbounded" name="Blocks">
                <xs:complexType>
                  <xs:all>

                    <xs:element minOccurs="0" maxOccurs="1" name="Location" nillable="true">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element minOccurs="1" maxOccurs="1" name="Latitude">
                            <xs:simpleType>
                              <xs:restriction base="xs:double">
                                <xs:minInclusive value="-90" />
                                <xs:maxExclusive value="90" />
                              </xs:restriction>
                            </xs:simpleType>
                          </xs:element>
                          <xs:element minOccurs="1" maxOccurs="1" name="Longitude">
                            <xs:simpleType>
                              <xs:restriction base="xs:double">
                                <xs:minInclusive value="-180" />
                                <xs:maxExclusive value="180" />
                              </xs:restriction>
                            </xs:simpleType>
                          </xs:element>
                          <xs:element minOccurs="1" maxOccurs="1" name="IsValid" type="xs:boolean" />
                          <xs:element minOccurs="0" maxOccurs="1" name="PrecisionKilometers" nillable="true" type="xs:double" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>

                  </xs:all>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

我读取 xml 的设置是:(请注意,我正在为 ReportValidationWarnings 和 ProcessIdentityContraints 指定标志,并使用验证处理程序来检测警告)

    var settings = new XmlReaderSettings
          {
            ValidationType = ValidationType.Schema,
            ValidationFlags =         
              XmlSchemaValidationFlags.ReportValidationWarnings |
              XmlSchemaValidationFlags.ProcessInlineSchema |
              XmlSchemaValidationFlags.ProcessSchemaLocation |
              XmlSchemaValidationFlags.ProcessIdentityConstraints |
              XmlSchemaValidationFlags.AllowXmlAttributes,
            IgnoreWhitespace = true,
            IgnoreComments = true,
          };
settings.ValidationEventHandler += (o, ex) =>
          {            
            if (ex.Severity == XmlSeverityType.Warning || ex.Severity == XmlSeverityType.Error)
            {
              //do something
            }
          };
    settings.Schemas.Add(mySchemaSet);

我用来反序列化的代码非常标准。

XmlReader reader = XmlReader.Create(memoryStreamContainingXml, settings);
var serializer = new XmlSerializer(typeof(MessageList));
MessageList returned = ser.Deserialize(reader) as MessageList;

我还尝试使用 while(reader.read(){}) 而不是反序列化来查看是否引发了验证错误,但我没有遇到任何问题。

【问题讨论】:

  • 您在哪里指定要使用的架构?
  • 另外,如果您在架构中指定 targetNamespace,XML 中的元素不应该在该命名空间内吗?
  • 要使用的架构在设置部分给出。我正在添加一个“mySchemaSet”,我正在向其中添加架构。我只是在这里省略了它,因为我不想弄乱这个问题。至于命名空间,由于我没有为我的 xml 元素指定 xmlns:target 前缀,它们将恢复为使用默认 xmlns w3.org/2001/XMLSchema"
  • 但是您在 XSD 文档中指定了目标命名空间 http://customUri。因此,XML 中默认命名空间中的 Message 元素不是 XSD 的 http://customUri 命名空间中的 Message 元素。
  • 仅供参考,您在XSD 中缺少http://customUri:Messages(复数)的元素声明。

标签: c# xml validation xsd xmlreader


【解决方案1】:

使用以下 XML 尝试您的代码:

<ns0:Messages xmlns:ns0="http://customUri">
  <ns0:Message>
    <ns0:Blocks>
      <ns0:Location>
        <ns0:Latitude>110.0</ns0:Latitude>
        <ns0:Longitude>11.5</ns0:Longitude>
        <ns0:IsValid>true</ns0:IsValid>
        <ns0:PrecisionKilometers>1</ns0:PrecisionKilometers>
      </ns0:Location>
    </ns0:Blocks>
  </ns0:Message>
</ns0:Messages>

正如 Vadim 在 cmets 中所说,您需要告诉验证器您的 XML 中的类型是模式中定义的类型。这样做的方法是在您的 XML 实例中包含架构的目标命名空间。

没有这个,验证器所能做的就是检查 XML 格式是否正确。这就是它返回有效结果的原因。

更新

【讨论】:

  • 不,当我尝试这个时它不起作用。它抛出异常 {" 不是预期的。"}
  • 是的,我在仅基于消息生成的架构上进行了尝试。我在 MessageList 上重试了这个,但遇到了类似的错误。
  • 当我根据您的架构验证上述内容时,我得到:Validation error: The 'http://customUri:Latitude' element is invalid - The value '110.0' is invalid according to its datatype 'Double' - The MaxExclusive constraint failed,这是您不想要的吗?
  • 不,我收到了{"&lt;Messages xmlns='http://customUri'&gt; was not expected."}。我也尝试将 xmlns:xsi 和 xmlns:xsd 属性添加\删除到根目录,但没有变化。
  • 那你做错了。你确定你的 XSD 就是上面的样子吗?我只是剪切并再次粘贴它,它可以工作。去utilities-online.info/xsdvalidation试试吧。我已经用截图更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 2011-01-13
  • 2010-09-22
  • 1970-01-01
  • 2017-04-26
相关资源
最近更新 更多