单遍读取和验证 XML 与 C# 中引用的 XSD

Single-pass Read and Validate XML vs referenced XSD in C#(单遍读取和验证 XML 与 C# 中引用的 XSD)
本文介绍了单遍读取和验证 XML 与 C# 中引用的 XSD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我正在尝试从 XML 文件中读取数据,并根据它建议的 XSD 对其进行验证,并将其转换为单个数据结构(例如 XmlDocument).我有一个解决方案,但它需要 2 遍文件,我想知道是否有单遍解决方案.

I'm trying to read the data from an XML file, validating it against the XSD it suggests, into a single data structure (such as XmlDocument). I have a solution, but it requires 2 passes through the file, and I'm wondering if there's a single-pass solution.

MyBooks.xml:

<Books xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:noNamespaceSchemaLocation='books.xsd' id='999'>
    <Book>Book A</Book>
    <Book>Book B</Book>
</Books>

Books.xsd:

<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
    elementFormDefault='qualified'
    attributeFormDefault='unqualified'>
    <xs:element name='Books'>
        <xs:complexType>
            <xs:sequence>
                <xs:element name='Book' type='xs:string' />
            </xs:sequence>
            <xs:attribute name='id' type='xs:unsignedShort' use='required' />
        </xs:complexType>
    </xs:element>
</xs:schema>

假设 MyBooks.xml 和 Books.xsd 在同一个目录中.

Let's say MyBooks.xml and Books.xsd are in the same directory.

验证:

//Given a filename pointing to the XML file
var settings = new XmlReaderSettings();

settings.ValidationType = ValidationType.Schema;

settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;

settings.CloseInput = true;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCB);
//eg:
//private static void ValidationCB(object sender, ValidationEventArgs args)
//{ throw new ApplicationException(args.Message); }

using(var reader = XmlReader.Create(filename, settings))
{ while(reader.Read()) ; }

读入 XmlDocument:

XmlDocument x = new XmlDocument();
x.Load(filename);

当然,我可以在从 XmlReader 读取数据时收集节点,但如果可能的话,我宁愿自己不必这样做.有什么建议吗?

Sure, I could collect the nodes as the read from the XmlReader is taking place, but I'd rather not have to do it myself, if possible. Any suggestion?

提前致谢

推荐答案

您的解决方案非常接近;您需要做的是使用验证阅读器来加载您的 XML;这样一来,您的加载就完成了验证;验证错误不会阻止您加载文档.

You're very close with your solution; what you need to do is to use a validating reader to load your XML; this way the validation is done with your loading, in one pass; validation errors will not stop you from loading the document.

这些是我通常与 ValidateXml 辅助函数一起使用的高级步骤;这一切都从一个已编译的 XmlSchemaSet 开始:

These are the high level steps that I usually use with a ValidateXml helper function; it all starts with a compiled XmlSchemaSet:

public bool ValidateXml(XmlSchemaSet xset)

我设置了阅读器设置(你也这样做了):

I set the reader settings (which you did, too):

XmlReaderSettings settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = xset, ConformanceLevel = ConformanceLevel.Document };
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
// Use your helper class that collects validation events. 
XsdUtils.Utils.SmartValidationHandler svh = new XsdUtils.Utils.SmartValidationHandler(Paschi.Xml.DefaultResolver.Instance);
settings.ValidationEventHandler += svh.ValidationCallbackOne;

然后我得到一个读者:

XmlReader xvr = XmlReader.Create(filename, settings);

然后我读取了文件,它带来了验证:

Then I read the file, which brings the validation in:

XmlDocument xdoc = new XmlDocument();
xdoc.Load(xvr);

您的验证处理程序现在有了结果;我还要做的一件事是确保加载的文档元素实际上在 xml 模式集中具有相应的全局元素定义.

Your validation handler has the results now; one thing I also do is to ensure that the document element that was loaded, actually has a corresponding global element definition in the xml schema set.

XmlQualifiedName qn = XmlQualifiedName.Empty;
if (xdoc.DocumentElement != null)
{
        if (string.IsNullOrEmpty(xdoc.DocumentElement.NamespaceURI))
        {
              qn = new XmlQualifiedName(xdoc.DocumentElement.LocalName);
        }
        else
        {
               qn = new XmlQualifiedName(xdoc.DocumentElement.LocalName, xdoc.DocumentElement.NamespaceURI);
         }
}
return !(svh.HasError || qn.IsEmpty || (!xset.GlobalElements.Contains(qn)));

这篇关于单遍读取和验证 XML 与 C# 中引用的 XSD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

Custom Error Queue Name when using EasyNetQ for RabbitMQ?(使用 EasyNetQ for RabbitMQ 时自定义错误队列名称?)
How to generate password_hash for RabbitMQ Management HTTP API(如何为 RabbitMQ 管理 HTTP API 生成密码哈希)
Rabbitmq Ack or Nack, leaving messages on the queue(Rabbitmq Ack 或 Nack,将消息留在队列中)
Setup RabbitMQ consumer in ASP.NET Core application(在 ASP.NET Core 应用程序中设置 RabbitMQ 消费者)
Specify Publish timeouts in mass transit(指定公共交通中的发布超时)
RabbitMQ asynchronous support(RabbitMQ 异步支持)