在 C# 中针对引用的 XSD 验证 XML

Posted

技术标签:

【中文标题】在 C# 中针对引用的 XSD 验证 XML【英文标题】:Validating an XML against referenced XSD in C# 【发布时间】:2010-10-19 14:05:14 【问题描述】:

我有一个带有指定架构位置的 XML 文件,例如:

xsi:schemaLocation="someurl ..\localSchemaPath.xsd"

我想在 C# 中进行验证。当我打开文件时,Visual Studio 会根据架构验证它并完美地列出错误。但是,不知何故,如果不指定要验证的架构,我似乎无法在 C# 中自动验证它:

XmlDocument asset = new XmlDocument();

XmlTextReader schemaReader = new XmlTextReader("relativeSchemaPath");
XmlSchema schema = XmlSchema.Read(schemaReader, SchemaValidationHandler);

asset.Schemas.Add(schema);

asset.Load(filename);
asset.Validate(DocumentValidationHandler);

我不应该能够使用 XML 文件中指定的架构自动进行验证吗?我错过了什么?

【问题讨论】:

参考 MSDN 示例:msdn.microsoft.com/en-us/library/… 【参考方案1】:

您需要创建一个 XmlReaderSettings 实例,并在创建时将其传递给您的 XmlReader。然后您可以在设置中订阅ValidationEventHandler 以接收验证错误。您的代码最终将如下所示:

using System.Xml;
using System.Xml.Schema;
using System.IO;

public class ValidXSD

    public static void Main()
    

        // Set the validation settings.
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

        // Create the XmlReader object.
        XmlReader reader = XmlReader.Create("inlineSchema.xml", settings);

        // Parse the file. 
        while (reader.Read()) ;

    
    // Display any warnings or errors.
    private static void ValidationCallBack(object sender, ValidationEventArgs args)
    
        if (args.Severity == XmlSeverityType.Warning)
            Console.WriteLine("\tWarning: Matching schema not found.  No validation occurred." + args.Message);
        else
            Console.WriteLine("\tValidation error: " + args.Message);

    

【讨论】:

+1 虽然应该更新以使用 using 子句以确保完整性:) 如果您要与 XSD 文件进行比较,请在上面的代码中添加以下行:settings.Schemas.Add("YourDomainHere", "yourXSDFile.xsd"); 要获取错误的 Line# 和 position#,只需使用:args.Exception.LineNumber... in ValidationCallBack 如果我的架构没有命名空间怎么办? 使用 lambda,恕我直言,更多清晰代码 settings.ValidationEventHandler += (o, args) => errors = true; // More code ;【参考方案2】:

如果您使用 .NET 3.5,更简单的方法是使用 XDocumentXmlSchemaSet 验证。

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(schemaNamespace, schemaFileName);

XDocument doc = XDocument.Load(filename);
string msg = "";
doc.Validate(schemas, (o, e) => 
    msg += e.Message + Environment.NewLine;
);
Console.WriteLine(msg == "" ? "Document is valid" : "Document invalid: " + msg);

请参阅MSDN documentation 以获得更多帮助。

【讨论】:

该方法要求您事先了解架构,而不是从 xml 中获取内联架构。 这工作正常,但是当 xml 文档包含像 my new catalog.... " 会产生一个问题,因为它是 "" 的值...如何验证它 @AnilPurswani:如果您希望将 html 放入 XML 文档,您需要将其包装在 CDATA 中。 <catalog><![CDATA[my <i> new </i> catalog....]]></catalog> 是这样做的正确方法。 简洁优雅!这在针对固定模式集(这是我们的情况,一个具有多个文件夹和文件的大模式集)进行验证时非常有效。我已经在考虑缓存 XmlSchemaSet 以在对验证器的调用之间重用。非常感谢!【参考方案3】:

以下example 验证 XML 文件并生成相应的错误或警告。

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;

public class Sample


    public static void Main()
    
        //Load the XmlSchemaSet.
        XmlSchemaSet schemaSet = new XmlSchemaSet();
        schemaSet.Add("urn:bookstore-schema", "books.xsd");

        //Validate the file using the schema stored in the schema set.
        //Any elements belonging to the namespace "urn:cd-schema" generate
        //a warning because there is no schema matching that namespace.
        Validate("store.xml", schemaSet);
        Console.ReadLine();
    

    private static void Validate(String filename, XmlSchemaSet schemaSet)
    
        Console.WriteLine();
        Console.WriteLine("\r\nValidating XML file 0...", filename.ToString());

        XmlSchema compiledSchema = null;

        foreach (XmlSchema schema in schemaSet.Schemas())
        
            compiledSchema = schema;
        

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(compiledSchema);
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
        settings.ValidationType = ValidationType.Schema;

        //Create the schema validating reader.
        XmlReader vreader = XmlReader.Create(filename, settings);

        while (vreader.Read())  

        //Close the reader.
        vreader.Close();
    

    //Display any warnings or errors.
    private static void ValidationCallBack(object sender, ValidationEventArgs args)
    
        if (args.Severity == XmlSeverityType.Warning)
            Console.WriteLine("\tWarning: Matching schema not found.  No validation occurred." + args.Message);
        else
            Console.WriteLine("\tValidation error: " + args.Message);

    

前面的示例使用以下输入文件。

<?xml version='1.0'?>
<bookstore xmlns="urn:bookstore-schema" xmlns:cd="urn:cd-schema">
  <book genre="novel">
    <title>The Confidence Man</title>
    <price>11.99</price>
  </book>
  <cd:cd>
    <title>Americana</title>
    <cd:artist>Offspring</cd:artist>
    <price>16.95</price>
  </cd:cd>
</bookstore>

books.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="urn:bookstore-schema"
    elementFormDefault="qualified"
    targetNamespace="urn:bookstore-schema">

 <xsd:element name="bookstore" type="bookstoreType"/>

 <xsd:complexType name="bookstoreType">
  <xsd:sequence maxOccurs="unbounded">
   <xsd:element name="book"  type="bookType"/>
  </xsd:sequence>
 </xsd:complexType>

 <xsd:complexType name="bookType">
  <xsd:sequence>
   <xsd:element name="title" type="xsd:string"/>
   <xsd:element name="author" type="authorName"/>
   <xsd:element name="price"  type="xsd:decimal"/>
  </xsd:sequence>
  <xsd:attribute name="genre" type="xsd:string"/>
 </xsd:complexType>

 <xsd:complexType name="authorName">
  <xsd:sequence>
   <xsd:element name="first-name"  type="xsd:string"/>
   <xsd:element name="last-name" type="xsd:string"/>
  </xsd:sequence>
 </xsd:complexType>

</xsd:schema>

【讨论】:

【参考方案4】:

我个人喜欢在没有回调的情况下进行验证:

public bool ValidateSchema(string xmlPath, string xsdPath)

    XmlDocument xml = new XmlDocument();
    xml.Load(xmlPath);

    xml.Schemas.Add(null, xsdPath);

    try
    
        xml.Validate(null);
    
    catch (XmlSchemaValidationException)
    
        return false;
    
    return true;

(参见 Timiz0r 在Synchronous XML Schema Validation? .NET 3.5 的帖子)

【讨论】:

回调为您提供一些额外信息,说明您的 xml 中哪一行不正确。这个方法很二元,不分对错:) 你可以得到异常信息:)【参考方案5】:

我在 VB 中做过这种自动验证,我就是这样做的(转换为 C#):

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = settings.ValidationFlags |
                           Schema.XmlSchemaValidationFlags.ProcessSchemaLocation;
XmlReader XMLvalidator = XmlReader.Create(reader, settings);

然后我在读取文件时订阅了settings.ValidationEventHandler 事件。

【讨论】:

以上是关于在 C# 中针对引用的 XSD 验证 XML的主要内容,如果未能解决你的问题,请参考以下文章

通过单一方法针对 XSD 验证 XML

可以在运行时使用代码针对 xsd 验证 xml 吗?

可以在运行时使用 Objc/iPhone 代码针对 xsd 验证 xml

在 Java 中针对 xsd 的 XML 验证

是否可以在 Python 中针对 XSD 1.1 验证 XML 文件?

要针对多个 xsd 模式验证 XML