要檢查的XmlReader
已經被正確定位,您可以檢查是否reader.NodeType == XmlNodeType.Element
和reader.Name == EntityElementName
。然後,如果閱讀器已正確定位,請勿使用ReadToNextSibling()
進行向前掃描。
不過,也有你的算法進行一些改進:
檢查正確reader.Name
相反的,檢查是否LocalName
和NamespaceURI
的預期,如果沒有,請致電reader.ReadToNextSibling(string localName,string namespaceURI)
。這避免了名稱空間前綴的硬編碼,這是一個bug to be avoided。
而不是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時有時掩蔽(因爲空白節點得到跳過。)
來源
2017-07-21 21:49:23
dbc
的跳躍是由ReadToNextSibling引起。找到一些其他的方式來了解你到底什麼時候,因爲ReadOuterXml已經在推進你的流。 – hoodaticus
是的,我意識到這一點,這就是爲什麼我正在尋找另一種解決方案,期待沒有閱讀。謝謝! –
' while(reader.Read()){...}'? – PiLHA