Optimisation mémoire pour la lecture d'un fichier XML

skimpyskimpy Membre
04:53 modifié dans API AppKit #1
Bonjour,

Afin de me familiariser avec la classe NSXMLParser, j'ai écrit une petite application qui parse un fichier XML. Afin de stocker les informations contenues entre les balises XML, j'ai créé un Modèle. Les 2 questions que je me posais sont les suivantes :

1. Est-ce que j'ai raison de créer un modèle ?
2. Si j'ai un fichier XML assez volumineux, je trouve ennuyeux de charger tout le contenu en mémoire. Quelles sont les solutions qui existent pour palier à  ce problème ?

Merci

Réponses

  • CéroceCéroce Membre, Modérateur
    04:53 modifié #2
    1. Oui
    OK, OK, je développe... Bon clairement, quelque soit l'application, Cocoa est basée sur le MVC, alors si on veut faire les choses correctement, mais aussi se faciliter la vie (si, si), il faut aller dans ce sens et créer un Modèle.
    Ton modèle n'a pas forcément besoin d'être complexe. Parfois, un NSMutableArray de NSDictionnaries fait très bien l'affaire pour du XML.

    2. Je donne ma langue au chat, puisqu'il me semble que NSData ne sait charger que des fichiers entiers. Si tu obtiens le XML par le réseau, alors la réponse est différente.
  • AliGatorAliGator Membre, Modérateur
    04:53 modifié #3
    2. NSXMLParser est un parseur SAX, autrement dit événementiel. Il parse le fichier XML au fur et à  mesure de sa lecture, te préviens quand il rencontre des tags d'ouverture ou de fermeture etc, puis continue. A toi d'en faire ce que tu veux.

    Du coup tu n'es pas obligé de "tout charger en mémoire", dans le sens où c'est de l'événementiel, tu n'es pas obligé dans ton modèle que tu construit au fur et à  mesure du parsing de garder tout l'arbre XML que tu rencontres (sinon cela correspond à  faire du DOM, par opposition au SAX, donc d'avoir à  la fin un gros objet représentant tout ton document XML dans son ensemble, même si tu n'en as besoin que d'une partie).

    Le mieux est donc de ne stocker dans ton modèle que ce qui t'es nécessaire. Rien ne t'empêche si tu rencontres lors du parsing SAX par NSXMLParser des tags ouvrants dont tu n'as rien à  f...aire, de les ignorer, nul besoin de les copier dans ton modèle.

    C'est toute la différence justement entre du parsing SAX (événementiel) et DOM (arbre modèle complet conservé)
  • skimpyskimpy Membre
    04:53 modifié #4
    Merci pour vos explications. Le point que je n'arrive pas à  voir (et ce n'est sûrement pas lié à  NSXMLParser) est aussi de savoir si je peux lire par exemple 2 balises, envoyer un traitement, attendre la fin de ce traitement pour poursuivre la lecture du fichier.

    Est-ce que c'est réalisable ? Par exemple dire au parser :

    Quand tu as lu 2 balises de type <balise1>, tu envoies un traitement et tu attends la fin de ce traitement avant de continuer de lire le document.

    J'ai juste mis un exemple XML pour illustrer mes propos :

    <br />&lt;balise1 subject=&quot;Informations 1&quot;&gt;<br />&nbsp; &lt;sousbalise&gt;Données 1&lt;/sousbalise&gt;<br />&nbsp; &lt;sousbalise&gt;Données 2&lt;/sousbalise&gt;<br />&lt;/balise1&gt;<br /><br />&lt;balise1 subject=&quot;Informations 2&quot;&gt;<br />&nbsp; &lt;sousbalise&gt;Données 1&lt;/sousbalise&gt;<br />&nbsp; &lt;sousbalise&gt;Données 2&lt;/sousbalise&gt;<br />&lt;/balise1&gt;<br /><br />&lt;balise1 subject=&quot;Informations 3&quot;&gt;<br />&nbsp; &lt;sousbalise&gt;Données 1&lt;/sousbalise&gt;<br />&nbsp; &lt;sousbalise&gt;Données 2&lt;/sousbalise&gt;<br />&lt;/balise1&gt;<br /><br />&lt;balise1 subject=&quot;Informations 4&quot;&gt;<br />&nbsp; &lt;sousbalise&gt;Données 1&lt;/sousbalise&gt;<br />&lt;/balise1&gt;<br /><br />
    


    Merci
  • AliGatorAliGator Membre, Modérateur
    04:53 modifié #5
    NSXMLParser est synchrone. Donc c'est ce qui est fait par défaut.

    Donc si dans la méthode "[tt]parser:didStartElement:[/tt]" tu mets un truc genre [tt]if ([tagName isEqualToString:@balise1]) countBalise1++;[/tt] puis [tt]if (countBalise1 == 2) { [self faireTraitement]; }[/tt]
    Alors il va exécuter toute la méthode "faireTraitement", et seulement quand elle aura finie, il va reprendre la main et continuer.

    Ce qui n'est d'ailleurs pas forcément une bonne chose si tu ne multithread pas ton parseur car cela va alors bloquer ton thread, donc si tu fais tout ça dans le main thread, cela va bloquer toute ton UI et donner à  l'utilisateur l'impression que ton application aura "gelé" (puisque pendant tout ce temps il ne pourra pas déplacer la fenêtre ou cliquer sur des boutons, voire risque d'avoir le fameux curseur de roue qui tourne)

    Après ça dépend la longueur de ton traitement en question, ce n'est jamais idéal de bloquer le main thread donc c'est à  éviter, mais quand on débute les considérations de multithreading sont loin d'être simples à  aborder donc pour commencer...
  • skimpyskimpy Membre
    04:53 modifié #6
    Les traitements que je dois lancer sont effectivement longs. Est-ce que le Concurrency Programming Guide est un bon début ?
  • AliGatorAliGator Membre, Modérateur
    04:53 modifié #7
    En effet un excellent début du coup :)
Connectez-vous ou Inscrivez-vous pour répondre.