如何检查另一个节点是否存在于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); 
    } 
+1

的跳跃是由ReadToNextSibling引起。找到一些其他的方式来了解你到底什么时候,因为ReadOuterXml已经在推进你的流。 – hoodaticus

+1

是的,我意识到这一点,这就是为什么我正在寻找另一种解决方案,期待没有阅读。谢谢! –

+2

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

要检查的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

这解决了我的问题,非常感谢! –