Quelle est la meilleure façon d’parsingr (gros) XML en code C #?

J’écris un outil client SIG en C # pour récupérer des “fonctionnalités” dans un schéma XML basé sur GML (exemple ci-dessous) à partir d’un serveur. Les extraits sont limités à 100 000 fonctionnalités.

Je pense que le plus gros extrait.xml pourrait s’élever à environ 150 mégaoctets, alors il est évident que les parsingurs DOM ont été supprimés .

Ou peut-être y a-t-il un meilleur moyen que je n’ai pas encore envisagé? Comme XLINQ ou ????

S’il vous plaît quelqu’un peut-il me guider? Surtout en ce qui concerne l’efficacité de la mémoire d’une approche donnée. Sinon, je devrai “prototyper” les deux solutions et les profiler côte à côte.

Je suis un peu une crevette crue dans .NET. Toute orientation serait grandement appréciée.

En vous remerciant Keith


Exemple XML – jusqu’à 100 000 d’entre eux, jusqu’à 234 600 caractères par fonction.

      153.505004,-27.42196 153.505044,-27.422015 153.503992 .... 172 coordinates omitted to save space ... 153.505004,-27.42196       

    Utilisez XmlReader pour parsingr des documents XML volumineux. XmlReader fournit un access rapide, direct uniquement, non mis en cache aux données XML. (Forward-only signifie que vous pouvez lire le fichier XML du début à la fin mais ne peut pas revenir en arrière dans le fichier.) XmlReader utilise de petites quantités de mémoire, et équivaut à utiliser un lecteur SAX simple.

      using (XmlReader myReader = XmlReader.Create(@"c:\data\coords.xml")) { while (myReader.Read()) { // Process each node (myReader.Value) here // ... } } 

    Vous pouvez utiliser XmlReader pour traiter des fichiers d’une taille maximale de 2 gigaoctets (Go).

    Ref: Comment lire du XML à partir d’un fichier à l’aide de Visual C #

    Le 14 mai 2009: j’ai opté pour une approche hybride … voir le code ci-dessous.

    Cette version présente la plupart des avantages des deux:
    * le XmlReader / XmlTextReader (efficacité mémoire -> vitesse); et
    * le XmlSerializer (code-gen -> développement rapide et flexibilité).

    Il utilise XmlTextReader pour parcourir le document et crée des “doclets” qu’il désérialise en utilisant les classes XmlSerializer et “XML binding” générées avec XSD.EXE.

    Je suppose que cette recette est universellement applicable, et elle est rapide … Je suis en train d’parsingr un document XML de 201 Mo contenant 56 000 fonctionnalités GML en 7 secondes environ … l’parsing de l’ancienne implémentation VB6 a pris quelques minutes (voire heures) gros extraits … alors je vais bien.

    Encore une fois, un grand merci aux forumites pour avoir donné votre précieux temps. J’apprécie vraiment cela.

    Bravo à tous. Keith

     using System; using System.Reflection; using System.Xml; using System.Xml.Serialization; using System.IO; using System.Collections.Generic; using nrw_rime_extract.utils; using nrw_rime_extract.xml.generated_bindings; namespace nrw_rime_extract.xml { internal interface ExtractXmlReader { rimeType read(ssortingng xmlFilename); } ///  /// RimeExtractXml provides bindings to the RIME Extract XML as defined by /// $/Release 2.7/Documentation/Technical/SCHEMA and DTDs/nrw-rime-extract.xsd ///  internal class ExtractXmlReader_XmlSerializerImpl : ExtractXmlReader { private Log log = Log.getInstance(); public rimeType read(ssortingng xmlFilename) { log.write( ssortingng.Format( "DEBUG: ExtractXmlReader_XmlSerializerImpl.read({0})", xmlFilename)); using (Stream stream = new FileStream(xmlFilename, FileMode.Open)) { return read(stream); } } internal rimeType read(Stream xmlInputStream) { // create an instance of the XmlSerializer class, // specifying the type of object to be deserialized. XmlSerializer serializer = new XmlSerializer(typeof(rimeType)); serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode); serializer.UnknownAtsortingbute += new XmlAtsortingbuteEventHandler(handleUnknownAtsortingbute); // use the Deserialize method to restore the object's state // with data from the XML document. return (rimeType)serializer.Deserialize(xmlInputStream); } protected void handleUnknownNode(object sender, XmlNodeEventArgs e) { log.write( ssortingng.Format( "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}", e.LineNumber, e.LinePosition, e.Name, e.Text)); } protected void handleUnknownAtsortingbute(object sender, XmlAtsortingbuteEventArgs e) { log.write( ssortingng.Format( "XML_ERROR: Unknown Atsortingbute at line {0} position {1} : {2}='{3}'", e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value)); } } ///  /// xtractXmlReader provides bindings to the extract.xml /// returned by the RIME server; as defined by: /// $/Release X/Documentation/Technical/SCHEMA and /// DTDs/nrw-rime-extract.xsd ///  internal class ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl : ExtractXmlReader { private Log log = Log.getInstance(); public rimeType read(ssortingng xmlFilename) { log.write( ssortingng.Format( "DEBUG: ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl." + "read({0})", xmlFilename)); using (XmlReader reader = XmlReader.Create(xmlFilename)) { return read(reader); } } public rimeType read(XmlReader reader) { rimeType result = new rimeType(); // a deserializer for featureClass, feature, etc, "doclets" Dictionary serializers = new Dictionary(); serializers.Add(typeof(featureClassType), newSerializer(typeof(featureClassType))); serializers.Add(typeof(featureType), newSerializer(typeof(featureType))); List featureClasses = new List(); List features = new List(); while (!reader.EOF) { if (reader.MoveToContent() != XmlNodeType.Element) { reader.Read(); // skip non-element-nodes and unknown-elements. continue; } // skip junk nodes. if (reader.Name.Equals("featureClass")) { using ( SsortingngReader elementReader = new SsortingngReader(reader.ReadOuterXml())) { XmlSerializer deserializer = serializers[typeof (featureClassType)]; featureClasses.Add( (featureClassType) deserializer.Deserialize(elementReader)); } continue; // ReadOuterXml advances the reader, so don't read again. } if (reader.Name.Equals("feature")) { using ( SsortingngReader elementReader = new SsortingngReader(reader.ReadOuterXml())) { XmlSerializer deserializer = serializers[typeof (featureType)]; features.Add( (featureType) deserializer.Deserialize(elementReader)); } continue; // ReadOuterXml advances the reader, so don't read again. } log.write( "WARNING: unknown element '" + reader.Name + "' was skipped during parsing."); reader.Read(); // skip non-element-nodes and unknown-elements. } result.featureClasses = featureClasses.ToArray(); result.features = features.ToArray(); return result; } private XmlSerializer newSerializer(Type elementType) { XmlSerializer serializer = new XmlSerializer(elementType); serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode); serializer.UnknownAtsortingbute += new XmlAtsortingbuteEventHandler(handleUnknownAtsortingbute); return serializer; } protected void handleUnknownNode(object sender, XmlNodeEventArgs e) { log.write( ssortingng.Format( "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}", e.LineNumber, e.LinePosition, e.Name, e.Text)); } protected void handleUnknownAtsortingbute(object sender, XmlAtsortingbuteEventArgs e) { log.write( ssortingng.Format( "XML_ERROR: Unknown Atsortingbute at line {0} position {1} : {2}='{3}'", e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value)); } } } 

    Juste pour résumer, et rendre la réponse un peu plus évidente pour quiconque trouve ce fil dans Google.

    Avant .NET 2, XmlTextReader était l’parsingur XML le plus efficace en termes de mémoire disponible dans l’API standard (thanx Mitch 😉

    .NET 2 a introduit la classe XmlReader qui est encore meilleure. Il s’agit d’un iterator d’éléments en avant uniquement (un peu comme un parsingur StAX). (merci Cerebrus 😉

    Et rappelez-vous que les kiddies, de n’importe quelle instance XML, ont le potentiel d’être plus gros qu’environ 500k, N’UTILISEZ PAS DOM!

    Bravo à tous. Keith

    Un parsingur SAX pourrait être ce que vous recherchez. SAX ne vous oblige pas à lire l’intégralité du document en mémoire – il parsing le document de manière incrémentielle et vous permet de traiter les éléments au fur et à mesure. Je ne sais pas s’il y a un parsingur SAX fourni dans .NET, mais il y a quelques options open source que vous pouvez consulter:

    Voici un article connexe:

    • SAX vs XmlTextReader – SAX en C #

    Je voulais juste append cette méthode d’extension simple comme exemple d’utilisation de XmlReader (comme Mitch a répondu):

     public static bool SkipToElement (this XmlReader xmlReader, ssortingng elementName) { if (!xmlReader.Read ()) return false; while (!xmlReader.EOF) { if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == elementName) return true; xmlReader.Skip (); } return false; } 

    Et usage:

     using (var xml_reader = XmlReader.Create (this.source.Url)) { if (!SkipToElement (xml_reader, "Root")) throw new InvalidOperationException ("XML element \"Root\" was not found."); if (!SkipToElement (xml_reader, "Users")) throw new InvalidOperationException ("XML element \"Root/Users\" was not found."); ... }