正在读取C#中带有未闭合标记的XML

本文关键字:XML 读取 | 更新日期: 2023-09-27 18:27:42

我有一个程序,它运行测试并生成一个包含所有结果的网格视图,还有一个XML日志文件。该程序还具有加载日志以复制网格视图的功能。

由于程序在执行时会写入日志文件,因此如果程序崩溃,日志文件将丢失关闭标记。尽管如此,我仍然希望能够加载这些XML文件,因为仍然有很多有价值的数据可以帮助我找出导致崩溃的原因。

我在想,也许是浏览XML文件并关闭任何未关闭的XML标记,或者可能是编写某种"脏"的XML读取器,假装每个标记都已关闭。关于我能做什么或应该如何进行,有什么想法吗?

编辑:

<Root>
  <Parent>
     <Child Name="One">
        <Foo>...</Foo>
        <Bar>...</Bar>
        <Baz>...</Baz>
     </Child>
     <Child Name="Two">
        <Foo>...</Foo>
        <Bar>...</Bar>
 !-- Crash happens here --!

从这一点我仍然希望生产

 Child   Foo   Bar   Baz
 One     ...   ...   ...
 Two     ...   ...    /

正在读取C#中带有未闭合标记的XML

在被截断之前,它可能都是有效的。。。因此使用CCD_ 1可以工作。。。只要准备好在它到达截断点时处理它。

现在XmlReader API不是很令人愉快(IMO),所以你可能想转移到一些有趣数据的开头(它本身必须是完整的),然后调用XNode.ReadFrom(XmlReader)方法以获得简单易用的形式的数据。然后转移到下一个元素的开头并做同样的事情,等等

样本代码:

using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
class Program
{
    static void Main(string[] args)
    {
        using (XmlReader reader = XmlReader.Create("test.xml"))
        {
            while (true)
            {
                while (reader.NodeType != XmlNodeType.Element ||
                    reader.LocalName != "Child")
                {
                    if (!reader.Read())
                    {
                        Console.WriteLine("Finished!");
                    }
                }
                XElement element = (XElement) XNode.ReadFrom(reader);
                Console.WriteLine("Got child: {0}", element.Value);
            }
        }
    }
}

示例XML:

<Root>
  <Parent>
    <Child>First child</Child>
    <Child>Second child</Child>
    <Child>Broken

样本输出:

有孩子:第一个孩子有孩子:第二个孩子

Unhandled Exception: System.Xml.XmlException: Unexpected end of file has occurred
The following elements are not closed: Child, Parent, Root. Line 5, position 18.
   at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
   at System.Xml.XmlTextReaderImpl.ParseElementContent()
   at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r)
   at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o)
   at System.Xml.Linq.XElement.ReadElementFrom(XmlReader r, LoadOptions o)
   at System.Xml.Linq.XNode.ReadFrom(XmlReader reader)
   at Program.Main(String[] args)

很明显,您想要捕获异常,但您可以看到它成功地正确读取了前两个元素。

作为最后的手段,根据您正在做的事情,您可以使用HTML阅读器,如HtmlAgilityPack(Nuget页面)或SGMLReader。SGMLReader实际上会将其转换为XmlDocument,因此这可能更符合您的要求。

当然,HTML不是XML,所以使用这种方法可以得到您所得到的。

默认情况下,Framework中没有这样的东西,也没有一个好的解决方案可以解析通用的无效xml。

你能做的最有意义的事情就是在开始阅读XML之前修复它。因为只有末尾被切掉了,所以你应该能够找出所有打开的标签并关闭它们。