将包含多个XML文件的单个大文件读入C#中的多个xml记录 [英] Read single large file containing multiple XML files into multiple xml records in C#

查看:65
本文介绍了将包含多个XML文件的单个大文件读入C#中的多个xml记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文件,其中实际上包含了多个相同格式的XML文件,因此该文件本身不是有效的XML;例如:

I have a single file that effectively contains multiple XML files of the same format, so the file is not itself valid XML; for instance:

<?xml version='1.0' encoding='UTF-8'?>
<Proposal xmlns="a namespace">
    <ASubnode>Text</ASubNode>
    <LotsOfOtherNodes />
</Proposal>
<?xml version='1.0' encoding='UTF-8'?>
<Proposal xmlns="a namespace">
    <ASubnode>Text</ASubNode>
    <LotsOfOtherNodes />
</Proposal>
....

我想一次处理所有投标"节点;例如:

I would like to process all the Proposal nodes, one at a time; for example:

foreach (var proposal in file)
    do something

我不能使用XmlReader,因为它在到达中间XML声明节点时会引发异常.我可以将整个文件读取为一个字符串,然后使用Split方法,但是这些文件的大小为千兆字节,因此作为一种选择并不是特别吸引人.似乎我可以一次读取一行文件,通过正则表达式搜索适当的节点,但是文件的格式不是如上所述的,每行一个节点,而是包含很长的多个节点行,以及节点文本中的随机换行符.

I cannot use XmlReader because it throws an exception upon reaching the intermediate XML declaration nodes. I could possibly read the entire file into a string and then use the Split method, but these files are Gigabytes in size, so that is not particularly attractive as an option. It might seem that I could read the file a line at a time, searching for the appropriate nodes via a regular expression, but the files are not line-formatted as above with one node per line, but rather contain very long lines of multiple nodes, and random line breaks in node text.

是否有一种无需手工制作文本解析器即可实现的方法?

Is there a method of achieving this without hand-crafting a text parser?

推荐答案

由于xml文档的标题是相同的,因此您可以逐行阅读文本而无需实际解析xml:

You can read the text line by line without actually parsing the xml, since the header of an xml document is the same:

IEnumerable<XDocument> GetDocuments(Stream bulkStream)
{
    var reader = new StreamReader(bulkStream);
    var sb = new StringBuilder();   
    var firstLine = reader.ReadLine();
    string line = firstLine;    
    while(line != null)
    {
        sb.Clear();
        sb.Append(firstLine);
        while((line = reader.ReadLine()) != null && line != firstLine)
        {
            sb.Append(line);
        }

        yield return XDocument.Parse(sb.ToString());
    }
}

更新:即使声明可以在一行之间开始,也可以执行以下操作:

UPDATE: Following will work even if the declarations can start in-between of a line:

IEnumerable<XDocument> GetDocuments(Stream bulkStream)
{
    const string decl = @"<?xml version='1.0' encoding='UTF-8'?>";
    var sb = new StringBuilder();   

    bool start = true;
    foreach(var line in GetLines(bulkStream).Where(l => !string.IsNullOrWhiteSpace(l)))
    {
        if (start)
        {
            if (line == decl)
                start = false;
            sb.AppendLine(line);
        }
        else
        {
            if (line == decl)
            {
                sb.ToString().Dump();
                yield return XDocument.Parse(sb.ToString());

                sb.Clear();
                start = true;
                sb.AppendLine(line);
            }
            else
                sb.AppendLine(line);
        }
    }

    sb.ToString().Dump();
    yield return XDocument.Parse(sb.ToString());
}

IEnumerable<string> GetLines(Stream bulkStream)
{
    const string decl = @"<?xml version='1.0' encoding='UTF-8'?>";
    var reader = new StreamReader(bulkStream);
    string line;
    while((line = reader.ReadLine()) != null)
    {
        if (line.Contains(decl))
        {
            var declIndex = line.IndexOf(decl);
            yield return line.Substring(0, declIndex);
            yield return decl;
            yield return line.Substring(declIndex + decl.Length);
        }
        else
        {
            yield return line;
        }
    }
}

这篇关于将包含多个XML文件的单个大文件读入C#中的多个xml记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆