将包含多个XML文件的单个大文件读入C#中的多个xml记录

时间:2015-09-02 12:19:24

标签: c#

我有一个文件,它有效地包含多个相同格式的XML文件,因此该文件本身不是有效的XML;例如:

<?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>
....

我想一次一个地处理所有Proposal节点;例如:

foreach (var proposal in file)
    do something

我无法使用XmlReader,因为它在到达中间XML声明节点时会抛出异常。我可能会将整个文件读入一个字符串,然后使用Split方法,但这些文件的大小是千兆字节,因此作为一个选项并不是特别有吸引力。看起来我可以一次读取一行文件,通过正则表达式搜索相应的节点,但文件不是如上所述的行格式,每行一个节点,而是包含很长的多个节点行,以及节点文本中的随机换行符。

有没有一种方法可以实现这个目的而无需手工制作文本解析器?

2 个答案:

答案 0 :(得分:2)

您有两种选择:

  1. 告诉XmlReader不要那么挑剔。将XmlReaderSettings.ConformanceLevel设置为ConformanceLevel.Fragment。这将使解析器忽略没有根节点的事实。

    var settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;
    using (var reader = XmlReader.Create(textReader, settings))
    {
         ...
    }
    
  2. 使用“root”元素包装XML文件,这样您的文档将只有一个根节点

  3.  <?xml version='1.0' encoding='UTF-8'?>
     <root>
         <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>
     ....
     </root>
    

答案 1 :(得分:0)

您可以逐行阅读文本而不实际解析xml,因为xml文档的标题是相同的:

mSplashThread = new Thread() {
    @Override
    public void run() {
        try {
                Thread.sleep(DURATION);

                runOnUiThread(new Runnable() {
                    public void run() {
                        Intent intent = new Intent(Splash.this,
                        Main.class);
                        startActivity(intent);
                        finish();
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
        }
    }

};
mSplashThread.start();

更新: 即使声明可以在一行之间开始,以下内容也会起作用:

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