针对.net中的模式进行多线程xml验证

时间:2014-04-30 13:50:10

标签: c# xml multithreading validation xml-parsing

我尝试在多线程应用程序中验证xml文件,但我遇到了问题(验证错误:未声明''元素。)如果我运行单个线程的代码,或者一次只有一个xml文件,一切都按预期工作。

我认为它与此Schema validation error / Thread safety of 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文件中第一次遇到时实时向缓存添加架构?

2 个答案:

答案 0 :(得分:2)

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

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);          
    }





}

答案 1 :(得分:-2)

如果Schema validation error / Thread safety of XmlSchemaSet?中所述仍然无法对同一编译模式运行多个并行模式验证,那么解决方法可能是使用没有的Saxon模式验证器[无耻插件]这个限制。

http://www.saxonica.com/