如何检查另一个节点是否存在于xml中而不读 - C#
我想实现将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);
}
要检查的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时有时掩蔽(因为空白节点得到跳过。)
这解决了我的问题,非常感谢! –
的跳跃是由ReadToNextSibling引起。找到一些其他的方式来了解你到底什么时候,因为ReadOuterXml已经在推进你的流。 – hoodaticus
是的,我意识到这一点,这就是为什么我正在寻找另一种解决方案,期待没有阅读。谢谢! –
' while(reader.Read()){...}'? – PiLHA