根据.net中的模式进行多线程xml验证



我试图在多线程应用程序中验证xml文件,但遇到了问题(验证错误:未声明"元素。

我认为这与XmlSchemaSet的架构验证错误/线程安全中的问题相同?这个问题,但我不知道如何让它发挥作用。

我最初使用的是内联模式,这很好,但解决外部文件的速度太慢了。我决定将模式缓存在ConcurrentDictionary中以加快速度。

这是代码:

此方法属于每个线程的本地对象。

public void validate() 
{
    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);
    using (var tr = new XmlTextReader(xmlFile))
    {
        tr.MoveToContent();
        var url = tr.GetAttribute("xsi:noNamespaceSchemaLocation");
        var schema = SchemaFactory.GetSchema(url);
        settings.Schemas.Add(schema);
    }
    using (XmlReader reader = XmlReader.Create(xmlFile, settings))
    {
        while (reader.Read());
    }

SchemaFactory定义:

public static class SchemaFactory
{
    static ConcurrentDictionary<string, XmlSchema> schemaStore = 
        new ConcurrentDictionary<string, XmlSchema>();
    public static XmlSchema GetSchema(string url)
    {
        XmlSchema schema = null;
        if (!schemaStore.TryGetValue(url, out schema))
        {
            var schemadata = new System.Net.WebClient().DownloadString(url);
            schema = XmlSchema.Read(new StringReader(schemadata), (sender, args) => {  });
            schemaStore.TryAdd(url, schema);
        }
        return schema;
    }
}

在多个线程中处理时,如何在xml文件中第一次遇到架构时实时将其添加到缓存中

XMLSchema不是线程安全的。将模式缓存为字符串,然后它就可以工作了:

class Program
{           
    private ConcurrentDictionary<string, string> schemaStore =
            new ConcurrentDictionary<string, string>();
    static void Main(string[] args)
    {
        Program p = new Program();
        for (int i = 0; i < 40;i++ )
            new Thread(new ThreadStart(p.validate)).Start();
        Console.ReadKey();
    }

    public void validate()
    {
        string xmlFile = "XMLFile1.xml";
        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);

            using (var tr = new XmlTextReader(xmlFile))
            {
                tr.MoveToContent();
                var url = tr.GetAttribute("xsi:noNamespaceSchemaLocation");
                string schemaXml =null;
                if (!schemaStore.TryGetValue(url, out schemaXml))
                {
                    //Console.WriteLine("Need download");
                    using (System.Net.WebClient wc = new System.Net.WebClient())
                    {
                        string schemadata = wc.DownloadString(url);
                        schemaStore.TryAdd(url, schemadata);
                        schemaXml = schemadata;
                    }
                }else
                {
                        //Console.WriteLine("Cache hit");
                }

                XmlSchema schema = XmlSchema.Read(new StringReader(schemaXml), (sender, args) => { });
                settings.Schemas.Add(schema);
            }

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

        Console.WriteLine("Thread "+Thread.CurrentThread.ManagedThreadId+" completes");
    }
    private void ValidationCallBack(object sender, ValidationEventArgs args)
    {           
            if (args.Severity == XmlSeverityType.Error)
                Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " -> Error: " + args.Message);
            else
                Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " -> Warning: " + args.Message);          
    }


}

如果它仍然是真的,如XmlSchemaSet的架构验证错误/线程安全中所述?如果您不能针对同一个编译的模式运行多个并行模式验证,那么解决方法可能是使用没有此限制的Saxon模式验证器[无耻插件]。

http://www.saxonica.com/

最新更新