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

Modules Perl Discussion :

Fusion de fichiers XML - utilisation des handlers (XML::Twig) ?


Sujet :

Modules Perl

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut Fusion de fichiers XML - utilisation des handlers (XML::Twig) ?
    (Edit : Je me suis trompé, ce sujet serait mieux dans /Modules plutôt qu'ici. Si quelqu'un pouvait déplacer ce sujet... Merci d'avance !)

    Bonjour,

    récemment j'ai créé un topic qui traitait de la transformation des balises XML, et j'ai été bien aidé, alors je me permet un autre sujet.

    Je vais essayer d'être clair immédiatement cette fois-ci


    Sujet :
    Fusionner des fichiers XML possédant la même structure
    (racine : volume
    fils : entry (+ sous éléments))

    Problématique :
    Les fichiers xml sont ici très gros (entre 10 et 100 mo, entre 15 000 et 100 000 éléments <entry>).
    Il s'agit donc d'utiliser les handlers de XML::Twig (ou de proposer un autre module plus efficace dans ce cas-ci).
    On pourrait par exemple avancer entrée par entrée comme suit :

    1) si entry-fichier1 = entry-fichier2
    on insère certains fils de entry-fichier2 dans entry-fichier1

    2) si entry-fichier1 est inférieur (lexicographiquement) à entry-fichier2
    on passe à l'entry suivant du fichier1, on ne change pas entry-fichier2 (et on ne fait rien d'autre).

    3) si entry-fichier1 est supérieur (lexicographiquement) à entry-fichier1 (ce qui arrivera rarement), on ajoute entry-fichier2 en entier avant entry-fichier1, et on passe à l'entry suivant pour les deux fichiers.

    Sujet proche sur le forum :
    Une fusion de fichiers XML mais "à la Dom" (on charge tout en mémoire). Ici on voudrait une fusion "à la Sax" (avec donc les handlers).
    J'ai une version sans handler (issu du sujet en référence au-dessus), mais qui ne fonctionne pas (ou alors il faudrait que je laisse tourner ma machine toute une nuit...je n'ai pas essayé).


    Je cherche juste à avoir des pistes, pas forcément un code (ou alors juste un bout ), parce que ça m'a l'air costaud à faire quand même.

    Le plus difficile pour moi est le point 2) et 3), plus particulièrement d'avancer entrée par entrée dans deux fichiers à la fois.

    J'espère avoir été clair, comme je suis dans le flou, il se peut que mes explications s'en ressentent.

    (Pour indication :
    La transformation que j'ai adaptée du code de Djibrill, en DOM, prend entre 40min et 3heures pour mes sources. en SAX, avec un handler qui porte sur entry, je ne dépasse pas 2minutes.
    D'où mon envie de faire pareil ici !)

    Si vous avez vu des sujets similaires, un bouquin qui en parle, ou même que vous avez bossé sur quelque chose de proche, n'hésitez pas ! Même une idée tout simple peut m'aider.
    Sur le site officiel de Xml::Twig ou sur CPAN je n'ai trouvé aucune indication pour une telle application.

    Si jamais ce sujet me permet de réaliser quelque chose qui fonctionne, je mettrai le code, je pense que ça peut servir. Je commence de mon côté à tester comment faire.

  2. #2
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    As-tu regardé du coté du module XML::Merge ?
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Oui, c'est un module intéressant, mais soit j'ai loupé mon test, soit il est également très long (au bout de 4h j'ai arrêté l'exécution).

    Je vais quand même tester à nouveau, on ne sait jamais. Parce qu'il n'y a pas de grosses difficultés dans les éléments à copier, enfin je ne pense pas.

    Je vais lancer quelques tests sur des fichiers plus petits de même structure puis sur les plus gros, et je vous donne la réponse (qui sera justifiée cette fois-ci).

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Les tests sont finis !!

    En effet XML::Merge fonctionne très bien pour des fichiers pas trop gros, dès que je suis passé sur les gros fichiers :

    Out of memory !!

    Par contre, peut être que tu confirmeras Philou, mais ce serait une bonne solution d'utiliser Xml::Twig et Xml::Merge non ?

    Le problème des handlers persiste, mais peut être que j'avancerai mieux en utilisant les deux. Je vais tâtonner.

    Je met le petit bout de code relatif à Xml::Merge :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    use Xml::Merge;
     
    my $merge_obj = XML::Merge->new(
    'filename' => $FichierOne,
    );
    $merge_obj->merge('filename' => $FichierTwo);
    $merge_obj->write($FichierResultat);
    P.S. : il est incomplet, n'oubliez pas de définir vos variables !

  5. #5
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Effectivement, XML::Merge intègre un parser DOM-like, et non pas SAX-like. De fait, il charge tout l'arbre des nœuds pour chaque fichier XML.

    Il te reste donc l'implémentation que tu as proposé à l'aide de XML::Twig. Mais je ne maitrise pas ce module.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  6. #6
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Citation Envoyé par japanatome Voir le message
    (Pour indication :
    La transformation que j'ai adaptée du code de Djibrill, en DOM, prend entre 40min et 3heures pour mes sources. en SAX, avec un handler qui porte sur entry, je ne dépasse pas 2minutes.
    D'où mon envie de faire pareil ici !)
    Quand tu dis en sax, ça veut dire en utlisant XML::Twig avec les twig_handler, c'est bien ça ? Car le code que je t'ai filé fais effectivement du DOM mais si tu l'as adapté, c'est sûr qu'il sera plus rapide. De 3h à 2min, ça change tout . D'ailleurs, pourrais tu nous le montrer ?

    Pour ta nouvelle problématique, rien ne vaut plus qu'un exemple concret. Montre nous 2 petits fichiers XML à fusionner et le fichier résultat XML que tu souhaiterais obtenir. C'est le moyen le plus simple pour que tout le monde se fasse une idée précise de ton souci et se plonge dans le code pour t'aider.

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Euh oui Djibril, je n'emploie pas forcément un vocabulaire strict (je fais du "Perl intuitif" ), mais ta méthode chargeait tout en mémoire (pour moi c'est du DOM) et quand on utilise les handler de twig, on passe en SAX. Quand j'ai vu que pour une des sources (96 000 éléments <entry>), prenait près de 3heures, je suis passé par un handler pour purger la mémoire.

    J'indiquerai ce nouveau code sans problème, dans le sujet précédent sur la transformation, que je met en lien ici pour ceux qui sont intéressés et qui ne l'ont pas vu :

    Utilisation des tables de hachage, transformation XML avec Twig

    Et pour ce sujet-ci je vais vous préparer les p'tits codes.
    Si j'ai un début de quelque chose, je le mettrai aussi.

    Je ferai tout ça d'ici ce soir.

    Merci d'avance pour vos réponses !

  8. #8
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Citation Envoyé par japanatome Voir le message
    Euh oui Djibril, je n'emploie pas forcément un vocabulaire strict (je fais du "Perl intuitif" ), mais ta méthode chargeait tout en mémoire (pour moi c'est du DOM) et quand on utilise les handler de twig, on passe en SAX. Quand j'ai vu que pour une des sources (96 000 éléments <entry>), prenait près de 3heures, je suis passé par un handler pour purger la mémoire.

    J'indiquerai ce nouveau code sans problème, dans le sujet précédent sur la transformation, que je met en lien ici pour ceux qui sont intéressés et qui ne l'ont pas vu :

    Utilisation des tables de hachage, transformation XML avec Twig

    Et pour ce sujet-ci je vais vous préparer les p'tits codes.
    Si j'ai un début de quelque chose, je le mettrai aussi.

    Je ferai tout ça d'ici ce soir.

    Merci d'avance pour vos réponses !
    C'était juste pour confirmer qu'on parle bien de la même chose. Effectivement la méthode handler de twig permet de ne mettre en mémoire que des portions de XML. J'en parle d'ailleurs dans cette article.

    Nous attendons donc tes fichiers et codes.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Ne t'inquiètes pas Djibril, tes articles, ou indications, ou même critiques de livres, on été lus

    Mais ça veut pas dire que je les utilise correctement après. Malheureusement, c'est en forgeant qu'on devient forgeron, et apparemment je n'ai pas encore assez forgé .

    Mais j'en apprend tous les jours. Dernièrement c'est la gestion des arguments par Getopt::Long. Après il y a eu aussi la barre de progression (j'aime bien la partie code source).
    J'ai eu une période Interface TK aussi (mais là à part faire du copier/coller.... mais j'y reviendrai !)

    Enfin bref, mon truc du moment, c'est le Xml, et après avoir transformé, j'aimerais fusionner.

    Voici donc les codes :

    Fichier1.xml :

    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
    <?xml version="1.0" encoding="UTF-8"?>
     
    <volume name="Morphalou" source-langage="fra" creation-date="Tue Jun  8 14:43:16 2010">
       <entry id="a">
          <head>
             <headword>a</headword>
             <pronunciation></pronunciation>
             <pos>s.</pos>
          </head>
       </entry>
       <entry id="a b c">
          <head>
             <headword>a b c</headword>
             <pronunciation></pronunciation>
             <pos>s.</pos>
          </head>
       </entry>
       <entry id="a-humain">
          <head>
             <headword>a-humain</headword>
             <pronunciation></pronunciation>
             <pos>adj.</pos>
          </head>
       </entry>
     
       <entry id="abaisser">
          <head>
             <headword>abaisser</headword>
             <pronunciation></pronunciation>
             <pos>v.</pos>
          </head>
       </entry>
    </volume>
    Fichier2.xml :

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    <?xml version="1.0" encoding="UTF-8"?>
    <volume>
      <entry id="a">
        <head>
          <headword>a</headword>
          <pronunciation></pronunciation>
          <pos></pos>
        </head>
        <sense id="s1">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>mẫu tự đầu tiên và nguyên âm đầu tiên trong bảng chữ cái</translation>
          </translations>
          <examples>
            <example>a majuscule (A)</example>
            <example>a minuscule (a)</example>
          </examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>danh từ giống đực ( không đổi)</m:else>
          </else2>
        </sense>
        <sense id="s2">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>nốt nhạc la (thuật ngữ (âm nhạc) thuộc Anglo-Saxon và Đức)</translation>
            <translation>a (sào)</translation>
            <translation>ampe</translation>
            <translation>angström</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>viết tắt và ký hiệu của:</m:else>
          </else2>
        </sense>
        <sense id="s3">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>thành phần lấy từ tiếng Latinh, để chỉ hướng, đích đến, hoặc từ trạng thái này sang trạng thái khác Amener,  alunir,  adoucir</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>tiếp đầu ngữ</m:else>
          </else2>
        </sense>
      </entry>
      <entry id="abaca">
        <head>
          <headword>abaca</headword>
          <pronunciation></pronunciation>
          <pos></pos>
        </head>
        <sense id="s1">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>một loại chuối ở Philipine, vỏ dùng để dệt.</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>danh từ giống đực</m:else>
          </else2>
        </sense>
      </entry>
      <entry id="abacule">
        <head>
          <headword>abacule</headword>
          <pronunciation></pronunciation>
          <pos></pos>
        </head>
        <sense id="s1">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>hình khối nhỏ tạo nên thành phần của một hình khảm.</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>danh từ giống đực</m:else>
          </else2>
        </sense>
      </entry>
    </volume>
    Je donne les objectifs suivants (ils ont un peu changé) :

    1) si entry-fichier1 = entry-fichier2 (je travaille au niveau des id, mais le headword marche aussi)
    => on insère les éléments <sense> de fichier2, on passe aux entry suivants pour les deux fichiers.

    2) si entry-fichier1 est lexicographiquement (selon l'ordre alphabétique) inférieur (avant) entry-fichier2, alors
    => on passe à entry-fichier1 suivant, on n'ajoute rien.

    3) si entry-fichier1 est lexicographiquement supérieur (après) entry-fichier2, alors
    => on passe à entry-fichier2 suivant, on n'ajoute rien.

    Le cas 3) ne se présente pas dans l'exemple, pour ma part je ne le traite pas pour le moment, je me focalise sur les deux premiers cas. J'ajouterai le 3ème ensuite.

    Résultat :

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    <?xml version="1.0" encoding="UTF-8"?>
     
    <volume name="Morphalou" source-langage="fra" creation-date="Tue Jun  8 14:43:16 2010">
       <entry id="a">
          <head>
             <headword>a</headword>
             <pronunciation></pronunciation>
             <pos>s.</pos>
          </head>
          <sense id="s1">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>mẫu tự đầu tiên và nguyên âm đầu tiên trong bảng chữ cái</translation>
          </translations>
          <examples>
            <example>a majuscule (A)</example>
            <example>a minuscule (a)</example>
          </examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>danh từ giống đực ( không đổi)</m:else>
          </else2>
        </sense>
        <sense id="s2">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>nốt nhạc la (thuật ngữ (âm nhạc) thuộc Anglo-Saxon và Đức)</translation>
            <translation>a (sào)</translation>
            <translation>ampe</translation>
            <translation>angström</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>viết tắt và ký hiệu của:</m:else>
          </else2>
        </sense>
        <sense id="s3">
          <definition>
            <label></label>
            <formula></formula>
          </definition>
          <gloss></gloss>
          <translations>
            <translation>thành phần lấy từ tiếng Latinh, để chỉ hướng, đích đến, hoặc từ trạng thái này sang trạng thái khác Amener,  alunir,  adoucir</translation>
          </translations>
          <examples></examples>
          <idioms></idioms>
          <else1></else1>
          <else2>
            <m:else>tiếp đầu ngữ</m:else>
          </else2>
        </sense>
        </entry>
       <entry id="a b c">
          <head>
             <headword>a b c</headword>
             <pronunciation></pronunciation>
             <pos>s.</pos>
          </head>
       </entry>
       <entry id="a-humain">
          <head>
             <headword>a-humain</headword>
             <pronunciation></pronunciation>
             <pos>adj.</pos>
          </head>
       </entry>
     
       <entry id="abaisser">
          <head>
             <headword>abaisser</headword>
             <pronunciation></pronunciation>
             <pos>v.</pos>
          </head>
       </entry>
    </volume>

    J'essaie pour l'instant de faire quelque chose en associant Xml::Twig et Xml::Merge.

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut Proposition personnelle.


    J'ai laissé tombé Xml::Merge pour le moment.

    Je tente cette idée :

    (1) je modifie le caractère de fin de ligne avec $/ (j'indique la balise fermante de l'élément 'entry').

    (2) avec un while tant que j'ai des lignes dans le fichier 1 OU dans le fichier 2,
    je compare les entrées et je procède selon les indications que j'avais données dans mes messages précédents.

    Quand on écrit quelque chose comme ça :

    Seule la première ligne est chargée, ou alors il parcours tout le fichier ? Parce que si il fait tout le fichier, puis il me donne la première ligne, c'est comme si je faisais du DOM, et donc je ne réduit pas l'utilisation de la mémoire...

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    J'ai une question un peu bête, peut être que les experts du forum pourront me répondre.

    Dans ce que je suis en train de faire (désolé de ne pas encore le montrer, mais le code ne donne pas de résultats ), je lis donc ligne par ligne mon fichier source (enfin j'essaie XD).
    Bon ensuite j'essaie d'introduire le parsing de l'entrée que je garde. C'est là que je coince, le parsing est fait, mais je récupère un XML::Twig=HASH qui se transforme en un magnifique 0 (je suppose pour false), juste après que je sorte de ma subroutine.

    Bon ce problème n'est pas ma question. Ce que je me demandais, c'est vu que je récupère mon élément entry correctement avec $line = <IN>, pourquoi ne pas tout faire avec des expressions régulières ?

    Parce que là je commence à vraiment ne plus avoir d'idée.

  12. #12
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par japanatome Voir le message
    Quand on écrit quelque chose comme ça :

    Seule la première ligne est chargée, ou alors il parcours tout le fichier ? Parce que si il fait tout le fichier, puis il me donne la première ligne, c'est comme si je faisais du DOM, et donc je ne réduit pas l'utilisation de la mémoire...
    Seule la ligne "courante" est lue, jusqu'au prochain délimiteur de ligne défini dans $/

    Citation Envoyé par japanatome Voir le message
    Bon ensuite j'essaie d'introduire le parsing de l'entrée que je garde. C'est là que je coince, le parsing est fait, mais je récupère un XML::Twig=HASH qui se transforme en un magnifique 0 (je suppose pour false), juste après que je sorte de ma subroutine.
    Montre le code de ta subroutine (fonction) et comment tu l'appelles.
    Ce que je me demandais, c'est vu que je récupère mon élément entry correctement avec $line = <IN>, pourquoi ne pas tout faire avec des expressions régulières ?
    Je doute que tu puisses récupérer le contenu de tes entry ainsi... ta ligne contiendra plus que le contenu de l'entry... il faudra nettoyer.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Je te réponds Philou sur la récupération de mes entrées.

    Il y a deux manières d'avoir une entrée nickel chrome selon moi, et si jamais c'est incorrect, fais le moi savoir, mon erreur vient peut être de ça.

    1) une entrée par ligne (début : <entry>.... jusque fin </entry>). Quand on ne choisit pas l'indentation dans Twig, c'est quelque chose que l'on peut avoir. Il y a juste la première entrée qui a besoin de nettoyage (puisque devant il y a l'en-tête xml), que je saute tranquillement en enlevant l'en-tête.

    2) en redéfinissant $/ qui a par défaut le marqueur de fin de ligne.
    je pose $/ = </entry>, et hop le tour est joué. Même si mon entrée est sur plusieurs lignes, aucun problème avec cette méthode.

    J'ai essayé les deux, avec plus ou moins de résultat. Plus j'avançais, moins ce que j'obtenais était bon .

    Je commence à baisser les bras. En fait le problème à résoudre, c'est cette méthode du parcours ligne par ligne (avec nettoyage comme le signale Philou, je pars du principe qu'il a raison ).
    Le souci est que je fais un while <IN1> et en même temps un while <IN2>, et ça génère n'importe quoi.

    Ma question est donc : perl ne peut pas suivre la lecture ligne à ligne de deux fichiers simultanément ? Si il en est capable, comment faire ?



    Cette question est une petite mise en bouche pour le lundi matin. Mais dans tous les cas, demain j'indique mon code, qui ne fonctionne pas, mais qui pourra peut être faire avancer ce sujet. J'aimerai vraiment trouver la solution, ça m'éviterait de diviser en plusieurs fichiers xml mes sources, pour les fusionner à la DOM 500 fois.... Un bon SAX à plein régime, y a que ça de vrai.

    En tout cas merci de répondre, c'est sympa, j'y gagne en rigueur. à demain pour mon code.

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    OK... je vais être plus précis dans mes explications : utiliser $/ pour délimiter des éléments XML n'est pas une méthode correcte dans un cas général. Il est possible que le cas particulier où (quasiment) seuls des éléments <entry> sont présent, le nettoyage soit facile. Mais la méthode n'est pas applicable de manière générale.

    Sinon, perl sais parfaitement lire plusieurs fichiers en même temps. J'avais aussi développé un mergeur il y a fort longtemps déjà (dont je n'ai pas les sources ici), qui traitait des fichiers de traces de protocoles de commutation avec des timestamps à synchroniser. J'utilisais un algorithme similaire. Je pense que ton défaut se situe dans ta fonction de merge. J'attends donc que tu la postes pour t'en dire plus.
    As-tu essayé de débugger avec perl -d ?
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Euh Philou, quand je te lis, je me dis que j'ai encore énormément à apprendre en perl.... parce que j'ai jamais débuggé, et j'ai l'impression de faire des programmes "bordel", en oubliant de vérifier des points importants... ça viendra avec le temps !

    Je donne donc le code que j'ai, dernière version . Qui ne marche pas, j'ai l'en-tête (avec Xml::Writer) qui s'inscrit bien dans le fichier de sortie. Par contre la fermeture (encore avec Xml::Writer) n'a pas fonctionné, je trouve ça très bizarre, puisque ça ne dépend pas de la boucle while..... C'est peut être un indice !

    J'ai laissé les commentaires, le choix des options, et le mode "verbeux", qui affiche des messages dans STDERR. ça me permet de voir si ça avance. Pour les subroutines, elles sont à la fin. Je les ai séparées :

    1) d'abord celle sur source1.xml
    2) puis celle sur source2.xml
    3) la fusion
    4) et enfin celles pour l'aide et les informations.


    En commande on peut mettre ça :

    perl Fusion.pl -v -from source1.xml -and source2.xml -to out.xml


    (le -v : active le mode verbeux).

    Les autres options n'ont pas d'intérêts pour le test (la langue, le pretty_print, ...)

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    #!/usr/bin/perl
     
    # =======================================================================================================================================
    ###--- METADIRECTIVES ---###
     
    use strict;
    use warnings;
    use utf8;
    use IO::File; 
    use Getopt::Long; # pour gérer les arguments.
     
    use XML::Twig; # (non inclus dans le core de Perl), pour le parsing de la source.
    use XML::Writer; # (non inclus dans le core de Perl), pour le fichier de sortie.
     
     
    # =======================================================================================================================================
    ###--- PROLOGUE ---###
     
    my $ref_root = 'volume'; # la racine (par exemple : <volume> ou <dictionary>).
    my $ref_entry = 'entry'; # l'élément dans la source qui correspond avec <m:entry> dans MAM.
    my $ref_headword = 'headword';
    my $ref_sense = 'sense'; # idem pour l'élément <sense> dans MAM.
     
    # ------------------------------------------------------------------------
    ##-- Gestion des options --##
     
    my ($date, $FichierOne, $FichierTwo, $FichierResultat, $erreur, $encoding) = ();
    my ($verbeux, $help, $pretty_print, $langue) = ();
    GetOptions( 
      'date|time|t=s'        	    => \$date, # flag de type -date ou --date, ou -time ou --time, ou -t ou --t (=s : string)
      'source|base|in|one|from|i=s' => \$FichierOne, 
      'add|and|two|j=s'        		=> \$FichierTwo,
      'sortie|out|to|o=s'           => \$FichierResultat, 
      'erreur|error|e=s'     	  	=> \$erreur, 
      'encodage|encoding|enc|f=s' 	=> \$encoding, 
      'help|h'                	  	=> \$help, 
      'verbeux|v'             	  	=> \$verbeux, 
      'print|pretty|p=s'       	  	=> \$pretty_print, 
      'langue|lang|l=s'				=> \$langue,
      );
     
    if (!( defined $date ))
    	{
    	$date = localtime;
    	};
    if (!( defined $FichierOne ))
    	{
    	&help ; # si le fichier source n'est pas spécifié, affichage de l'aide.
    	};
    if (!( defined $FichierTwo ))
    	{
    	&help ; # si le fichier source n'est pas spécifié, affichage de l'aide.
    	};
    if (!( defined $FichierResultat ))
    	{
    	$FichierResultat = "toto.xml" ;
    	};
    if (!( defined $erreur ))
    	{
    	$erreur = "|ERROR| : problem opening file :";
    	};
    if (!( defined $encoding ))
    	{
    	$encoding = "UTF-8"; 
    	};
    if (!( defined $pretty_print ))
    	{
    	$pretty_print = "none"; 
    	};
    if (!( defined $langue ))
    	{
    	$langue = "XX"; 
    	};
    if ( defined $help )
    	{
    	&help;
    	};
     
    # ------------------------------------------------------------------------
    # Autres variables :
     
    my $stop_one = 0; # variable pour simuler la fin des entrées.
    my $stop_two = 0;
    my $count_one = 0;
    my $count_two = 0;
     
    # ------------------------------------------------------------------------
    # Input/ Output
     
    open (FILEONE, "<:encoding($encoding)", $FichierOne) or die ("$erreur $!\n");
    open (FILETWO, "<:encoding($encoding)", $FichierTwo) or die ("$erreur $!\n");
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('a'); 
    	};
    # message dans le STDERR (voir subroutine 'info') indiquant le démarrage du programme.
     
    # ------------------------------------------------------------------------
    ##-- Début de l'écriture --##
     
    my $output = new IO::File(">$FichierResultat");
    my $writer = new XML::Writer(
      OUTPUT      => $output,
      DATA_INDENT => 3,         # indentation, 3 espaces
      DATA_MODE   => 1,         # changement ligne.
      ENCODING    => $encoding,
    );
    $writer->xmlDecl($encoding);
     
    $writer->startTag
    	(
      "m:volume",
      'name'              => "NAME",
      'source-language'   => $langue,
      'creation-date'     => $date,
    	);
     
    # =======================================================================================================================================
    ###--- PREPARATION ---###
     
    my $twig_one = XML::Twig->new
    (
    output_encoding => $encoding, # on reste en utf8
    pretty_print    => $pretty_print, # par défaut le style est 'none'
    twig_roots      => {'entry' => 1}, 
    Twig_handlers   => {'entry' => \&twig_base,}, 
    ); 
     
    # ------------------------------------------------------------------------
     
    my $twig_two= XML::Twig->new
    (
    output_encoding => $encoding, 
    pretty_print    => $pretty_print,
    twig_roots      => {'entry' => 1},
    Twig_handlers   => {'entry' => \&twig_ajout,}, 
    ); 
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('b'); 
    	};
     
    # ------------------------------------------------------------------------
     
    my $entry_one = &one_suivant; # obtenir la première entrée de la source 1.
    my $entry_two = &two_suivant; # obtenir la première entrée de la source 2.
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('c'); 
    	};
     
    # =======================================================================================================================================
    ###--- ALGORITHME DE LA FUSION ---###
     
    # Après avoir récupéré la ou les entrées (sub one_suivant et two_suivant), on les compare.
    # On écrit dans le fichier de sortie selon la comparaison.
    while (($entry_one ne "0") || ($entry_two ne "0")) 
    # Le traitement continuera tant qu'il y a des entrées dans l'une ou l'autre source.
    	{
    if ( defined $verbeux )	{print (STDERR "In progress\n");};
    	if ($entry_one ne "0")
    		{
    		my $headword_one = $entry_one -> findnodes ("headword")->text;
    if ( defined $verbeux )	{print (STDERR "$FichierOne : entrée [$headword_one]\n");};
    		if ($entry_two ne "0")
    			{
    			my $headword_two = $entry_two -> findnodes ("headword")->text;
    if ( defined $verbeux )	{print (STDERR "$FichierTwo : entrée [$headword_two]\n");};
    			# On compare les deux headword 'lexicographiquement' :
    			# 1) si l'entrée 1 est inférieure à l'entrée 2 :
    # On écrit l'entrée 1 dans le fichier de sortie.
    # On avance d'une entrée dans le fichier 1
    			if ($headword_one lt $headword_two)
    				{
    				$entry_one->print_to_file ($FichierResultat);
    				$entry_one = 0; # pour avoir l'entrée suivante dans le fichier 1.
    				}
    			# 2) si l'entrée 1 est supérieure à l'entrée 2 :
    # On écrit l'entrée 2 dans le fichier de sortie.
    # On avance d'une entrée dans le fichier 2.
    			elsif ($headword_one gt $headword_two)
    				{
    				$entry_two->print_to_file ($FichierResultat);
    				$entry_two = 0; # pour avoir l'entrée suivante dans le fichier 2.
    				}
    			# 3) le dernier cas : entrée 1 = entrée 2 :
    # On ajoute les éléments de entrée 2 dans entrée 1, qu'on écrit dans le fichier de sortie.
    # On avance d'une entrée dans le fichier 1 et dans le fichier 2.
    			else
    				{
    				&fusion ($entry_one, $entry_two);
    				$entry_one->print_to_file($FichierResultat);
    				$entry_one = 0;
    				$entry_two = 0;
    				}
    			}
    		else # si on a pas d'entrée 2 : ajout terminé, on écrit les entrées 1
    			{
    			$entry_one->print_to_file($FichierResultat);
    			$entry_one = 0;
    			}
    		}
    	elsif ($entry_two) # si pas d'entrée 1 mais entrée 2, on ajoute entrée 2.
    		{
    		$entry_two->print_to_file($FichierResultat);
    		$entry_two = 0;
    		}
    	# le traitement est terminé, pour récupérer la ou les entrées suivantes, on relance les subroutines.
    	$entry_one = &one_suivant; 
    	$entry_two = &two_suivant; 
    	};
     
    # ------------------------------------------------------------------------	
    # Fin de l'écriture :
     
    $writer->endTag("m:volume");
    $output->close();
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('d'); 
    	};
     
    # =======================================================================================================================================
    ###--- SUBROUTINES ---###
     
    sub one_suivant
    {
    my $base_xml_header;
    if ((!$entry_one) && (!$stop_one))
    	{
    	$/ = "</entry>";
    	my $entry = <FILEONE>;
    	if ($entry =~ /<entry>/)
    		{
    		if (my $match = $entry =~ /^.*<entry/sm)
    			{
    			$entry =~ s/^(.*)<entry>/<entry>/sm;
    			}
    			$count_one++;
    			$entry_one = $twig_one->parse($entry);
    			$twig_one->purge;
    		}
    	else 
    		{
    		$stop_one = 1;
    		$entry_one = 0;
    		}
    	}	
    return $entry_one;
    }
     
    sub twig_base 
    {
    my ($temp, $entry_one) = @_ ;
    $twig_one->purge;
    return ($entry_one);
    }
     
    # ------------------------------------------------------------------------
     
    sub two_suivant 
    	{
    	my $add_xml_header;
    	if ((!$entry_two) && (!$stop_two)) 
    		{
    		$/ = "</entry>";
    		my $entry=<FILETWO>;
    		if ($entry =~ /<entry>/) 
    			{
    			if (my $match = $entry =~  /^.*<entry/sm) 
    				{
    				$entry =~ s/^(.*)<entry>/<entry>/sm;
    				}
    			$entry_two = $twig_two->parse($entry);
    			$twig_two->purge;
    			}
    		else 
    			{
    			$stop_two = 1;
    			$entry_two = 0;
    			}
    		}	
    return $entry_two;
    	}
     
    sub twig_ajout
    {
    my ($temp, $entry_two) = @_ ;
    $twig_one->purge;
    return ($entry_two);
    }
    # ------------------------------------------------------------------------
     
    sub fusion
    {
    my $entry_one = shift @_;
    my $entry_two = shift @_;
     
    foreach my $sense_two ($entry_two->findnodes('sense'))
    	{
    	$sense_two->copy;
    	$sense_two->paste('after'=>$entry_one->last_child('sense'));
    	}
    return ($entry_one);
    }
     
    # ------------------------------------------------------------------------
     
    sub info
    {
    my $info = shift @_;
    if ($info =~ 'a')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "\t~~~~ $0 : START ~~~~\n");
    	print (STDERR "================================================================================\n");
    	}
    elsif ($info=~ 'b')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "en-tete du fichier de sortie effective\n");
    	print (STDERR "--------------------------------------------------------------------------------\n");
    	}
    elsif ($info=~ 'c')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "lancement du processus de fusion\n");
    	print (STDERR "--------------------------------------------------------------------------------\n");
    	}
    elsif ($info =~ 'd')
    	{
    	print (STDERR "~~~~ $0 : END ~~~~\n");
    	print (STDERR "================================================================================\n");
    	my $time = times ;
    	my $FichierLog = 'LOG.txt';
    	open(my $FiLo, ">>:encoding($encoding)", $FichierLog) or die ("$erreur $!\n");
    	print {$FiLo}
    	"==================================================\n",
    	"RAPPORT : ~~~~ $0 ~~~~\n",
    	"--------------------------------------------------\n",
    	"Fichier source : $FichierOne\n",
    	"--------------------------------------------------\n",
    	"Fichier final : $FichierResultat\n",
    	"--------------------------------------------------\n",
    	"Date du traitement : ", $date, "\n",
    	"--------------------------------------------------\n",
    	"Lapsed time : ", $time, " s\n",
    	"==================================================\n";
    	}
    }
     
     
    sub help 
    {
    print (STDERR "================================================================================\n");  
    print (STDERR "HELP\n");
    print (STDERR "================================================================================\n");
    print (STDERR "usage : $0 -i <sourcefile.xml> -o <outfile.xml>\n\n") ;
    print (STDERR "options : -h affichage de l'aide\n") ;
    print (STDERR "          -e le message d'erreur (ouverture de fichiers)\n") ;
    print (STDERR "          -f le format d'encodage\n");
    print (STDERR "          -v mode verbeux (STDERR et LOG)\n");
    print (STDERR "          -t pour la gestion de la date (initialement : localtime)\n");
    print (STDERR "================================================================================\n");
    }
     
     
    # =======================================================================================================================================
    1 ;

    Je sens que mon idée n'est pas mauvaise, il me manque un Philou pour me barrer de rouge les erreurs et que ça tourne enfin

  16. #16
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Programme un peu long... réponse un peu temporisée
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  17. #17
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    ah autant pour moi, je n'avais pas compris.

    J'utilise quand même $/, regarde du côté des subroutines, one_suivant et two_suivant. Je n'utilise twig qu'à la fin des sub.

    Mais si vraiment l'utilisation du twig t'embête, je dois avoir garder la version sans, je peux la mettre si tu veux. Par contre elle est moins fiable que celle-ci je pense.

  18. #18
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Je n'ai plus le fichier que tu voulais voir.

    Mais à ce propos j'ai une question, Philou. Si je me lance dans un version sans Xml::Twig, à grand renforts d'expressions régulières (puisque la fusion en elle-même n'est pas si compliquée), tu accepterais de corriger une telle version ?

    évidemment avec un maximum de travail pour te proposer quelque chose de cohérent, mais je suis pas certain d'y parvenir, les expressions régulières ne me donnent jamais ce que je veux

  19. #19
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Il y a un premier bug dans l'utilisation de la regexp /^.*<entry>/ (les éléments contenant des paramètres id, le tag n'est pas fermé immédiatement après entry).

    Ensuite, tu as défini beaucoup (trop) de variables globales, et des fonctions spécifiques pour chaque fichier, ce qui n'est pas très judicieux. J'ai donc commencé à remanier un peu ton script, en :
    - factorisant suivant one_suivant() et two_suivant() en next_entry (désolé, je suis passé à l'anglais en même temps, j'ai pas fait attention).
    - supprimé les variables $stop qui me semblent redondantes
    - remplacé la condition de lecture dans next_entry par une condition de lecture dans le fichier, et externalisé vers l'appelant la condition d'avancement dans le fichier : c'est en effet plus logique de conserver cette condition dans l'algorithme de fusion que de le descendre dans la fonction de lecture et d'extraction
    - remplacé la condition d'avancement dans un fichier : à la place de l'usage de la valeur logique 0 (qui signifiait à la fois fin de fichier pour la fonction one/two_suivant, et pas d'avancement dans l'algorithme de fusion) j'ai utilisé la valeur "undef" lorsqu'il faut avancer dans le fichier (il faut définir à nouveau la valeur courante).

    Le script devrait sans doute être encore simplifié, mais cette version devrait mieux répondre à ta problématique. Cependant, une fois la correction du bug identifié au début, le script "plante" lors de la recherche du noeud headword (en fait, la recherche échoue, donc l'appel à la méthode text échoue sur un objet non défini).
    Ne sachant pas utilisé XML::Twig, je ne sais trop quoi conclure. Pourtant, la chaine fournie au parser semble correcte.

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    #!/usr/bin/perl
     
    # =======================================================================================================================================
    ###--- METADIRECTIVES ---###
     
    use strict;
    use warnings;
    use utf8;
    use IO::File; 
    use Getopt::Long; # pour gérer les arguments.
     
    use XML::Twig; # (non inclus dans le core de Perl), pour le parsing de la source.
    use XML::Writer; # (non inclus dans le core de Perl), pour le fichier de sortie.
     
     
    # =======================================================================================================================================
    ###--- PROLOGUE ---###
     
    my $ref_root = 'volume'; # la racine (par exemple : <volume> ou <dictionary>).
    my $ref_entry = 'entry'; # l'élément dans la source qui correspond avec <m:entry> dans MAM.
    my $ref_headword = 'headword';
    my $ref_sense = 'sense'; # idem pour l'élément <sense> dans MAM.
     
    # ------------------------------------------------------------------------
    ##-- Gestion des options --##
     
    my ($date, $FichierOne, $FichierTwo, $FichierResultat, $erreur, $encoding) = ();
    my ($verbeux, $help, $pretty_print, $langue) = ();
    GetOptions( 
      'date|time|t=s'        	    => \$date, # flag de type -date ou --date, ou -time ou --time, ou -t ou --t (=s : string)
      'source|base|in|one|from|i=s' => \$FichierOne, 
      'add|and|two|j=s'        		=> \$FichierTwo,
      'sortie|out|to|o=s'           => \$FichierResultat, 
      'erreur|error|e=s'     	  	=> \$erreur, 
      'encodage|encoding|enc|f=s' 	=> \$encoding, 
      'help|h'                	  	=> \$help, 
      'verbeux|v'             	  	=> \$verbeux, 
      'print|pretty|p=s'       	  	=> \$pretty_print, 
      'langue|lang|l=s'				=> \$langue,
      );
     
    if (!( defined $date ))
    	{
    	$date = localtime;
    	};
    if (!( defined $FichierOne ))
    	{
    	&help ; # si le fichier source n'est pas spécifié, affichage de l'aide.
    	};
    if (!( defined $FichierTwo ))
    	{
    	&help ; # si le fichier source n'est pas spécifié, affichage de l'aide.
    	};
    if (!( defined $FichierResultat ))
    	{
    	$FichierResultat = "toto.xml" ;
    	};
    if (!( defined $erreur ))
    	{
    	$erreur = "|ERROR| : problem opening file :";
    	};
    if (!( defined $encoding ))
    	{
    	$encoding = "UTF-8"; 
    	};
    if (!( defined $pretty_print ))
    	{
    	$pretty_print = "none"; 
    	};
    if (!( defined $langue ))
    	{
    	$langue = "XX"; 
    	};
    if ( defined $help )
    	{
    	&help;
    	};
     
    # ------------------------------------------------------------------------
    # Autres variables :
     
    my $count_one = 0;
    my $count_two = 0;
     
    # ------------------------------------------------------------------------
    # Input/ Output
     
    open (FILEONE, "<:encoding($encoding)", $FichierOne) or die ("$erreur $!\n");
    open (FILETWO, "<:encoding($encoding)", $FichierTwo) or die ("$erreur $!\n");
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('a'); 
    	};
    # message dans le STDERR (voir subroutine 'info') indiquant le démarrage du programme.
     
    # ------------------------------------------------------------------------
    ##-- Début de l'écriture --##
     
    my $output = new IO::File(">$FichierResultat");
    my $writer = new XML::Writer(
      OUTPUT      => $output,
      DATA_INDENT => 3,         # indentation, 3 espaces
      DATA_MODE   => 1,         # changement ligne.
      ENCODING    => $encoding,
    );
    $writer->xmlDecl($encoding);
     
    $writer->startTag
    	(
      "m:volume",
      'name'              => "NAME",
      'source-language'   => $langue,
      'creation-date'     => $date,
    	);
     
    # =======================================================================================================================================
    ###--- PREPARATION ---###
     
    my $twig_one = XML::Twig
    ->new
    (
    output_encoding => $encoding, # on reste en utf8
    pretty_print    => $pretty_print, # par défaut le style est 'none'
    twig_roots      => {'entry' => 1}, 
    Twig_handlers   => {'entry' => \&twig_base,}, 
    ); 
     
    # ------------------------------------------------------------------------
     
    my $twig_two= XML::Twig->new
    (
    output_encoding => $encoding, 
    pretty_print    => $pretty_print,
    twig_roots      => {'entry' => 1},
    Twig_handlers   => {'entry' => \&twig_ajout,}, 
    ); 
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('b'); 
    	};
     
    # ------------------------------------------------------------------------
     
    my $entry_one = next_entry($twig_one, *FILEONE); # obtenir la première entrée de la source 1.
    my $entry_two = next_entry($twig_two, *FILETWO); # obtenir la première entrée de la source 2.
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
    	{
    	&info('c'); 
    	};
     
    # =======================================================================================================================================
    ###--- ALGORITHME DE LA FUSION ---###
     
    # Après avoir récupéré la ou les entrées (sub next_entry), on les compare.
    # On écrit dans le fichier de sortie selon la comparaison.
    while (($entry_one ne "0") || ($entry_two ne "0"))
      # Le traitement continuera tant qu'il y a des entrées dans l'une ou l'autre source.
      {
        if ( defined $verbeux )	{print (STDERR "In progress\n");};
        if ($entry_one ne "0")
          {
            my $headword_one = $entry_one -> findnodes ("headword")->text;
            if ( defined $verbeux )	{print (STDERR "$FichierOne : entrée [$headword_one]\n");};
            if ($entry_two ne "0")
              {
                my $headword_two = $entry_two -> findnodes ("headword")->text;
                if ( defined $verbeux )	{print (STDERR "$FichierTwo : entrée [$headword_two]\n");};
                # On compare les deux headword 'lexicographiquement' :
                # 1) si l'entrée 1 est inférieure à l'entrée 2 :
                # On écrit l'entrée 1 dans le fichier de sortie.
                # On avance d'une entrée dans le fichier 1
                if ($headword_one le $headword_two)
                  {
                    $entry_one->print_to_file($FichierResultat);
                    undef $entry_one; # pour avoir l'entrée suivante dans le fichier 1.
                  }
                # 2) si l'entrée 1 est supérieure à l'entrée 2 :
                # On écrit l'entrée 2 dans le fichier de sortie.
                # On avance d'une entrée dans le fichier 2.
                elsif ($headword_one gt $headword_two)
                  {
                    $entry_two->print_to_file ($FichierResultat);
                    undef $entry_two; # pour avoir l'entrée suivante dans le fichier 2.
                  }
                # 3) le dernier cas : entrée 1 = entrée 2 :
                # On ajoute les éléments de entrée 2 dans entrée 1, qu'on écrit dans le fichier de sortie.
                # On avance d'une entrée dans le fichier 1 et dans le fichier 2.
                else
                  {
                    fusion ($entry_one, $entry_two);
                    $entry_one->print_to_file($FichierResultat);
                    undef $entry_one;
                    undef $entry_two;
                  }
              }
            else # si on a pas d'entrée 2 : ajout terminé, on écrit les entrées 1
              {
                $entry_one->print_to_file($FichierResultat);
                undef $entry_one;
              }
          }
        elsif ($entry_two) # si pas d'entrée 1 mais entrée 2, on ajoute entrée 2.
          {
            $entry_two->print_to_file($FichierResultat);
            undef $entry_two;
          }
        # le traitement est terminé, pour récupérer la ou les entrées suivantes, on relance les subroutines.
        $entry_one = next_entry($twig_one, *FILEONE) if !defined $entry_one;
        $entry_two = next_entry($twig_two, *FILETWO) if !defined $entry_two;
      };
     
    # ------------------------------------------------------------------------
    # Fin de l'écriture :
     
    $writer->endTag("m:volume");
    $output->close();
     
    # ------------------------------------------------------------------------
     
    if ( defined $verbeux )
      {
        &info('d');
      };
     
    # =======================================================================================================================================
    ###--- SUBROUTINES ---###
    sub next_entry {
      my ($twig, $file) = @_;
     
      my $entry;
      $/ = "</entry>";
      my $xml = <$file>;
      if ($xml && $xml =~ /<entry/) {
        if (my $match = $xml =~ /^.*<entry/sm) {
          $xml =~ s/^(.*)<entry/<entry/sm;
        }
        $count_one++; # Inutile et inutilisé (et effet de bord)
        $entry = $twig->parse($xml);
        $twig->purge;
      }
      else {
        $entry = 0;
      }
     
      return $entry;
    }
     
    sub twig_base 
    {
    my ($temp, $entry_one) = @_ ;
    $twig_one->purge;
    return ($entry_one);
    }
     
    # ------------------------------------------------------------------------
     
     
    sub twig_ajout
    {
    my ($temp, $entry_two) = @_ ;
    $twig_one->purge;
    return ($entry_two);
    }
    # ------------------------------------------------------------------------
     
    sub fusion
    {
    my $entry_one = shift @_;
    my $entry_two = shift @_;
     
    foreach my $sense_two ($entry_two->findnodes('sense'))
    	{
    	$sense_two->copy;
    	$sense_two->paste('after'=>$entry_one->last_child('sense'));
    	}
    return ($entry_one);
    }
     
    # ------------------------------------------------------------------------
     
    sub info
    {
    my $info = shift @_;
    if ($info =~ 'a')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "\t~~~~ $0 : START ~~~~\n");
    	print (STDERR "================================================================================\n");
    	}
    elsif ($info=~ 'b')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "en-tete du fichier de sortie effective\n");
    	print (STDERR "--------------------------------------------------------------------------------\n");
    	}
    elsif ($info=~ 'c')
    	{
    	print (STDERR "================================================================================\n");
    	print (STDERR "lancement du processus de fusion\n");
    	print (STDERR "--------------------------------------------------------------------------------\n");
    	}
    elsif ($info =~ 'd')
    	{
    	print (STDERR "~~~~ $0 : END ~~~~\n");
    	print (STDERR "================================================================================\n");
    	my $time = times ;
    	my $FichierLog = 'LOG.txt';
    	open(my $FiLo, ">>:encoding($encoding)", $FichierLog) or die ("$erreur $!\n");
    	print {$FiLo}
    	"==================================================\n",
    	"RAPPORT : ~~~~ $0 ~~~~\n",
    	"--------------------------------------------------\n",
    	"Fichier source : $FichierOne\n",
    	"--------------------------------------------------\n",
    	"Fichier final : $FichierResultat\n",
    	"--------------------------------------------------\n",
    	"Date du traitement : ", $date, "\n",
    	"--------------------------------------------------\n",
    	"Lapsed time : ", $time, " s\n",
    	"==================================================\n";
    	}
    }
     
     
    sub help 
    {
    print (STDERR "================================================================================\n");  
    print (STDERR "HELP\n");
    print (STDERR "================================================================================\n");
    print (STDERR "usage : $0 -i <sourcefile.xml> -o <outfile.xml>\n\n") ;
    print (STDERR "options : -h affichage de l'aide\n") ;
    print (STDERR "          -e le message d'erreur (ouverture de fichiers)\n") ;
    print (STDERR "          -f le format d'encodage\n");
    print (STDERR "          -v mode verbeux (STDERR et LOG)\n");
    print (STDERR "          -t pour la gestion de la date (initialement : localtime)\n");
    print (STDERR "================================================================================\n");
    }
     
     
    # =======================================================================================================================================
    1 ;
    Bien entendu, tu peux poser toutes les questions que tu souhaites sur les modifications que j'ai opérées.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  20. #20
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 5
    Points
    5
    Par défaut
    Merci beaucoup Philou !!

    Même si ça ne résout pas tout, c'est sympa de passer du temps dessus. J'ai compris tes explications (c'est plutôt bien non ?), je vais regarder ça.

    Le passage en anglais ne me gène pas, j'ai même tendance à "forcer" le français juste pour pas mettre de l'anglais .

    Je vais voir pourquoi ça plante avec twig, j'ai peut être des erreurs à ce niveau-là aussi.

    Si je trouve j'indique le code. Sinon peut être Djibril par exemple aura un avis.

    En tout cas tu n'as pas dit que mon code était bidon, donc j'avais quand même une bonne piste... enfin je crois... un p'tit peu....

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Utiliser des données XML avec Excel ?
    Par sky1989 dans le forum Excel
    Réponses: 3
    Dernier message: 29/03/2012, 21h48
  2. doc XML utiliser des conditions
    Par clouddd dans le forum C#
    Réponses: 5
    Dernier message: 07/06/2011, 14h00
  3. Réponses: 1
    Dernier message: 29/04/2009, 10h43
  4. [xslt][xpath]Utilisation des attributs XML
    Par Little_flower dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 15/05/2007, 12h42
  5. Réponses: 1
    Dernier message: 01/07/2006, 11h18

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