2017-07-08 118 views
1

虽然试图尽量减少XML解析程序的内存占用,特别是避免使用XElement.Load()加载数百兆字节,但是我遇到了使用较旧的XmlReadere.g. here的文章。XmlReader跳过相邻元素

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

我拆掉了问题该单元测试(MSTest2与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.NodeTypeText,而不是Element。通过处理所有4

在我的现实世界的例子第二次测试(与</entry><entry>通过之间的空间,我不能轻易改变的源泉。我已经有一个解决方案,通过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); 
} 

回答

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(); 
    } 
} 
+0

啊,疑难杂症。因此,在if条件中,我会调用'continue',否则(不需要else)我会执行'xml.Read()'来执行类似于你的操作。 –