XmlReader异常处理 - IEnumerable

时间:2013-09-19 13:49:02

标签: c# xml ienumerable xmlreader

我正在阅读一个非常大的XML文件,我必须将其作为流读取,如下所示:

public IEnumerable<something> GetStuff()
{
    foreach(var gzipStream in GetGZips())
    {
        using (var reader = XmlReader.Create(gzipStream, new XmlReaderSettings{ CheckCharacters = false }))
        {
            reader.MoveToContent();

            while (reader.Read()) //<-- Exception here
            {
                //Do stuff
                yield return something;
            }
        }
    }
}

我得到了一个无效的char异常,处理过程中的一部分:

' ', hexadecimal value 0x19, is an invalid character. Line 655, position 45.

鉴于你不允许在try-catch中产生回报 - 在出现错误的情况下,简单地中止当前Xml doc(并完成Enumeration)的处理有什么好方法?

try / finally并不好 - 因为异常会破坏整个IEnumerable的处理。

我无法对文件执行任何预处理。

2 个答案:

答案 0 :(得分:1)

如果你真的无法进行任何预处理,并且绝对必须在解析XML时生成枚举,那么如果用以下内容替换while循环呢?

bool IsMoreXml = true;

while (IsMoreXml)
{
    var ValuesRead = null; //not sure what you're reading
    try
    {
        IsMoreXml = reader.Read();
        if(!IsMoreXml) break;
        //Do Stuff
        ValuesRead = whateverwereadfromxml;

    }
    catch (XmlException ex)
    {
        //do what you gotta do
        break;
    }

    if(ValuesRead != null)
        yield return ValuesRead;
}

您应该处理其他可能的异常,但不确定您是否正在处理从中调用它的那些异常。它不优雅,但后来我不确定你的限制是什么(例如,没有预处理)

答案 1 :(得分:0)

我只是处理同样的事情。我知道这已经过时了,但我想我会把它放在这里作为参考。

我打算提出一个要点,但我认为看看GitHub上的提交会更有帮助。

https://github.com/DewJunkie/Log2Console/commit/fb000c0a97c6762b619d213022ddc750bd9254ae 如果您使用winmerge比较之前的版本,您将更清楚地了解更改。

虽然你无法在try catch中获得yield返回,但你可以使用另一个返回单个解析实例的函数。 try catch将在第二个函数中。我使用正则表达式将日志拆分为单个记录。我假设即使在一个大文件中,单个记录仍然适合几KB的缓冲区。我还想象RegEx会有一些开销,但我主要担心的是丢失数据。

我实际上花了几个小时写一个解析器,当我测试时,我意识到解析器的核心是这个正则表达式,我实际上甚至不需要其余的。

TLDR;

//旧方法,非常类似于你的方法

while(!xmlreader.eof){xmlreader.read();}

//新方法

IEnumerable<Foo> ParseFile(stream){
foreach(var match in Regex.Matches(xmlText,$"<(/?)\\s*(XML_RECORD_ELEMENT)[^<>]*(/?)>") 
{/*logic to split xml based on matches.
working code is in the above commit.   Not too long, but too long for MD. */
yield return ParseXmlFragment(xmlFragment);
...}
}

Foo ParseXmlFragment(string xmlFragment)
{
   Foo newFoo = new Foo();
   try{//xmlreader here to parse fragment}
   catch(ex)
   {
     // handle ex if possible here.  If not possible, you now have the complete text of the unparsable fragment, which you can correct and try again.
     throw; // if you want to halt execution, or you can continue
   }
}