2017-07-21 79 views
2

我想實現將xml反序列化爲對象列表的代碼。我在代碼中發現了一個問題,while while read reads forward,所以其他節點被跳過。檢查xml中的下一個節點的正確方法是在此代碼的while循環中執行的是什麼?如何檢查另一個節點是否存在於xml中而不讀 - C#

private Task<List<TAxEntity>> Deserialize(XmlReader reader) 
    { 
     var deserializer = new XmlSerializer(typeof(TAxEntity)); 
     var entities = new List<TAxEntity>(); 

     do 
     { 
      using (var stringReader = new StringReader(reader.ReadOuterXml())) 
      { 
       var entity = (TAxEntity)deserializer.Deserialize(stringReader); 

       entities.Add(entity); 
      } 
     } 
     while (reader.ReadToNextSibling(EntityElementName)); 

     return Task.FromResult(entities); 
    } 
+1

的跳躍是由ReadToNextSibling引起。找到一些其他的方式來了解你到底什麼時候,因爲ReadOuterXml已經在推進你的流。 – hoodaticus

+1

是的,我意識到這一點,這就是爲什麼我正在尋找另一種解決方案,期待沒有閱讀。謝謝! –

+2

' while(reader.Read()){...}'? – PiLHA

回答

0

要檢查的XmlReader已經被正確定位,您可以檢查是否reader.NodeType == XmlNodeType.Elementreader.Name == EntityElementName。然後,如果閱讀器已正確定位,請勿使用ReadToNextSibling()進行向前掃描。

不過,也有你的算法進行一些改進:

  1. 檢查正確reader.Name相反的,檢查是否LocalNameNamespaceURI的預期,如果沒有,請致電reader.ReadToNextSibling(string localName,string namespaceURI)。這避免了名稱空間前綴的硬編碼,這是一個bug to be avoided

  2. 而不是ReadOuterXml(),請致電reader.ReadSubtree()並將返回的閱讀器直接傳遞給deserializer.Deserialize()。您當前的算法解析XML,將其重新格式化爲第二個XML字符串,然後再解析該字符串。使用ReadSubtree()允許XmlSerializer直接從傳入的XmlReader流式傳輸嵌套元素,因此避免了這種額外的解析和重新格式化。

把所有這些組合起來,就可以推出以下較低級別的擴展方法:

public static class XmlReaderExtensions 
{ 
    public static IEnumerable<TElement> DeserializeSequence<TElement>(this XmlReader reader, string localEntityElementName, string namespaceURI) 
    { 
     if (reader == null) 
      throw new ArgumentNullException(); 
     var deserializer = new XmlSerializer(typeof(TElement)); 
     while ((reader.NodeType == XmlNodeType.Element && reader.LocalName == localEntityElementName && reader.NamespaceURI == namespaceURI) 
      || reader.ReadToNextSibling(localEntityElementName, namespaceURI)) 
     { 
      // Using ReadSubtree instead of ReadOuterXml() avoids having do parse, reformat, then parse the formatted XML a second time 
      // by reading directly from the current stream only once. 
      TElement element; 
      using (var subReader = reader.ReadSubtree()) 
      { 
       element = (TElement)deserializer.Deserialize(subReader); 
      } 
      // Consume the EndElement also (or move past the current element if reader.IsEmptyElement). 
      reader.Read(); 
      yield return element; 
     } 
    } 
} 

並修改Deserialize()方法如下:

private Task<List<TAxEntity>> Deserialize(XmlReader reader) 
    { 
     var entities = reader.DeserializeSequence<TAxEntity>(EntityElementName, "" /* Pass the correct namespace here */).ToList(); 

     return Task.FromResult(entities); 
    }  

樣品.Net fiddle

注意,任何手動XmlReader代碼應該是單元測試既縮進和沒有鋸齒的XML,由於涉及跳過節點錯誤解析縮進的XML時有時掩蔽(因爲空白節點得到跳過。)

+0

這解決了我的問題,非常感謝! –

相關問題