2017-07-21 3 views
2

xmlをオブジェクトのリストに逆直列化するコードを実装したいと思います。 whileコードが前方に読み込まれ、他のノードが1つおきにスキップされるというコードで問題が見つかりました。このコードのwhileループで実装されるxmlの次のノードをチェックする適切な方法は何ですか?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を2番目のXML文字列に再フォーマットし、2番目にその文字列を解析します。 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を。インデントされたXMLを解析するときにスキップノードを含むバグが時々マスクされているので、手動XmlReaderコードは、ユニットテストさインデントおよびインデントを解除しましXMLの両方でなければならないこと

注(空白ノードがスキップ得るからである。)

+0

これは私の問題を解決しました、ありがとうございます! –

関連する問題