0

我编写了一个快速类来验证 FilePath 上的 XML 文件与 .NET 的 XSD(见下文)。

我有大量数据文件由局域网上的另一台机器生成,但这些文件不是真正的 XML,它们格式错误,但每次都以相同的方式并根据它们的结构,我可以对内容进行一些全局替换文件来纠正它。所以我必须在用 XSD 测试之前纠正这些。我必须替换<\</等等。所有替换都列在代码中。

当我将其指向生成文件的机器的 LAN 网络共享时,文件列表大约有 50k 个文件,这大约需要 15 分钟才能完成。我想知道这是否只是局域网限制的 IO,或者是否有比我在这里所做的替换更好(更快)的方法来纠正格式错误的 XML。

class VCheck
{
    private static XmlReaderSettings settings = new XmlReaderSettings();
    private bool valid;
    string message;
    public string Message { get { return message; } }

    public VCheck()
    {
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
        settings.Schemas.Add(null, "schema.xsd");
    }

    public bool CheckFile(string FileFullPath) 
    {
        StreamReader file = new StreamReader(FileFullPath);
        valid = true;
        message = null;
        try
        { //setup xml reader with settings
            XmlReader xml = XmlReader.Create(new StringReader(@"<?xml version='1.0'?><root xmlns=""MYE"">" + 
            file.ReadToEnd().Replace(@"<\", @"</").Replace("&", "&amp;").Replace("\"", "&quot;").Replace("'", "&apos;") + "</root>"), 
            settings);

            while (xml.Read()) ; //read in all xml, validating against xsd
        }
        catch
        {
            //problem reading the xml file in, bad path, disk error etc.
            return false;
        }

        return valid;
    }

    void ValidationCallBack(object sender, ValidationEventArgs e) //called on failed validations
    {
        valid = false;
        message = e.Message;
        switch (e.Severity)
        {
            case XmlSeverityType.Error:
                //Do stuff on validation error
                break;
            case XmlSeverityType.Warning:
                //Do stuff on validation warning
                break;
        }

    }

}

我会像这样从 main 调用它:

    static void Main(string[] args)
    {
        VCheck checker = new VCheck();
        foreach (string file in files) //files is a List<string> of file paths/names
        {
            if (!checker.CheckFile(file))
            {
                //To do stuff if not valid
            }
        }
}
4

2 回答 2

1

考虑到您的性能问题,我不认为将其全部读入内存 -ReadToEnd并对内容执行是一个不错的选择。String.Replace

如果我是你,我宁愿“一块一块地”重写这些文件——也就是说,即时缓冲和替换数据。

只需创建一个新文件,将一些格式错误的文件加载到缓冲区中(例如 4 kb),进行替换,将结果刷新到新创建的文件中;冲洗并重复。

注意:可能会发生一个缓冲区以 . 结尾,<而下一个缓冲区以\. 如果你不想错过任何<\s (和类似的),你也需要处理这种情况。

另一种可能的解决方案是,您可以尝试创建自己的“更宽容”的实现XmlReader(此类不是密封的,因此您可以基于它并创建自己的),尽管我个人没有这样做,我不确定这是否是一个好方法。重写文件至少会给您留下语法上有效的 XML,这在某些时候可能会派上用场。


PS。附带说明:

    catch
    {
        //problem reading the xml file in, bad path, disk error etc.
        return false;
    }

我不会那样做的。它使调用者不知道操作失败的原因。

于 2012-08-21T13:51:57.520 回答
0

最快的过程是那些根本不需要执行的过程。因此,我建议您注意 Michael Kay 关于处理“非格式良好的 XML”的评论。

如果您希望作为 XML 处理的非 XML 数据是由一台机器生成的,那么该机器没有理由不能生成 XML 数据而不是您当前尝试修复的非 XML 数据。更糟糕的是,您为处理数据生成过程中的错误所付出的每一分钟努力都是在说服负责该过程的人员他们正在生成正确、格式良好的 XML 上的一分钟。所以你在这里受伤的不仅仅是你自己。

于 2012-08-21T17:23:18.953 回答