XmlReader 跳过相邻元素
Posted
技术标签:
【中文标题】XmlReader 跳过相邻元素【英文标题】:XmlReader skipping adjoined elements 【发布时间】: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
。第二个测试(</entry>
和 <entry>
之间的空格通过处理所有 4 个。
在我的真实示例中,我不能轻易更改源。我已经有了一个受another *** 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);
【问题讨论】:
【参考方案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()
。以上是关于XmlReader 跳过相邻元素的主要内容,如果未能解决你的问题,请参考以下文章