59 votes

Quelle est la meilleure façon d'analyser les (gros) XML dans le Code C#?

Je suis en train d'écrire un SIG outil client en C# pour récupérer des "features" dans un LANGAGE basé sur XML schéma (exemple ci-dessous) à partir d'un serveur. Les extraits sont limités à 100 000 caractéristiques.

Je guestimate que le plus grand extract.xml pourriez obtenir jusqu'à environ 150 mégaoctets, alors, évidemment, DOM analyseurs sont sorti, j'ai été en train de décider entre XmlSerializer et XSD.EXE généré liaisons --OU-- XmlReader et une main d'objet graphique.

Ou peut-être il ya une meilleure façon que je n'ai pas encore réfléchi? Comme XLINQ, ou ????

Svp quelqu'un peut-il me guider? Notamment en ce qui concerne l'efficacité de mémoire de toute approche. Si non je vais devoir le "prototype" les deux solutions et le profil de ces side-by-side.

Je suis un peu brut de crevettes dans .NET. Des conseils seraient grandement appréciés.

En vous remerciant. Keith.


Exemple de XML - jusqu'à 100 000 d'entre eux, jusqu'à 234,600 coords par fonction.

<feature featId="27168306" fType="vegetation" fTypeId="1129" fClass="vegetation" gType="Polygon" ID="0" cLockNr="51598" metadataId="51599" mdFileId="NRM/TIS/VEGETATION/9543_22_v3" dataScale="25000">
  <MultiGeometry>
    <geometryMember>
      <Polygon>
        <outerBoundaryIs>
          <LinearRing>
            <coordinates>153.505004,-27.42196 153.505044,-27.422015 153.503992 .... 172 coordinates omitted to save space ... 153.505004,-27.42196</coordinates>
          </LinearRing>
        </outerBoundaryIs>
      </Polygon>
    </geometryMember>
  </MultiGeometry>
</feature>

63voto

Mitch Wheat Points 169614

Utiliser XmlReader pour parser des documents XML volumineux. XmlReader rapide avant uniquement, non mis en cache d'accéder aux données XML. (Avant uniquement signifie que vous pouvez lire le fichier XML à partir de début à la fin, mais ne peut pas se déplacer vers l'arrière dans le fichier.) XmlReader utilise de petites quantités de mémoire, et est équivalent à l'aide d'un simple lecteur SAX.

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

Vous pouvez utiliser XmlReader pour traiter les fichiers qui sont jusqu'à 2 gigaoctets (GO) de taille.

Ref: Comment lire un fichier XML à l'aide de Visual C#

16voto

corlettk Points 5051

Asat 14 Mai 2009: j'ai passé à l'aide d'une approche hybride... voir code ci-dessous.

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

Il utilise le XmlTextReader à parcourir le document, et crée des "doclets", dont la désérialise en utilisant le XmlSerializer et "liaison XML" classes générées avec XSD.EXE.

Je suppose que cette recette est universellement applicable, et c'est rapide... je suis de l'analyse d'une 201 MO Document XML contenant de 56 000 GML Fonctionnalités en environ 7 secondes... le vieux VB6 mise en œuvre de cette application pris quelques minutes (voire heures) pour analyser de larges extraits... donc je suis lookin' bon pour aller.

Encore une fois, un GRAND Merci à la forumites pour le don de votre temps précieux. J'ai vraiment l'apprécier.

Acclamations de 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(string xmlFilename);
    }

    /// <summary>
    /// RimeExtractXml provides bindings to the RIME Extract XML as defined by
    /// $/Release 2.7/Documentation/Technical/SCHEMA and DTDs/nrw-rime-extract.xsd
    /// </summary>
    internal class ExtractXmlReader_XmlSerializerImpl : ExtractXmlReader
    {
        private Log log = Log.getInstance();

        public rimeType read(string xmlFilename)
        {
            log.write(
                string.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.UnknownAttribute += 
                new XmlAttributeEventHandler(handleUnknownAttribute);
            // 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(
                string.Format(
                    "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",
                    e.LineNumber, e.LinePosition, e.Name, e.Text));
        }

        protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)
        {
            log.write(
                string.Format(
                    "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",
                    e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));
        }

    }

    /// <summary>
    /// 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
    /// </summary>
    internal class ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl :
        ExtractXmlReader
    {
        private Log log = Log.getInstance();

        public rimeType read(string xmlFilename)
        {
            log.write(
                string.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<Type, XmlSerializer> serializers = 
                new Dictionary<Type, XmlSerializer>();
            serializers.Add(typeof(featureClassType), 
                newSerializer(typeof(featureClassType)));
            serializers.Add(typeof(featureType), 
                newSerializer(typeof(featureType)));

            List<featureClassType> featureClasses = new List<featureClassType>();
            List<featureType> features = new List<featureType>();
            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 (
                        StringReader elementReader =
                            new StringReader(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 (
                        StringReader elementReader =
                            new StringReader(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.UnknownAttribute += 
                new XmlAttributeEventHandler(handleUnknownAttribute);
            return serializer;
        }

        protected void handleUnknownNode(object sender, XmlNodeEventArgs e)
        {
            log.write(
                string.Format(
                    "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",
                    e.LineNumber, e.LinePosition, e.Name, e.Text));
        }

        protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)
        {
            log.write(
                string.Format(
                    "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",
                    e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));
        }
    }
}

12voto

corlettk Points 5051

Juste pour résumer, et faire la réponse un peu plus évident pour toute personne qui trouve ce fil dans google.

Avant .NET 2 le XmlTextReader a été le plus efficace en terme de mémoire analyseur XML disponible dans l'API standard (merci Mitch;-)

.NET 2 introduit la classe XmlReader ce qui est mieux encore, C'est un avant-seul élément itérateur (un peu comme un StAX analyseur). (merci Cerebrus;-)

Et n'oubliez pas de gosses, de toute instance XML a le potentiel pour être supérieur à 500k, NE PAS UTILISER de DOM!

Acclamations de tous. Keith.

6voto

Andy White Points 36586

Un SAX parser peut-être ce que vous cherchez. SAX ne vous oblige pas à lire l'intégralité du document en mémoire - il analyse à travers elle de manière incrémentale et vous permet de traiter les éléments que vous allez. Je ne sais pas si il y a un parser SAX fourni dans .NET, mais il y a quelques opensource options que vous pouvez consulter:

Voici un related post:

1voto

Michael Logutov Points 632

Je voulais juste rajouter cette simple méthode d'extension comme un exemple de l'utilisation de XmlReader (comme Mitch répondu):

public static bool SkipToElement (this XmlReader xmlReader, string elementName)
{
    if (!xmlReader.Read ())
        return false;

    while (!xmlReader.EOF)
    {
        if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == elementName)
            return true;

        xmlReader.Skip ();
    }

    return false;
}

Et l'utilisation:

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.");

    ...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X