【问题标题】:XmlReader skipping adjoined elementsXmlReader 跳过相邻元素
【发布时间】:2017-07-08 12:22:01
【问题描述】:

在尝试最小化 XML 解析程序的内存占用,特别是避免使用 XElement.Load() 加载数百兆字节时,我遇到了建议使用较旧的 XmlReader e.g. here 的文章。

我需要在内部将每个主要元素重构为 XElement 以避免重大重构。但是,我发现如果我的源元素直接相邻,这种方法会跳过每个第二个元素。

我已经解决了这个单元测试的问题(MSTest2 with FluentAssertions):

[DataTestMethod]
[DataRow("<data><entry>1</entry><entry>2</entry><entry>3</entry><entry>4</entry></data>")]
[DataRow("<data><entry>1</entry> <entry>2</entry> <entry>3</entry> <entry>4</entry></data>")]
public void XmlReaderCount(string input)
{
    var sr = new StringReader(input);
    var xml = XmlReader.Create(sr);
    xml.MoveToContent();

    var data = new List<string>();
    while (xml.Read())
    {
        if (xml.LocalName == "entry" && xml.NodeType == XmlNodeType.Element)
        {
            var element = (XElement)System.Xml.Linq.XNode.ReadFrom(xml);
            data.Add(element.Value);
        }
    }

    data.Should()
        .HaveCount(4);
}

第一个(数据驱动的)测试失败:

预期的集合包含 4 个项目,但找到了 2 个。

因为它将 1 和 3 放入数据收集中。它确实循环了 4 次,但每个其他元素都有一个 xml.NodeType 或 Text,而不是 Element。第二个测试(&lt;/entry&gt; 和 &lt;entry&gt; 之间的空格通过处理所有 4 个。

在我的真实示例中,我不能轻易更改源。我已经有了一个受another StackOverflow question 启发的解决方案,所以我可以执行以下操作,但这似乎很奇怪 - 有什么问题吗?

[DataTestMethod]
[DataRow("<data><entry>1</entry><entry>2</entry><entry>3</entry><entry>4</entry></data>")]
[DataRow("<data><entry>1</entry> <entry>2</entry> <entry>3</entry> <entry>4</entry></data>")]
public void XmlReaderCountSubtree(string input)
{
    var data = new List<string>();

    var sr = new StringReader(input);
    var xml = XmlReader.Create(sr);
    xml.MoveToContent();

    while (xml.Read())
    {
        if (xml.LocalName == "entry" && xml.NodeType == XmlNodeType.Element)
        {
            using (var subtree = xml.ReadSubtree())
            {
                subtree.MoveToContent();
                var content = subtree.ReadOuterXml();
                var element = XElement.Parse(content);
                data.Add(element.Value);
            }
         }
     }

     data.Should()
         .HaveCount(4);
}

【问题讨论】:

    标签: c# xml-parsing


    【解决方案1】:

    当您调用 ReadFrom(xml) 时,xml 的状态发生了变化。它的光标向前移动到下一个元素。然后您的代码继续移动到while (xml.Read()),因此完全忽略了该新元素。

    对于第二个数据集,被忽略(和未经检查)的元素是空白节点,因此您可以摆脱它。但基本上,你阅读算法是错误的。

    您的第一种方法的修复,不是很漂亮,但它有效:

    xml.Read();
    while (! xml.EOF)
    {
        if (xml.LocalName == "entry" && xml.NodeType == XmlNodeType.Element)
        {
            //using (var subtree = xml.ReadSubtree())
            {                    
                var element = (XElement)XNode.ReadFrom(xml);
                data.Add(element.Value);
            }
        }
        else
        {
            xml.Read();
        }
    }
    

    【讨论】:

    • 啊,明白了。所以用while(!xml.EOF)做一些与你类似的事情,在if条件内我会调用continue,否则(不需要else)我会做xml.Read()。
    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 2016-08-22
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多