2017-07-08 195 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()'來執行類似於你的操作。 –