c# XML无法正确验证XmlReaderSettings中的Schema

本文关键字:验证 XmlReaderSettings 中的 Schema XML | 更新日期: 2023-09-27 18:12:17

我搜索了,没有找到任何关于这个问题的问题。

我正在尝试根据模式验证各种XML, 它似乎正在验证所有格式良好的XML,而不仅仅是符合模式的XML。我已经发布了我正在使用的代码,Schema,一个有效的XML样本和一个无效的XML样本。

我已经为此挣扎了一段时间。我对大部分事情都不知情。我必须学习如何编写XSD,编写XSD,然后学习如何用c#解析XML。这些我都没做过。我使用了许多教程和微软网站,得出以下结论。我认为这应该可以工作,但是它没有。

我做错了什么?

private bool ValidateXmlAgainstSchema(string sourceXml, string schemaUri)
{
    bool validated = false;
    try
    {
        //  REF:
        //  This should create a SCHEMA-VALIDATING XMLREADER
        //  http://msdn.microsoft.com/en-us/library/w5aahf2a(v=vs.110).aspx
        XmlReaderSettings xmlSettings = new XmlReaderSettings();
        xmlSettings.Schemas.Add("MySchema.xsd", schemaUri);
        xmlSettings.ValidationType = ValidationType.Schema;
        xmlSettings.ValidationFlags = XmlSchemaValidationFlags.None;
        XmlReader xmlReader = XmlReader.Create(new StringReader(sourceXml), xmlSettings);
        //  parse the input (not sure this is needed)
        while (xmlReader.Read()) ;
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlReader);
        validated = true;
    }
    catch (XmlException e)
    {
        //  load or parse error in the XML
        validated = false;
    }
    catch (XmlSchemaValidationException e)
    {
        //  Validation failure in XML
        validated = false;
    }
    catch (Exception e)
    {
        validated = false;
    }
    return validated;
}

XSD/Schema。目的是接受包含Incident或PersonOfInterest的XML。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="MySchema.xsd"
    xmlns="MySchema.xsd"
    elementFormDefault="qualified"
>
  <xs:element name="Incident" type="IncidentType"/>
  <xs:element name="PersonOfInterest" type="PersonOfInterestType"/>
  <xs:complexType name="IncidentType">
    <xs:sequence>
      <xs:element name="Description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="PersonOfInterest" type="PersonOfInterestType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="PersonOfInterestType">
    <xs:sequence>
      <xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
下面是一个有效的 XML 示例
<?xml version="1.0" encoding="utf-8" ?>
  <Incident
      xmlns="MySchema.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3schools.com MySchema.xsd"
  >
    <Description>something happened</Description>
    <PersonOfInterest>
        <Name>Joe</Name>
    </PersonOfInterest>
    <PersonOfInterest>
        <Name>Sue</Name>
    </PersonOfInterest>
  </Incident>

这是一个格式良好的无效 XML示例,它应该抛出一个异常(我认为),但是当我尝试它时,代码返回true,表明它对模式有效。

<ghost>Boo</ghost>

c# XML无法正确验证XmlReaderSettings中的Schema

您的<ghost>Boo</ghost>验证的原因是解析器找不到任何与xml匹配的模式。如果没有模式,那么只要xml格式良好,解析器就假定它是有效的。我知道这是违反直觉的,并且可能会根据解析器的实现而有所不同。

尽管如此,你的代码还是有几个问题:

两个根元素

在xsd中这是一个大禁忌—您只能有一个根元素。一些解析器实际上会抛出一个异常,其他解析器会容忍它,但只会在任何后续验证中使用第一个根元素(在您的例子中是Incident)。

schemaLocation属性

应该取值(namespace) (URI),其中名称空间是模式的targetNamespace, URI是模式的位置。在您的示例中,您似乎正在使用模式文件名作为目标名称空间。此外,看看您的代码,您正在将模式加载到xml阅读器中,因此实际上根本不需要schemaLocation属性。这是一个可选属性,有些解析器完全忽略它。

我建议做以下修改:

<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://MyMoreMeaningfulNamespace"
    xmlns="http://MyMoreMeaningfulNamespace"
    elementFormDefault="qualified"
>
  <xs:element name="Root">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="Incident" type="IncidentType"/>
        <xs:element maxOccurs="unbounded" name="PersonOfInterest" type="PersonOfInterestType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="IncidentType">
    <xs:sequence>
      <xs:element name="Description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="PersonOfInterest" type="PersonOfInterestType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="PersonOfInterestType">
    <xs:sequence>
      <xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

验证这个实例

<Root xmlns="http://MyMoreMeaningfulNamespace">
  <Incident>
    <Description>something happened</Description>
    <PersonOfInterest>
      <Name>Joe</Name>
    </PersonOfInterest>
    <PersonOfInterest>
      <Name>Sue</Name>
    </PersonOfInterest>
  </Incident>
  <Incident>
    ...
  </Incident>
  <PersonOfInterest>
    <Name>Manny</Name>
  </PersonOfInterest>
  <PersonOfInterest>
    ...
  </PersonOfInterest> 
</Root>

只是补充一下,您可以启用警告:

xmlSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;

所以你可以得到一个消息的条目,如<ghost>Boo</ghost>