IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

comptage de balise <Page> dans un grand fichier XML


Sujet :

Python

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 28
    Points : 25
    Points
    25
    Par défaut comptage de balise <Page> dans un grand fichier XML
    Bonjour à tous,
    Je suis débutante en Python et j'essaye de faire un script pour extraire le nombre de balise <Page> afin de connaitre le nombre de pages que j'ai dans mon fichier XML. Ce fichier XML est très grand c'est pourquoi j'utilise le module SAX.
    Voici mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    #!/usr/bin/python
    #-*- coding:utf-8 -*-
    import string
    import sys
    from xml.sax import ContentHandler,make_parser
     
     
    class MaClasseContentHandler(ContentHandler):
      def startElement(self, name, attrs):
         print "Start element:", name
     
    class MaClassePage(ContentHandler):
        def __init__(self):
            ContentHandler.__init__(self)
            self.n = 0
     
        def startElement(self, Page, attrs):
            self.n += 1
     
    ####parser = make_parser()# parser le doc
    ####handler = MaClasseContentHandler()
    ####parser.setContentHandler(handler)
    ####parser.parse("monfic.xml")
     
    handler = MaClassePage()
    parser = make_parser()
    parser.setContentHandler(handler)
    parser.parse("monfic.xml")
     
    print  handler.n
    Merci de votre aide !

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 298
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 298
    Points : 6 778
    Points
    6 778
    Par défaut
    Salut,

    Si minidom te convient pareil voici un exemple, je n'ai pas de fichier avec la balise <Page> mais j'en ai un très gros (112.000 lignes) avec des balises <trk>

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    # -*- coding: utf-8 -*-
     
    import xml.dom.minidom
     
    class HandleGPX(object):
        def __init__(self, f):
            self.dom = xml.dom.minidom.parse(f)
     
        def read_gpx(self):
            trks = self.dom.getElementsByTagName("trk")
            print "Found {0} tracks".format(len(trks))
     
    hgpx = HandleGPX("/home/vincent/devel/GPS/GPSout.gpx")
    hgpx.read_gpx()
    Il a mis une douzaine de secondes quand même, peut-être que sax est plus rapide.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 28
    Points : 25
    Points
    25
    Par défaut
    Bonjour
    Merci VinsS pour ta réponse.
    J'ai déjà fait un code avec minidom, mais il ne marche pas sur mon document xml.
    Je préfère le faire en sax puisqu'il ne met pas tout le document en mémoire.
    Merci

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 240
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 240
    Points : 36 696
    Points
    36 696
    Par défaut
    Salut,
    Votre code est un peu "brouillon" mais "fonctionne" modulo le fait que la méthode "startElement" étant appelée chaque fois qu'un élément est "rencontré", si vous voulez "comptez" les "tags" page, il faut être un peu plus explicite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        def startElement(self, name, attrs):
            print "Start element:", name
            if name == 'page':                     #<---
                self.n += 1
    Sinon, j'écrirais le tout ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from xml.sax import make_parser, handler
    class TagCounter(handler.ContentHandler):
     
        def __init__(self, *tags):
             self._counters = { tag:0 for tag in tags }
             handler.ContentHandler.__init__(self)
     
        def startElement(self, tag, attrs):
            if tag in self._counters:
                 self._counters[tag] += 1
     
        def endDocument(self):
             print 'end document'
             print self._counters
    => TagCounter accepte une liste de "tags" à compter.

    Une des difficultés étant "les tests", je vous suggère d'utiliser StringIO (ou encore io). Cela permet de faire des "reproducteurs" faciles à copier/coller/poster...
    Genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    if __name__ == '__main__':
         import StringIO as io
         XML = """
         <a>
            <bb>
            </bb>
            <bb>
              <c>
                <d>
                </d>
              </c>
            </bb>
         </a>"""         
         xmlfile = io.StringIO(XML)          
         parser = make_parser()
         parser.setContentHandler(TagCounter('bb', 'c'))
         parser.parse(xmlfile)
    Il n'est pas nécessaire de passer par SAX pour faire cela. La bibliothèque xml.etree.ElementTree "vient" avec un parser qui peut être nourrit ("feed") au fil de l'eau et attaquer une classe de handling des "events" similaire.
    Comme on jette tout, çà ne pose pas de soucis (côté utilisation mémoire).

    Le code ressemble à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import xml.etree.ElementTree as et
     
    class TagCounter:                     
         def __init__(self, *tags):
             self._counters = { tag:0 for tag in tags }
     
          def end(self, tag):
              pass
     
         def data(self, tag):
              pass
     
         def start(self, tag, attrib):
             if tag in self._counters:
                 self._counters[tag] += 1
     
         def close(self):
             print (self._counters)
    Pour le tester,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    if __name__ == '__main__':
         import StringIO as io
         XML = """<a>
            <bb>
            </bb>
            <bb>
              <c>
                <d>
                </d>
              </c>
            </bb>
         </a>"""         
         xmlfile = io.StringIO(XML)          
         counters = TagCounter('bb', 'c')
         parser = et.XMLParser(target=counters)
         for line in xmlfile.readlines():
              print 'line', line
              parser.feed(line)
         parser.close()
    nota, la chose suivante ne sert qu'à montrer "au fil de l'eau" mais n'a pas grande utilité.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
         for line in xmlfile.readlines():
              print 'line', line
              parser.feed(line)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    J'aurais une question. Vu qu'il s'agit uniquement de compter Une regexp ne ferais pas l'affaire? Ou c'est plus lent?
    Win 10 64 bits / Linux Mint 18, - AMD A6 Quad: Py27 / Py35
    CONTENU D'UNE QUESTION
    Exemples:
    - Configuration (système d'exploitation, version de Python et des bibliothèques utilisées)
    - Code source du morceau de programme où il y a un bogue
    - Ligne de code sur laquelle le bogue apparaît
    - Erreur complète retournée pas l'interpréteur Python
    - Recherche déjà effectuée (FAQ, Tutoriels, ...)
    - Tests déjà effectués

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 240
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 240
    Points : 36 696
    Points
    36 696
    Par défaut
    Salut,

    Citation Envoyé par afranck64 Voir le message
    J'aurais une question. Vu qu'il s'agit uniquement de compter Une regexp ne ferais pas l'affaire? Ou c'est plus lent?
    Utiliser 'grep' serait encore plus simple et rapide!
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 28
    Points : 25
    Points
    25
    Par défaut
    Bonjour à tous et merci à tous pour votre aide

    @wiztricks :
    J'ai essayé ton test, justement je cherchai un moyen, mais, quand j'applique le test j'ai une note sur le shell qui dit "TypeError: __init__() takes exactly 1 argument (3 given)"

    Merci

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 240
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 240
    Points : 36 696
    Points
    36 696
    Par défaut
    Salut,

    Citation Envoyé par funmatica Voir le message
    @wiztricks :
    J'ai essayé ton test, justement je cherchai un moyen, mais, quand j'applique le test j'ai une note sur le shell qui dit "TypeError: __init__() takes exactly 1 argument (3 given)"
    Sans le code, je ne puis que compatir.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 28
    Points : 25
    Points
    25
    Par défaut
    Bonjour,

    Voici le code jusqu'à présent, j'ai du mal à l'adapter !

    #!/usr/bin/python
    #-*- coding:utf-8 -*-

    import string
    import sys

    from xml.sax import ContentHandler,make_parser


    class MaClasseContentHandler(ContentHandler):
    def startElement(self, name, attrs):
    print "Start element:", name
    if name == "Page":
    self.n += 1

    class MaClassePage(ContentHandler):
    def __init__(self):
    ContentHandler.__init__(self)
    self.n = 0

    def startElement(self, name, attrs):
    self.n += 1


    handler = MaClassePage()
    parser = make_parser()
    parser.setContentHandler(handler)
    parser.parse("monfic.xml")

    print handler.n

    # TEST

    if __name__ == '__main__':
    import StringIO as io
    XML = """
    <a>
    <bb>
    </bb>
    <bb>
    <c>
    <d>
    </d>
    </c>
    </bb>
    </a>"""
    xmlfile = io.StringIO(XML)
    parser = make_parser()
    parser.setContentHandler(handler('bb', 'c'))
    parser.parse(xmlfile)

    Merci d'avance pour votre aide !

  10. #10
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    En plus joli

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #!/usr/bin/python
    #-*- coding:utf-8 -*-
     
    import string
    import sys
     
    from xml.sax import ContentHandler,make_parser
     
     
    class MaClasseContentHandler(ContentHandler):
        def startElement(self, name, attrs):
            print "Start element:", name
            if name == "Page":
                self.n += 1
     
    class MaClassePage(ContentHandler):
        def __init__(self):
            ContentHandler.__init__(self)
            self.n = 0
     
        def startElement(self, name, attrs):
            self.n += 1
     
     
    handler = MaClassePage()
    parser = make_parser()
    parser.setContentHandler(handler)
    parser.parse("monfic.xml")
     
    print handler.n
     
    # TEST
     
    if __name__ == '__main__':
        import StringIO as io
        XML = """
        <a>
            <bb>
            </bb>
            <bb>
                <c>
                    <d>
                    </d>
                </c>
            </bb>
        </a>"""
        xmlfile = io.StringIO(XML)
        parser = make_parser()
        parser.setContentHandler(handler('bb', 'c'))
        parser.parse(xmlfile)
    Win 10 64 bits / Linux Mint 18, - AMD A6 Quad: Py27 / Py35
    CONTENU D'UNE QUESTION
    Exemples:
    - Configuration (système d'exploitation, version de Python et des bibliothèques utilisées)
    - Code source du morceau de programme où il y a un bogue
    - Ligne de code sur laquelle le bogue apparaît
    - Erreur complète retournée pas l'interpréteur Python
    - Recherche déjà effectuée (FAQ, Tutoriels, ...)
    - Tests déjà effectués

  11. #11
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    Avec le regex-finder:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import re
     
    XML = """
        <a>
            <bb>
            </bb>
            <bb>
                <c>
                    <d>
                    </d>
                </c>
            </bb>
        </a>"""*16384
     
    def count_pattern(pattern="<bb>", filename=None, file=None, text=None):
        if file:
            return len(re.count_parttern(pattern, file.read()))
        elif filename:
            return len(re.findall(pattern, open(filename).read()))
        elif text:
            return len(re.findall(pattern, text))
        else:
            return -1
     
    if __name__ == "__main__":
        print (count_pattern("<bb>", text=XML))
    Win 10 64 bits / Linux Mint 18, - AMD A6 Quad: Py27 / Py35
    CONTENU D'UNE QUESTION
    Exemples:
    - Configuration (système d'exploitation, version de Python et des bibliothèques utilisées)
    - Code source du morceau de programme où il y a un bogue
    - Ligne de code sur laquelle le bogue apparaît
    - Erreur complète retournée pas l'interpréteur Python
    - Recherche déjà effectuée (FAQ, Tutoriels, ...)
    - Tests déjà effectués

  12. #12
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 240
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 240
    Points : 36 696
    Points
    36 696
    Par défaut
    Salut afranck64,

    Si on fait du SAX, c'est pour éviter de lire tout le fichier d'un coup!
    Donc, certes, il est "possible" d'écrire cela avec des regexp mais pour envoyer à la regexp les caractères un par un, il faut plus de code que le "toy" proposé.

    Avec le parser.feed, çà supporte:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
         parser = et.XMLParser(target=counters)
         for line in xmlfile.readlines():
              print 'line', line
              for c in line:
                  parser.feed(c)
         parser.close()

    @funmatica
    Plusieurs choses.
    Pourquoi définir:
    • class MaClasseContentHandler(ContentHandler) qui a une méthode qui filtre les name == "Page" et
    • class MaClassePage(ContentHandler) qui compte les appels à la méthode startElement

    Essayez d'être cohérent, çà évitera des maux de têtes!

    l'appel a handler('bb', 'c') se vautre car après l'initialisation de handler = MaClassePage()... handler n'est plus un "callable" sauf à définir la méthode __call__ mais ce n'est pas ce qu'on veut. Inutile de s'égarer.

    Cela corrigé (écrire: handler = MaClassePage plutôt que MaClassePage()) on tombe dans la méthode __init__ n'admettant pour paramètre que (self) et non les 'bb', 'c' qu'on lui propose.

    Hmm reprenons le b.a.ba du cut & paste!

    Le TagCounter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from xml.sax import handler,make_parser
     
    class TagCounter(handler.ContentHandler):
        def __init__(self, *tags):
             self._counters = { tag:0 for tag in tags }
             handler.ContentHandler.__init__(self)
     
        def startElement(self, tag, attrs):
            if tag in self._counters:
                 self._counters[tag] += 1
     
        def endDocument(self):
             print 'end document'
             print self._counter
    On le teste, il marche (ou pas) et on ferme.

    Mais on le "spécialise" pour compter les tags "Page", genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class CountPage(TagCounter):
        def __init__(self):
            TagCounter.__init__(self, 'Page')
     
    class Countbb(TagCounter):  # pas envie de re-ecrire les data de tests!
        def __init__(self):
             TagCounter.__init__(self, 'bb')
     
    if __name__ == '__main__':
        import StringIO as io
        XML = "<a><bb></bb><bb><c><d></d></c></bb></a>"
        xmlfile = io.StringIO(XML)
        parser = make_parser()
        parser.setContentHandler(Countbb())
        parser.parse(xmlfile)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 12/05/2009, 11h18
  2. afficher dans combobox contenu fichier xml
    Par gilbertbicot dans le forum Langage
    Réponses: 1
    Dernier message: 22/01/2009, 15h23
  3. [DOM] (org.w3c.dom) copier un noeud d'un fichier XML dans un autre fichier XML
    Par snoop dans le forum Format d'échange (XML, JSON...)
    Réponses: 4
    Dernier message: 13/02/2007, 18h22
  4. Réponses: 13
    Dernier message: 27/10/2006, 12h50
  5. Importer le contenu un fichier xml dans un autre fichier xml
    Par gedeon555 dans le forum XML/XSL et SOAP
    Réponses: 5
    Dernier message: 27/07/2005, 12h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo