Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 20/11/2010, à 01:41

Malizor

[Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Salut à tous,

Je suis en train de rédiger un script qui doit, entre autre, signaler à l'utilisateur les balises non fermées d'un fichier.
Il s'agit d'arbres très simples avec généralement un unique nœud comme « <xml>Plop !</xml> » perdu au milieu d'un texte (il n'y a pas de balises auto-fermantes et les noms de balises ne sont pas forcément connus à l'avance).

Jusqu'à présent, je lisais le fichier ligne par ligne en utilisant un code de ce genre :

if [ -n "`echo $ligne | grep "<.*>.*<[^/]*>"`" ]; then
    echo "Ligne $i : balises mal fermées ?" >> fichier.log
fi

Ce code marche relativement bien dans la plupart des cas, mais il pose problème quand des balises sont imbriquées et/ou lorsqu'il y a plusieurs balises sur une même ligne.

Malgré plusieurs expérimentations, je n'ai pas réussi à trouver mon bonheur.

Quelqu'un aurait-il une idée pour résoudre ce problème de façon pas trop sale ?

Dernière modification par Malaria (Le 20/11/2010, à 22:48)


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#2 Le 20/11/2010, à 02:57

chopinhauer

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Les expressions rationnelles marchent mal avec XML (qui n'est pas un Langage rationnel). Utilisez plutôt xmllint.


Pensez à donner un bon titre à vos sujets : cela permettra d'aider d'autres utilisateurs dans votre même situation. Ce n'est pas qu'en donnant des solutions qu'on aide, mais aussi en posant des bonnes questions et… facilement trouvables.

Hors ligne

#3 Le 20/11/2010, à 12:00

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Intéressant, merci.

Mais le truc c'est qu'à priori xmllint ne marche qu'avec des arbres XML, or moi j'ai des balises perdues au milieu d'un texte.
Par exemple, j'ai des lignes de ce genre :

"case <gui>Plein écran</gui> du menu <guiseq><gui>Affichage</gui></guiseq>."

C'est dans ce contexte que j'aimerais vérifier que toutes les balises sont fermées.

Au pire, ce n'est pas dramatique si mon script rapporte quelques faux positifs (sans oublier de vrais positifs par contre).
Le problème du code dans mon premier post c'est qu'il en rapporte trop pour être utile. wink

Dernière modification par Malaria (Le 20/11/2010, à 12:03)


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#4 Le 20/11/2010, à 13:14

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Je pense avoir trouvé une solution : pour obtenir ce que je veux il suffit en fait de comparer le nombre de balises ouvrantes et le nombres de balises fermantes.

Je ne sais pas pas si on peut considérer ça comme propre, mais voilà ce que j'utilise :
(ici je ne suis plus ligne par ligne, j'ai isolé tout un bloc de texte dans le fichier « MON_FICHIER »)

nbBalisesOuvrantes="`sed ':z;N;s/<\([^/][^<]*[^/]\|.\)>/\nBALISEOUVRANTE/g;bz' MON_FICHIER | grep -c BALISEOUVRANTE`"
nbBalisesFermantes="`sed ':z;N;s/<\/[^<]*>/\nBALISEFERMANTE/g;bz' MON_FICHIER | grep -c BALISEFERMANTE`"

if [ $nbBalisesOuvrantes != $nbBalisesFermantes ]; then
    echo "Bloc commençant à la ligne $i : problème de fermeture de balise ?" >> à_verifier.log
fi

Ça à l'air de très bien fonctionner : sur un fichier de 1239 « blocs » je n'ai eu qu'un faux positif (sur une adresse mail de type <plop@machin.fr>)

C'est clair qu'il serait mieux de vérifier également que les noms des balises face à face correspondent, mais je ne vois pas comment faire ça proprement et simplement. Après tout, c'est déjà ça de pouvoir vérifier qu'il y a autant de balises ouvrantes que fermantes.

En ce qui concerne mon objectif initial, mission accomplie.
Je vais attendre encore un peu avant de considérer ce sujet comme étant résolu, au cas où quelqu'un trouverait une solution miracle pour vraiment bien vérifier tout ça.

édit : le calcul du nombre de balises ouvrantes ne tenait pas comptes des balises qui ont un nom de un seul caractère.
édit2 : notez que les commandes sed ne fonctionnent que s'il y a plus d'une ligne dans MON_FICHIER (enlever les « :z;N; » et les « ;bz » s'il n'y a qu'une seule ligne, différenciez les deux cas avec un if)

Dernière modification par Malaria (Le 20/11/2010, à 16:11)


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#5 Le 20/11/2010, à 20:46

chopinhauer

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

sed -n -e 'H' -e '${g;:a;s/<\([[:alpha:]]\+\)\( [^>]*\)\?>[^<]*<\/\1>\|<[^>]\+\/>//g;ta;s/[ \t\n]//g;p}'

Cela contrôle aussi le nom des balises et donne un résultat vide si il aucune erreur n'a pas été détectée.

PS : Cela contracte les morceaux de texte de la forme <balise blah blah blah>…</balise> et <balise blah blah blah/>.

Évidemment il faudrait regarder le standard XML pour les détails et constructions étranges (genre je ne cherche pas les <![CDATA[…]]>.

Dernière modification par chopinhauer (Le 20/11/2010, à 20:56)


Pensez à donner un bon titre à vos sujets : cela permettra d'aider d'autres utilisateurs dans votre même situation. Ce n'est pas qu'en donnant des solutions qu'on aide, mais aussi en posant des bonnes questions et… facilement trouvables.

Hors ligne

#6 Le 20/11/2010, à 21:08

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Soit le texte suivant dans le fichier « xml.po » :

msgid ""
"<application>Dasher</application> can be started by selecting "
"<guimenuitem>Dasher</guimenuitem> from the <guisubmenu>Accessibility </"
"guisubmenu> submenu of the <guimenu>Main Menu</guimenu>, or by running the "
"command <command>dasher</command> on the command line."

La commande :

sed -n -e 'H' -e '${g;:a;s/<\([[:alpha:]]\+\)\( [^>]*\)\?>[^<]*<\/\1>\|<[^>]\+\/>//g;ta;s/[ \t\n]//g;p}' xml.po

me renvoie ça :

msgid"""canbestartedbyselecting""fromthe<guisubmenu>Accessibility</""guisubmenu>submenuofthe,orbyrunningthe""commandonthecommandline."

Ce n'est pas normal à priori.
Merci pour ton aide, je vais creuser un peu.


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#7 Le 20/11/2010, à 21:28

chopinhauer

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Bah, oui, parce que t'as par exemple t'as des mots comme </"\n"guisubmenu>. Mon expression rationnelle ne reconnait pas cela comme fin d'une balise. Sinon à la fin tu devrais avoir quelque chose qui ne contient plus de balises (tandis que dans un fichier XML une fois les balises enlevées il ne reste que la déclaration <?xml…?>).

Je ne connais pas le format des fichiers .po mais tu peux filtrer les guillemets dans la première expression et garder la deuxième (enlève le s qui élimine les espaces…) :

sed -n -e 's/^\(msgid\)\?[[:space:]]*"\(.*\)"[[:space:]]*$/\2/;H' \
-e '${g;:a;s/<\([[:alpha:]]\+\)\( [^>]*\)\?>[^<]*<\/\1>\|<[^>]\+\/>//g;ta;p}'

Le fonctionnement du programme est simple : la première ligne charge le lignes dans les holding space, la dernière s'applique pour la dernière ligne uniquement et remet le holding space dans le pattern space et fais la substitution en boucle.

Dernière modification par chopinhauer (Le 20/11/2010, à 22:16)


Pensez à donner un bon titre à vos sujets : cela permettra d'aider d'autres utilisateurs dans votre même situation. Ce n'est pas qu'en donnant des solutions qu'on aide, mais aussi en posant des bonnes questions et… facilement trouvables.

Hors ligne

#8 Le 20/11/2010, à 22:09

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

(il te manque un « ' » en début de deuxième ligne)

En utilisant cette commande, j'obtiens ceci : (avec le même texte)

 can be started by selecting 
 from the <guisubmenu>Accessibility </
guisubmenu> submenu of the , or by running the 
command  on the command line.

(il y a 2 lignes vides avant)

Il doit manquer un bout pour le saut de ligne.
Quand ça marchera, il suffira de faire un grep sur une regexp de balise pour voir si tout est bien fermé, donc pas de résultat = tout va bien. C'est ça ?

Arg, et c'est vrai que mon texte d'exemple ne montre pas les cas où il y a des balises imbriquées... sad
Tant pis si ça n'est pas faisable écoute, je ferais avec (ou plutôt sans).

Dernière modification par Malaria (Le 20/11/2010, à 22:18)


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#9 Le 20/11/2010, à 22:21

chopinhauer

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Version "adieu aux retours à la ligne" :

sed -n -e 's/^\(msgid\)\?[[:space:]]*"\(.*\)"[[:space:]]*$/\2/;H' \
-e '${g;s/[\n]//g;:a;s/<\([[:alpha:]]\+\)\( [^>]*\)\?>[^<]*<\/\1>\|<[^>]\+\/>//g;ta;p}'

Oui, j'imagine qu'il te suffira chercher le caractère '<', car il ne peut pas se trouver dans du texte XML.

Dernière modification par chopinhauer (Le 20/11/2010, à 22:22)


Pensez à donner un bon titre à vos sujets : cela permettra d'aider d'autres utilisateurs dans votre même situation. Ce n'est pas qu'en donnant des solutions qu'on aide, mais aussi en posant des bonnes questions et… facilement trouvables.

Hors ligne

#10 Le 20/11/2010, à 22:46

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Mais c'est génial ! yikes
Ça fonctionne même quand les balises sont imbriquées !

Félicitation, tu es officiellement devenu mon nouveau héros. Je peux avoir un autographe ?

J'étudierais les détails de la commande à tête reposée (c'est vrai que de loin ça ressemble à du klingon tongue).
En tout cas je suis vraiment impressionné (par toi et par sed), je ne pensais pas que c'était possible de gérer ça en shell (j'imaginais un programme C compliqué qui lisait caractère par caractère lol)

Encore une fois merci. Si on se croise un jour IRL, fait moi penser à te payer un verre de ton breuvage préféré.


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne

#11 Le 20/11/2010, à 23:25

chopinhauer

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Sed est Turing complet, donc il peut faire tout ce que n'importe quel langage de programmation peut faire. Cela n'empêche que le code source aura l'air d'être écrit en Unlambda et sera très peu performant. Vu que au départ t'as donné un code sed avancé, j'ai continué sur cette route.

Utiliser C pour des programmes courts n'est pas économe en temps : vaut mieux utiliser Perl ou Python.

Pour la signification de mon code, en pseudo-code cela équivaut à :

hold = ''
while(ligne = lire_une_ligne()):
    ligne = morceau de ligne entre guillemets;
    hold = hold + "\n" + ligne;
    if (dernière_ligne()):
        ligne = hold;
        while (on a fait une substitution):
            ligne = ligne sans toute chaine <balise>que du texte</balise> ou <balise/>
        print ligne
    fi

Dernière modification par chopinhauer (Le 20/11/2010, à 23:25)


Pensez à donner un bon titre à vos sujets : cela permettra d'aider d'autres utilisateurs dans votre même situation. Ce n'est pas qu'en donnant des solutions qu'on aide, mais aussi en posant des bonnes questions et… facilement trouvables.

Hors ligne

#12 Le 21/11/2010, à 00:45

Malizor

Re : [Résolu] Bash : Vérifier que toutes les balises XML sont fermées

Que dire de plus si ce n'est encore merci ? wink


« Prouver que j'ai raison serait accorder que je puis avoir tort. »  -  Beaumarchais  ← Le premier troll ?

Hors ligne