解析具有在不同级别重复的元素名称的大XML文件

时间:2015-12-01 00:08:43

标签: c# xml

我正在尝试用C#解析一个非常大的XML文件 - 足够大,以至于某些XML工具无法处理它,所以我想按顺序处理它而不是全部加载它。另外,如果有某些错误在源代码中,我希望能够报告错误以及发生错误的XML中的行号。

不幸的是,XML在不同级别重复元素名称,如:

<foo>
    <foo>
        <foo>Something interesting</foo>
    </foo>
    Something else interesting
    <foo>Yes, it's horrid, isn't it?</foo>
</foo>

我需要跟踪事情发生的嵌套级别。

我尝试过使用XmlTextReader,但我似乎只获得了foo个元素的列表:我无法弄清楚如何跟踪嵌套级别。我的下一个想法是在每个元素上使用ReadSubtree,所以当我从嵌套返回时,我可以使用它来告诉我。但是它返回一个XmlReader,而不是一个XmlTextReader,所以我不再能够访问原始XML的行号。一个网络搜索建议使用ReadOuterXml来获取节点的文本并从中生成另一个阅读器,但这似乎是在整个文本中读取的,所以我回到原来的文件问题那么大。

那么如何跟踪嵌套级别(当元素名称没有帮助时)和源行号而不加载整个文件?

1 个答案:

答案 0 :(得分:2)

回答您的相关问题:

  1. 您可以cast your XmlReader to an IXmlLineInfo提取行号。请注意,并非所有XmlReader实现都实现此接口,但XmlReader.Create Method(string inputUri)返回的实现具有此接口。过时的XmlTextReader也会。

  2. 要获取当前深度,请使用XmlReader.Depth

  3. 更一般地说,您可以在遍历文件时维护一堆XName类,例如:

    public static class XmlReaderExtensions
    {
        public static void WalkXmlNodes(this XmlReader xmlReader, Action<XmlReader, Stack<XName>, IXmlLineInfo> action)
        {
            IXmlLineInfo xmlInfo = xmlReader as IXmlLineInfo;
            try
            {
                Stack<XName> names = new Stack<XName>();
    
                while (xmlReader.Read())
                {
                    if (xmlReader.NodeType == XmlNodeType.Element)
                    {
                        names.Push(XName.Get(xmlReader.LocalName, xmlReader.NamespaceURI));
                    }
    
                    action(xmlReader, names, xmlInfo);
    
                    if ((xmlReader.NodeType == XmlNodeType.Element && xmlReader.IsEmptyElement)
                        || xmlReader.NodeType == XmlNodeType.EndElement)
                    {
                        names.Pop();
                    }
                }
            }
            catch (Exception ex)
            {
                // Rethrow exception with line number information.
                var line = (xmlInfo == null ? -1 : xmlInfo.LineNumber);
                var pos = (xmlInfo == null ? -1 : xmlInfo.LinePosition);
                var xmlException = new XmlException("XmlException occurred", ex, line, pos);
                throw xmlException;
            }
        }
    }