Partage
  • Partager sur Facebook
  • Partager sur Twitter

Boucler sur des balises xml et exporter dans csv

id + le contenu d'une balise dans une ligne

    16 juin 2021 à 11:09:30

    Bonjour,

    Je suis entrain de convertir un fichier xml (de plus de 150 000 enregistrements avec plus de 50 tags) et j'ai besoin d'extraire de chaque ligne avec le même id + le contenu de mes références et les exporter dans csv.

    voici un exemple simplifié de ce que je souhaite avoir comme résultat


    id unique : 1 ; non de la note : "ma note" ; reference _mot : Chaise; reference : 1,2,3;

    id unique : 1 ;                                             ; reference _mot : Armoire; reference : 3,4,5;

    id unique : 1 ;                                             ; reference _mot : Canapé; reference : 6,7,8;

    id unique : 2;..
    ...

    Mon code m'affiche des erreurs quand à la partie "sources" je n'arrive pas donc à boucler sur les références et stocker chacune dans une ligne avec le même id unique.


    Voici à quoi ressemble mon code python + xml

    Merci d'avance

    SOURCES_REFS = []
    SOURCES_DUPS = [ 0 ]
    
    class Note(object):
    
        OLDS = {
            'UNIQUE_KEY'    : 'key',
            'CREATE_DATE'   : 'create_date',
            'NOM'           : 'nom_note',
            'AUTEUR'        : 'auteur',
            'SRC'           : 'sources',
        }
    
        FIELDS = list(OLDS.values())
        TAG = 'NOTE'
    
    
    
    
        def  __init__(self, separator=';'):
            self.separator = separator
    
        def start(self, e):
            if e.tag in self.OLDS.keys():
                attr = self.OLDS[e.tag]
                value = e.text.strip() if e.text else e.text
                if ( attr == 'create_date' or attr == 'modify_date' ):
                    value = format_date(e.get('display'))
                elif attr == 'nom_note' or\
                    attr == 'auteur':
                    value = '|'.join(value.split('_RS_'))
                #loop arround sources whatever a number...
                elif attr == 'sources':
                    for child in e.iterdescendants():
                        if child.tag == 'SRC_MOT':
                            # UNIQUE_KEY
                            ref = (child.text, ref[1])
                        elif child.tag == 'S_REF':
                            refs = child.text.split(';')
                            for part in refs:
                                # remove surrounding spaces (trim)
                                r = part.strip()
                                # merge multiple spaces into one
                                r = ' '.join(r.split())
                                self.add_source_reference((ref[0], r))
                setattr(self, attr, value)
            return None
    
    
        def end(self, e):
            if e.tag == self.TAG:
                values = []
                for attr in self.FIELDS:
                    value = getattr(self, attr, '') or ''
                    values.append(value)
                csv = self.separator.join('"{0}"'.format(w) for w in values)
                self.reset()
                return csv
            return None
    
        def reset(self):
            for attr in self.FIELDS:
                if hasattr(self, attr):
                    delattr(self, attr)
    
        def add_source_reference(self, ref):
            try:
                index = SOURCES_REFS.index(ref)
                SOURCES_DUPS[0] += 1
            except ValueError:  # first reference
                index = len(SOURCES_REFS)
                SOURCES_REFS.append(ref)
            try:
                if index not in self.sources:
                    self.sources.append(index)
            except AttributeError:
                setattr(self, 'sources', [index, ])
    
        def reset(self):
            for attr in self.OLDS.values():
                if hasattr(self, attr):
                    delattr(self, attr)   
    
    
    def format_date(value):
        parts = value.split('/')
        dd = parts[0].strip()
        mm = parts[1].strip()
        yyyy = parts[2].strip()[:4]
        return '%s/%s/%s' % (yyyy, mm, dd)
    



    <?xml version='1.0' encoding='UTF-8'?>
    <NOTES>
        <NOTE>
            <UNIQUE_KEY>1</UNIQUE_KEY>
            <NOM>MA NOTE </NOM>
            <CREATE_USER>admin</CREATE_USER>
            <CREATE_DATE display="14/02/2013 00:00:00">14022013000000</CREATE_DATE>
            <AUTEUR display="14/02/2013 00:00:00">14022013000000</AUTEUR>
            <SRCS>
                <SRC>
                    <SRC_MOT display="CHAISE" digest="CHAISE" source="note" table_name="MOBILIER">1</SRC_MOT>
                    <S_REF>1,2,3</S_REF>
                    <SRC_REF>CHAISE - 1,2,3</SRC_REF>
                </SRC>
                <SRC>
                    <SRC_MOT display="ARMOIRE" digest="ARMOIRE" source="note" table_name="MOBILIER">2</SRC_MOT>
                    <S_REF>4,5,6 autres références</S_REF>
                    <SRC_REF>ARMOIRE - 4,5,6 autres références</SRC_REF>
                </SRC>
                <SRC>
                    <SRC_MOT display="CANAPE" digest="CANAPE" source="note" table_name="MOBILIER">3</SRC_MOT>
                    <S_REF>7,8,9</S_REF>
                    <SRC_REF>CANAPE - 7,8,9</SRC_REF>
                </SRC>
            </SRCS>
        </NOTE>
    </NOTES>



    -
    Edité par Linus_11 16 juin 2021 à 11:42:24

    • Partager sur Facebook
    • Partager sur Twitter

    Nobody is perfect I'm Nobody...

      16 juin 2021 à 11:11:47

      C'est quoi la question ?
      • Partager sur Facebook
      • Partager sur Twitter

      Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
      La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

        16 juin 2021 à 11:24:45

        fred1599, mon code affiche cette erreur

        Traceback (most recent call last):
          File "C:\Users\sim\Desktop\script export\en cours\convert.py", line 65, in <module>
            parse(create_parser().parse_args())
          File "C:\Users\sim\Desktop\script export\en cours\convert.py", line 61, in parse
            write_csv(fd, context, target)
          File "C:\Users\sim\Desktop\en cours\convert.py", line 39, in write_csv
            line = getattr(target, action)(e)
          File "C:\Users\sim\Desktop\en cours\note.py", line 37, in start
            ref = (child.text, ref[1])
        UnboundLocalError: local variable 'ref' referenced before assignment
        

        Et sur mon csv la colonne "sources" est vide !
        Comment mon code puis générer des lignes qui correspondent aux références "SRC_MOT" et "S_REF"  ? cf: mon exemple.

        -
        Edité par Linus_11 16 juin 2021 à 11:31:09

        • Partager sur Facebook
        • Partager sur Twitter

        Nobody is perfect I'm Nobody...

          16 juin 2021 à 11:39:59

          if child.tag == 'SRC_MOT':

          dans le cas où on rentre pas dans cette condition, tu dois définir ta variable ref car ligne 45, cette variable risque de ne pas exister

          ou alors vérifier que cette variable existe

          elif child.tag == 'S_REF' and ref:

          et après ligne 33 définir ref à la valeur None donc ref = None

          -
          Edité par fred1599 16 juin 2021 à 11:44:14

          • Partager sur Facebook
          • Partager sur Twitter

          Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
          La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

            16 juin 2021 à 11:40:34

            Linus_11 a écrit:

            fred1599, mon code affiche cette erreur

            Traceback (most recent call last):
              File "C:\Users\sim\Desktop\script export\en cours\convert.py", line 65, in <module>
                parse(create_parser().parse_args())
              File "C:\Users\sim\Desktop\script export\en cours\convert.py", line 61, in parse
                write_csv(fd, context, target)
              File "C:\Users\sim\Desktop\en cours\convert.py", line 39, in write_csv
                line = getattr(target, action)(e)
              File "C:\Users\sim\Desktop\en cours\note.py", line 37, in start
                ref = (child.text, ref[1])
            UnboundLocalError: local variable 'ref' referenced before assignment
            


            Et sur mon csv la colonne "sources" est vide !
            Comment mon code puis générer des lignes qui correspondent aux références "SRC_MOT" et "S_REF"  ? cf: mon exemple.

            -
            Edité par Linus_11 il y a 6 minutes

            T'as cherché ce que voulait dire le message d'erreur ? Tu aurais pu répondre à ta question seul.

            Ce que ça te dit, c'est que tu cherches à accéder à une valeur (ref[1]) alors que la variable ref n'existe pas encore, puisque que tu es en train de la créer et lui assigner une valeur (ref = ...)

            • Partager sur Facebook
            • Partager sur Twitter
              16 juin 2021 à 11:47:02

              J'ai compris que la variable n'est pas définie
              Mais quand je fais une initiation de 'value' + ref

              le csv est vide cette fois-ci avec une autre erreur

                        elif attr == 'sources':
                              
                              value = None                
                              ref = (None, None)  # (source, reference)
                              for child in e.iterdescendants():
                                  if child.tag == 'SRC_MOT':
                                      # UNIQUE_KEY
                                      ref = (child.text, ref[1])
                                  elif child.tag == 'S_REF':
                                      refs = child.text.split(';')
                                      for part in refs:
                                          # remove surrounding spaces (trim)
                                          r = part.strip()
                                          # merge multiple spaces into one
                                          r = ' '.join(r.split())
                                          self.add_source_reference((ref[0], r))
                          setattr(self, attr, value)



              \script export\en cours\note.py", line 78, in add_source_reference
                  if index not in self.sources:
              TypeError: argument of type 'NoneType' is not iterable
              
              



              • Partager sur Facebook
              • Partager sur Twitter

              Nobody is perfect I'm Nobody...

                16 juin 2021 à 11:50:45

                ai-je dis qu'il fallait écrire ref = (None, None) ?

                ai-je pas dis d'ajouter quelquechose dans ta ligne 9 ?

                -
                Edité par fred1599 16 juin 2021 à 11:51:43

                • Partager sur Facebook
                • Partager sur Twitter

                Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                  16 juin 2021 à 12:04:14

                   elif attr == 'sources':                
                                  ref = None  # (source, reference)
                                  for child in e.iterdescendants():
                                      if child.tag == 'SRC_MOT':
                                          # UNIQUE_KEY
                                          ref = (child.text, ref[1])
                                      elif child.tag == 'S_REF' and ref:
                                          refs = child.text.split(';')
                                          for part in refs:
                                              # remove surrounding spaces (trim)
                                              r = part.strip()
                                              # merge multiple spaces into one
                                              r = ' '.join(r.split())
                                              self.add_source_reference((ref[0], r))
                              setattr(self, attr, value)

                  J'ai initialisé la variable ref et ajouté une condition 'and ref'
                  >> ai-je pas dis d'ajouter quelquechose dans ta ligne 9 ?

                  Je ne vois pas ce que je dois ajouter dans la ligne 9 ...?
                  Dois-je initialiser la variable au début du script ?

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Nobody is perfect I'm Nobody...

                    16 juin 2021 à 13:01:48

                    Faut peut-être un peu que tu comprennes ce que tu fais, la ligne 9 était la ligne représentative de ta ligne 38 dans ton code original.

                    Donc tu n'as plus rien à faire si ce n'est montré l'ensemble du code avec les modifications, et indiquer les autres erreurs, à savoir que cette modification te permet d'éviter l'erreur "local variable ...".

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                      16 juin 2021 à 13:20:12

                      Alors, l'erreur persiste :

                      script export\en cours\note.py", line 41, in start
                          ref = (child.text, ref[1])
                      TypeError: 'NoneType' object is not subscriptable
                      


                      J'ai l'impression que c'est le contenue de 'ref[...]' qui pose problème / toujours vide ?

                      SOURCES_REFS = []
                      SOURCES_DUPS = [ 0 ]
                      
                      class Note(object):
                      
                          OLDS = {
                              'UNIQUE_KEY'    : 'key',
                              'CREATE_DATE'   : 'create_date',
                              'NOM'           : 'nom_note',
                              'AUTEUR'        : 'auteur',
                              'SRC'           : 'sources',
                          }
                      
                          FIELDS = list(OLDS.values())
                          TAG = 'NOTE'
                      
                      
                      
                      
                          def  __init__(self, separator=';'):
                              self.separator = separator
                      
                          def start(self, e):
                              if e.tag in self.OLDS.keys():
                                  attr = self.OLDS[e.tag]
                                  value = e.text.strip() if e.text else e.text
                                  if ( attr == 'create_date' or attr == 'modify_date' ):
                                      value = format_date(e.get('display'))
                                  elif attr == 'nom_note' or\
                                      attr == 'auteur':
                                      value = '|'.join(value.split('_RS_'))
                                  #loop arround sources whatever a number...
                                  elif attr == 'sources':
                                      # this SRC element will become Reference record
                                      value = None  # we shouldn't need this, but just in case
                                      #ref = {'source': None, 'reference': None }
                                      ref = None  # (source, reference)
                                      for child in e.iterdescendants():
                                          if child.tag == 'SRC_MOT':
                                              # UNIQUE_KEY
                                              ref = (child.text, ref[1])
                                          elif child.tag == 'S_REF' and ref:
                                              refs = child.text.split(';')
                                              for part in refs:
                                                  # remove surrounding spaces (trim)
                                                  r = part.strip()
                                                  # merge multiple spaces into one
                                                  r = ' '.join(r.split())
                                                  self.add_source_reference((ref[0], r))
                                  setattr(self, attr, value)
                              return None
                      
                      
                          def end(self, e):
                              if e.tag == self.TAG:
                                  values = []
                                  for attr in self.FIELDS:
                                      value = getattr(self, attr, '') or ''
                                      values.append(value)
                                  csv = self.separator.join('"{0}"'.format(w) for w in values)
                                  self.reset()
                                  return csv
                              return None
                      
                          def reset(self):
                              for attr in self.FIELDS:
                                  if hasattr(self, attr):
                                      delattr(self, attr)
                      
                          def add_source_reference(self, ref):
                              try:
                                  index = SOURCES_REFS.index(ref)
                                  SOURCES_DUPS[0] += 1
                              except ValueError:  # first reference
                                  index = len(SOURCES_REFS)
                                  SOURCES_REFS.append(ref)
                              try:
                                  if index not in self.sources:
                                      self.sources.append(index)
                              except AttributeError:
                                  setattr(self, 'sources', [index, ])
                      
                      
                      def format_date(value):
                          parts = value.split('/')
                          dd = parts[0].strip()
                          mm = parts[1].strip()
                          yyyy = parts[2].strip()[:4]
                          return '%s/%s/%s' % (yyyy, mm, dd)
                      



                      -
                      Edité par Linus_11 16 juin 2021 à 15:23:19

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Nobody is perfect I'm Nobody...

                        16 juin 2021 à 13:55:35

                        Euh oui j'avais même pas remarqué cette erreur de logique,

                        Il faut définir ce qu'est ref et sa valeur avant ces conditions, et elles ne vaudront sans doute pas None

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                        La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                          16 juin 2021 à 14:22:19

                          D'après ma logique le tuple 'ref' devait être initialisée, puisque elle va accueillir le contenu des tags 'MOT_SRC' et 'S_REF' à chaque fois que la condition est vraie et qu'il y a du contenu dans les balises...

                          -
                          Edité par Linus_11 16 juin 2021 à 14:22:45

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Nobody is perfect I'm Nobody...

                            16 juin 2021 à 14:46:21

                            a priori il y a des modules qui parsent le xml en dictionnaire, et un dictionnaire en csv
                            • Partager sur Facebook
                            • Partager sur Twitter
                              16 juin 2021 à 14:48:24

                              umfred, mon script fonctionne tr-s bien quand les champs sont uniques dans un noeud, ici la particularité est qu'on va chercher plusieurs tags identiques dans le même noeud...
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Nobody is perfect I'm Nobody...

                                16 juin 2021 à 15:10:05

                                alors pourquoi tu appelles ref[1] si tu l'initialises au même endroit, sachant qu'il n'est pas encore initialisé ?
                                • Partager sur Facebook
                                • Partager sur Twitter

                                Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                  16 juin 2021 à 16:53:03

                                  pourquoi ref doit être un tuple ? puisque tu donnes toujours le même 2ème élément et que tu ne récupères que le 1er ensuite
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    16 juin 2021 à 17:13:59

                                    umfred a écrit:

                                    pourquoi ref doit être un tuple ? puisque tu donnes toujours le même 2ème élément et que tu ne récupères que le 1er ensuite


                                    Non parce-que regarde plus bas
                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                      16 juin 2021 à 17:31:41

                                      Je ne vois pas où ref[1] est utilisé dans le code sauf sur la ligne d'affectation de ref (ligne 41 du dernier code)

                                      ref est utilisé ligne 37, 41, 49 (et le test ligne 42)

                                      après, il y a une variable ref qui est le paramètre de la fonction add_source_reference(), et qui n'a donc rien à voir avec celle de start()

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        16 juin 2021 à 17:37:41

                                        umfred a écrit:

                                        Je ne vois pas où ref[1] est utilisé dans le code sauf sur la ligne d'affectation de ref (ligne 41 du dernier code)

                                        Ce n'est plus un problème python, mais de concept... À lui de revoir la manière dont il doit résoudre ce problème

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
                                        La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                                          16 juin 2021 à 19:18:21

                                                          ref = None
                                                          for child in e.iterdescendants():
                                                              if child.tag == 'SRC_MOT':
                                                                  # UNIQUE_KEY
                                                                  ref = child.text
                                                              elif child.tag == 'S_REF' and ref:
                                                                  refs = child.text.split(';')
                                                                  for part in refs:
                                                                      # remove surrounding spaces (trim)
                                                                      r = part.strip()
                                                                      # merge multiple spaces into one
                                                                      r = ' '.join(r.split())
                                                                      self.add_source_reference((ref, r))
                                                              ref=None # à rajouter ici, je pense
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            17 juin 2021 à 16:34:08

                                            Je n'ai effectivement plus d'erreurs, en revanche, dans la colonne sources de mon csv reste vide, aucune data n'est générée...

                                            Je me demande c'est c'est pas mieux avec cette logique pour générer les ressources (SRC_MOT et S_REF)

                                            la data est générée dans le csv, j'ai alors une seule la première ressource générée si la ligne et au même niveau que la boucle

                                            value = my_dict

                                            si la ligne est indenté à l'intérieur on génère la dernière

                                            def start(self, e):
                                                    if e.tag in self.OLDS.keys():
                                                        attr = self.OLDS[e.tag]
                                                        value = e.text.strip() if e.text else e.text
                                                        if ( attr == 'create_date' or attr == 'modify_date' ):
                                                            value = format_date(e.get('display'))
                                                        elif attr == 'nom_note' or\
                                                            attr == 'auteur':
                                                            value = '|'.join(value.split('_RS_'))
                                                        #loop arround sources whatever a number...
                                                        elif attr == 'sources':
                                                            value = None  
                                                            #ref = {'source': None, 'reference': None }
                                                            ref = None
                                                            for child in e.iterdescendants():
                                                                if child.tag == 'SRC_MOT':
                                                                    # UNIQUE_KEY
                                                                    my_dict["Sources_mots"] = child.text
                                                                    
                                                                elif child.tag == 'S_REF':
                                            
                                                                    my_dict["references"] = child.text
                                                                value = my_dict
                                                        setattr(self, attr, value)
                                                    return None



                                            -
                                            Edité par Linus_11 17 juin 2021 à 16:35:13

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Nobody is perfect I'm Nobody...

                                            Boucler sur des balises xml et exporter dans csv

                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                            • Editeur
                                            • Markdown