Pour vérifier qu'un XmlReader
est déjà correctement positionné, vous pouvez vérifier si reader.NodeType == XmlNodeType.Element
et reader.Name == EntityElementName
. Ensuite, si le lecteur est déjà correctement positionné, ne numérisez pas vers l'avant en utilisant ReadToNextSibling()
.
Cependant, il y a quelques améliorations à apporter à votre algorithme:
Au lieu de vérifier la reader.Name
correcte, vérifiez si la LocalName
et NamespaceURI
sont comme prévu, et sinon, appelez reader.ReadToNextSibling(string localName,string namespaceURI)
. Cela évite le codage en dur des préfixes d'espace de noms, qui est un bug to be avoided. Au lieu de ReadOuterXml()
, appelez reader.ReadSubtree()
et passez le lecteur retourné directement à deserializer.Deserialize()
. Votre algorithme actuel analyse le XML, le reformate en une deuxième chaîne XML, puis analyse cette chaîne une seconde fois. L'utilisation de ReadSubtree()
permet au XmlSerializer
de diffuser un élément imbriqué directement à partir du XmlReader
entrant et évite ainsi cette analyse et reformatage supplémentaires.
Mettre tout cela ensemble, vous pouvez introduire la méthode d'extension de niveau inférieur suivant:
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;
}
}
}
Et modifier votre méthode Deserialize()
être comme suit:
private Task<List<TAxEntity>> Deserialize(XmlReader reader)
{
var entities = reader.DeserializeSequence<TAxEntity>(EntityElementName, "" /* Pass the correct namespace here */).ToList();
return Task.FromResult(entities);
}
Sample .Net fiddle.
Notez que tout code XmlReader
manuel doit être l'unité testée à la fois XML échancrée et non indenté, car les bogues qui impliquent des noeuds à sauter sont parfois masqués lors de l'analyse XML dentelée (parce que les nœuds blancs se sautée.)
Le saut est causé par ReadToNextSibling. Trouvez un autre moyen de savoir quand vous êtes à la fin, car ReadOuterXml avance déjà votre flux. – hoodaticus
Oui, je l'ai réalisé, c'est pourquoi je suis à la recherche d'une autre solution pour aller de l'avant sans lire. Merci! –
'while (lecteur.read()) {...}'? – PiLHA