使用XSD进行部分XML文件验证



我正在尝试使用XDocument类和XmlSchemaSet类来验证XMl文件。

XML文件已经存在,但我只想添加一个由其他几个元素组成的元素,我只想验证这个节点。

下面是XML文件的一个示例。我想验证的部分是TestConfiguration节点:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Root>
  <AppType>Test App</AppType>
  <LabelMap>
    <Label0>
        <Title>Tests</Title>
        <Indexes>1,2,3</Indexes>
    </Label0>
  </LabelMap>
<TestConfiguration>
    <CalculateNumbers>true</CalculateNumbers>
    <RoundToDecimalPoint>3</RoundToDecimalPoint>
</TestConfiguration>
</Root>

这是我迄今为止的xsd:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="TestConfiguration"
           targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="TestConfiguration">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="CalculateNumbers" type="xs:boolean" minOccurs="1" maxOccurs="1"/>
        <xs:element name="RoundToDecimalPoint" type="xs:int" minOccurs="1" maxOccurs="1"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

这是我用来验证它的代码:

private bool ValidateXML(string xmlFile, string xsdFile)
{
    string xsdFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? string.Empty, xsdFile);
    Logger.Info("Validating XML file against XSD schema file.");
    Logger.Info("XML: " + xmlFile);
    Logger.Info("XSD: " + xsdFilePath);
    try
    {
        XDocument xsdDocument = XDocument.Load(xsdFilePath);
        XmlSchemaSet schemaSet = new XmlSchemaSet();
        schemaSet.Add(XmlSchema.Read(new StringReader(xsdDocument.ToString()), this.XmlValidationEventHandler));
        XDocument xmlDocument = XDocument.Load(xmlFile);
        xmlDocument.Validate(schemaSet, this.XmlValidationEventHandler);
    }
    catch (Exception e)
    {
        Logger.Info("Error parsing XML file: " + xmlFile);
        throw new Exception(e.Message);
    }
    Logger.Info("XML validated against XSD.");
    return true;
}

即使验证了完整的XML文件,验证也会成功通过,这会导致我在尝试将XML文件加载到由xsd2code创建的生成类文件时遇到问题,错误为:<Root xmlns=''> was not expected.

如何仅验证TestConfiguration工件?

感谢

这里有一些问题:

  1. 当整个文档应该失败时,验证它会成功。

    发生这种情况是因为根节点对架构是未知的,遇到未知节点被视为验证警告而不是验证错误,即使该未知节点是根元素。要在验证时启用警告,需要设置XmlSchemaValidationFlags.ReportValidationWarnings。但是,无法将此标志传递给XDocument.Validate()。问题XDocument。"验证总是成功的"展示了解决这一问题的一种方法。

    完成此操作后,还必须在ValidationEventArgs.Severity == XmlSeverityType.Warning时在验证处理程序中抛出异常。

    (至于在XSD中需要某个根元素,这显然是不可能的。)

  2. 您需要一种方便的方法来验证元素以及文档,这样您就可以验证<TestConfiguration>文章。

  3. 您的XSD和XML不一致。

    XSD指定元素位于targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified"行的XML命名空间MyApp_ConfigurationFiles中。事实上,问题中显示的XML元素不在任何命名空间中。

    如果XSD是正确的,那么您的XML根节点需要看起来像:

    <Root xmlns="MyApp_ConfigurationFiles">
    

    如果XML是正确的,那么XSD需要看起来像:

    <xs:schema id="TestConfiguration"
       elementFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    

在解决了#3中的XSD和XML不一致性之后,可以通过引入以下验证文档和元素的扩展方法来解决问题#1和#2:

public static class XNodeExtensions
{
    public static void Validate(this XContainer node, XmlReaderSettings settings)
    {
        if (node == null)
            throw new ArgumentNullException();
        using (var innerReader = node.CreateReader())
        using (var reader = XmlReader.Create(innerReader, settings))
        {
            while (reader.Read())
                ;
        }
    }
    public static void Validate(this XContainer node, XmlSchemaSet schemaSet, XmlSchemaValidationFlags validationFlags, ValidationEventHandler validationEventHandler)
    {
        var settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags |= validationFlags;
        if (validationEventHandler != null)
            settings.ValidationEventHandler += validationEventHandler;
        settings.Schemas = schemaSet;
        node.Validate(settings);
    }
}

然后,要验证整个文档,请执行以下操作:

try
{
    var xsdDocument = XDocument.Load(xsdFilePath);
    var schemaSet = new XmlSchemaSet();
    using (var xsdReader = xsdDocument.CreateReader())
        schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
    var xmlDocument = XDocument.Load(xmlFile);
    xmlDocument.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, XmlValidationEventHandler);
}
catch (Exception e)
{
    Logger.Info("Error parsing XML file: " + xmlFile);
    throw new Exception(e.Message);
}

要验证特定节点,可以使用相同的扩展方法:

XNamespace elementNamespace = "MyApp_ConfigurationFiles";
var elementName = elementNamespace + "TestConfiguration";
try
{
    var xsdDocument = XDocument.Load(xsdFilePath);
    var schemaSet = new XmlSchemaSet();
    using (var xsdReader = xsdDocument.CreateReader())
        schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
    var xmlDocument = XDocument.Load(xmlFile);
    var element = xmlDocument.Root.Element(elementName);
    element.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, this.XmlValidationEventHandler);
}
catch (Exception e)
{
    Logger.Info(string.Format("Error validating element {0} of XML file: {1}", elementName, xmlFile));
    throw new Exception(e.Message);
}

现在验证整个文档失败,而验证{MyApp_ConfigurationFiles}TestConfiguration节点成功,使用以下验证事件处理程序:

void XmlSchemaEventHandler(object sender, ValidationEventArgs e)
{
    if (e.Severity == XmlSeverityType.Error)
        throw new XmlException(e.Message);
    else if (e.Severity == XmlSeverityType.Warning)
        Logger.Info(e.Message);
}
void XmlValidationEventHandler(object sender, ValidationEventArgs e)
{
    if (e.Severity == XmlSeverityType.Error)
        throw new XmlException(e.Message);
    else if (e.Severity == XmlSeverityType.Warning)
        throw new XmlException(e.Message);
}

最新更新