Traitement xml shell script
Résolu
farwarx
Messages postés
125
Date d'inscription
Statut
Membre
Dernière intervention
-
farwarx Messages postés 125 Date d'inscription Statut Membre Dernière intervention -
farwarx Messages postés 125 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
J'ai un soucis!
J'essaye de traiter un fichier au format xml (balises) sans succès :s
Un fichier comporte plusieurs blocs séparer par des balises.
Voici le type de bloc:
Je veux avoir comme résultat:
J'ai essayé avec sed et grep et paste > problème sur les champs "Other Name".
Je tente avec awk et match sans succès!!!
Avec de l'aide, on avait presque réussi avec cette commande (sur une CentOs):
Mais à mon grand regret, je n'ai plus accès à cette machine et awk n'a pas la même fonction match, il ne supporte pas le tableau!!!
Quelqu'un pour m'aider?
J'ai un soucis!
J'essaye de traiter un fichier au format xml (balises) sans succès :s
Un fichier comporte plusieurs blocs séparer par des balises.
Voici le type de bloc:
<listitem> <variable name="Name">farwarx</variable> <variable name="Other Name">farwarx1</variable> <variable name="Other Name">farwarx2</variable> <variable name="Other Name">farwarx2</variable> <variable name="Fullname">Mr Farwarx</variable> <variable name="Description">Comment ca marche</variable> </listitem>
Je veux avoir comme résultat:
farwarx;farwarx1,farwarx2,farwarx3;Mr Farwarx;Comment ca marche
J'ai essayé avec sed et grep et paste > problème sur les champs "Other Name".
Je tente avec awk et match sans succès!!!
Avec de l'aide, on avait presque réussi avec cette commande (sur une CentOs):
#awk '{if ($1=="<listitem>") ligne=""; else if ($1=="</listitem>") print ligne; else { match($0,/<variable name="([^"]*)">([^<]*)</,champ); ligne=ligne""(champ[1]==prev? ",": ";")""champ[2]; prev=champ[1]; }}' prev=toto FICHIER
Mais à mon grand regret, je n'ai plus accès à cette machine et awk n'a pas la même fonction match, il ne supporte pas le tableau!!!
Quelqu'un pour m'aider?
A voir également:
- Traitement xml shell script
- Classic shell - Télécharger - Personnalisation
- Xml download - Télécharger - Édition & Programmation
- Script vidéo youtube - Guide
- Reconsidérer le traitement de vos informations à des fins publicitaires - Accueil - Réseaux sociaux
- Traitement de texte gratuit - Guide
4 réponses
Salut,
;-))
jp@MDK:~ ssh$ cat farwarx <listitem> <variable name="Name">farwarx</variable> <variable name="Other Name">farwarx1</variable> <variable name="Other Name">farwarx2</variable> <variable name="Other Name">farwarx2</variable> <variable name="Fullname">Mr Farwarx</variable> <variable name="Description">Comment ca marche</variable> </listitem> jp@MDK:~ ssh$ sed 's/ *<[^>]*>//g' farwarx | sed '/^$/d' | sed ':z;N;$!bz;s/\n/;/g' farwarx;farwarx1;farwarx2;farwarx2;Mr Farwarx;Comment ca marche jp@MDK:~ ssh$
;-))
Je savais que ça serai toi jipicy qui répondrai ;)
J'ai trouvé une solution 'alternative' et non optimisée... mais c'était urgent :S
Ton résultat n'est pas totalement correct:
Note les ',' pour les champs identiques.
Il faudrait que je me mette sérieusement sur sed, awk etc...., trop puissant ces outils ;)
Voici ma solution alternative:
J'avais d'autres champs par rapport à l'exemple, mais le principe est le même.
Et je l'exécute avec un fichier en paramètre.
Pas rapide, je te l'accorde, mais il fait ce que je lui demande, faute de savoir sur sed et awk.....
Je sais qu'il est moche, mais qu'en on a plusieurs centaines de blocs, on scripte quoi qu'il arrive ^^
Merci.
J'ai trouvé une solution 'alternative' et non optimisée... mais c'était urgent :S
Ton résultat n'est pas totalement correct:
farwarx;farwarx1;farwarx2;farwarx2;Mr Farwarx;Comment ca marche farwarx;farwarx1,farwarx2,farwarx2;Mr Farwarx;Comment ca marche
Note les ',' pour les champs identiques.
Il faudrait que je me mette sérieusement sur sed, awk etc...., trop puissant ces outils ;)
Voici ma solution alternative:
#!/bin/bash while read ligne; do if [ "$ligne" == "<listitem>" ] then liste="" elif [ "$ligne" == "</listitem>" ] then echo $liste Name="" Domain="" Fullname="" Description="" MailAddress="" ForwardMode="" ForwardAddress="" Account_enabled="" else lparse=`echo $ligne |sed -e 's/<variable name="//' -e 's/">.*//'` case $lparse in Name) Name=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; Domain) Domain=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; Fullname) Fullname=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; Description) Description=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; MailAddress) MailAddress=$MailAddress","`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; ForwardMode) ForwardMode=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; ForwardAddress) ForwardAddress=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; Account_enabled) Account_enabled=`echo $ligne |sed -e 's/.*">//' -e 's/<\/variable>//'` ;; *) ;; esac liste=$Name";"$Domain";"$Fullname";"$Description";"$MailAddress";"$ForwardMode";"$ForwardAddress";"$Account_enabled liste=`echo $liste | sed -e 's/;,/;/'` fi done < $1
J'avais d'autres champs par rapport à l'exemple, mais le principe est le même.
Et je l'exécute avec un fichier en paramètre.
Pas rapide, je te l'accorde, mais il fait ce que je lui demande, faute de savoir sur sed et awk.....
Je sais qu'il est moche, mais qu'en on a plusieurs centaines de blocs, on scripte quoi qu'il arrive ^^
Merci.
[tmpfs]$ cat farwarx <listitem> <variable name="Name">farwarx</variable> <variable name="Other Name">farwarx1</variable> <variable name="Other Name">farwarx2</variable> <variable name="Other Name">farwarx2</variable> <variable name="Fullname">Mr Farwarx</variable> <variable name="Description">Comment ca marche</variable> </listitem> <listitem> <variable name="Name">toto</variable> <variable name="Other Name">toto1</variable> <variable name="Other Name">toto2</variable> <variable name="Other Name">toto2</variable> <variable name="Other Name">toto2</variable> <variable name="Fullname">Mr Toto</variable> <variable name="Description">Comment ca marche bien</variable> </listitem> [tmpfs]$ cat test.sed #n \#<listitem>#,\#</listitem># { /"Name/{ s/ *<[^>]*>//g s/$/%/ h D } :z /r Name/{ s/ *<[^>]*>//g H N D bz } /Fullname/{ s/ *<[^>]*>//g s/^/%/ H D } /Description/{ s/ *<[^>]*>//g s/^/%/ H D } g s/\n%\|%\n/;/g s/\n/,/gp s/.*// x d } [tmpfs]$ sed -f test.sed farwarx farwarx;farwarx1,farwarx2,farwarx2;Mr Farwarx;Comment ca marche toto;toto1,toto2,toto2,toto2;Mr Toto;Comment ca marche bien [tmpfs]$
;-))
J'essaye de comprendre ton fichier test.sed.
Est-ce que le #n a une importance?
Que signifie exactement \#<listitem>#,\#</listitem># {?
Ensuite j'ai bien compris que lorsque il trouve une occurrence (/"Name"/{, il exécute ce qu'il y a en dessous jusqu'à l'accolade.
s: substitution
Pour l'occurrence qui se répète on utilise un 'label' (comme un Go To?).
:z pour le le début du label
bz pour revenir au label z
J'ai traduit du man les autres options (H, N, D), mais je n'ai pas tout compris.
J'ai l'impression que l'option D permet de passer à la ligne suivante.
Pour le H, je dirai qu'il stocke le résultat dans une case d'un tableau temporaire.
Pour le N, c'est comme H mais il va mettre la prochaine valeur dans la même case que la précédente.
Et au niveau du dernier bloc d'instruction, il se retrouve avec une ligne de résultat, et la tu le parses pour obtenir le résultat désiré.
Tu avais rajouté le caractère '%' pour différencier les ';' des ',' et le tour est joué.
C'est ça?
Est-ce que le #n a une importance?
Que signifie exactement \#<listitem>#,\#</listitem># {?
Ensuite j'ai bien compris que lorsque il trouve une occurrence (/"Name"/{, il exécute ce qu'il y a en dessous jusqu'à l'accolade.
s: substitution
Pour l'occurrence qui se répète on utilise un 'label' (comme un Go To?).
:z pour le le début du label
bz pour revenir au label z
J'ai traduit du man les autres options (H, N, D), mais je n'ai pas tout compris.
J'ai l'impression que l'option D permet de passer à la ligne suivante.
Pour le H, je dirai qu'il stocke le résultat dans une case d'un tableau temporaire.
Pour le N, c'est comme H mais il va mettre la prochaine valeur dans la même case que la précédente.
Et au niveau du dernier bloc d'instruction, il se retrouve avec une ligne de résultat, et la tu le parses pour obtenir le résultat désiré.
Tu avais rajouté le caractère '%' pour différencier les ';' des ',' et le tour est joué.
C'est ça?
Est-ce que le #n a une importance?
Oui. En fait c'est l'équivalent du "-n" en ligne de commande. On n'affiche le traitement que si c'est implicitement demandé, donc avec le flag "p".
Que signifie exactement \#<listitem>#,\#</listitem># {?
C'est ce qu'on appelle des intervalles d'adressage, en fait les commandes comprises entre { et } ne s'appliqueront qu'a chaque intervalle de lignes situées entre les 2 motifs.
Ensuite j'ai bien compris que lorsque il trouve une occurrence (/"Name"/{, il exécute ce qu'il y a en dessous jusqu'à l'accolade.
Oui.
s: substitution
Oui.
Pour l'occurrence qui se répète on utilise un 'label' (comme un Go To?).
:z pour le le début du label
bz pour revenir au label z
Oui
J'ai traduit du man les autres options (H, N, D), mais je n'ai pas tout compris.
J'ai l'impression que l'option D permet de passer à la ligne suivante.
Euh... non pas exactement, en fait c'est plus complexe. La commande D supprime de l'espace de travail (mémoire principale où est stockée la ligne en cours de traitement), tout ce qui est compris entre le début de la ligne jusqu'au 1er caractère de fin de ligne symbolisé par "\n".
En gros si tu as une ligne dans l'espace de travail qui ressemble à :
blabla\nautre chose\nla fin
et que tu appliques la commande D, il restera :
autre chose\nla fin
et le traitement (sur cette ligne) reprendra au début du script (et non pas à l'instruction suivante).
Pour le H, je dirai qu'il stocke le résultat dans une case d'un tableau temporaire.
En gros oui, on appelle ça la mémoire secondaire. La ligne en cours de traitement est ajoutée (au contraire de la commande "h" où là la ligne est envoyée dans la mémoire tampon en écrasant ce qui s'y trouve) au contenu déjà présent. Chaque fin de ligne étant matérialisée par un \n.
Non, la commande N ajoute la ligne suivante à la suite de celle contenue dans l'espace de travail, à l'instar de la commande "n" qui elle écrase le contenu de l'espace de travail par la ligne suivante.
Et au niveau du dernier bloc d'instruction, il se retrouve avec une ligne de résultat, et la tu le parses pour obtenir le résultat désiré.
Exact, avec la commande "g" qui rapatrie le contenu de la mémoire annexe dans l'espace de travail en écrasant le contenu. La commande "G" faisant la me chose mais en ajoutant à la suite.
Tu avais rajouté le caractère '%' pour différencier les ';' des ',' et le tour est joué.
Yes, il me fallait bien un subterfuge pour faire la différence ;-))
C'est ça?
En gros oui ;-))
Pour de plus amples renseignements, voir la FAQ sur sed ;-))
Oui. En fait c'est l'équivalent du "-n" en ligne de commande. On n'affiche le traitement que si c'est implicitement demandé, donc avec le flag "p".
Que signifie exactement \#<listitem>#,\#</listitem># {?
C'est ce qu'on appelle des intervalles d'adressage, en fait les commandes comprises entre { et } ne s'appliqueront qu'a chaque intervalle de lignes situées entre les 2 motifs.
Ensuite j'ai bien compris que lorsque il trouve une occurrence (/"Name"/{, il exécute ce qu'il y a en dessous jusqu'à l'accolade.
Oui.
s: substitution
Oui.
Pour l'occurrence qui se répète on utilise un 'label' (comme un Go To?).
:z pour le le début du label
bz pour revenir au label z
Oui
J'ai traduit du man les autres options (H, N, D), mais je n'ai pas tout compris.
J'ai l'impression que l'option D permet de passer à la ligne suivante.
Euh... non pas exactement, en fait c'est plus complexe. La commande D supprime de l'espace de travail (mémoire principale où est stockée la ligne en cours de traitement), tout ce qui est compris entre le début de la ligne jusqu'au 1er caractère de fin de ligne symbolisé par "\n".
En gros si tu as une ligne dans l'espace de travail qui ressemble à :
blabla\nautre chose\nla fin
et que tu appliques la commande D, il restera :
autre chose\nla fin
et le traitement (sur cette ligne) reprendra au début du script (et non pas à l'instruction suivante).
Pour le H, je dirai qu'il stocke le résultat dans une case d'un tableau temporaire.
En gros oui, on appelle ça la mémoire secondaire. La ligne en cours de traitement est ajoutée (au contraire de la commande "h" où là la ligne est envoyée dans la mémoire tampon en écrasant ce qui s'y trouve) au contenu déjà présent. Chaque fin de ligne étant matérialisée par un \n.
Pour le N, c'est comme H mais il va mettre la prochaine valeur dans la même case que la précédente.
Non, la commande N ajoute la ligne suivante à la suite de celle contenue dans l'espace de travail, à l'instar de la commande "n" qui elle écrase le contenu de l'espace de travail par la ligne suivante.
Et au niveau du dernier bloc d'instruction, il se retrouve avec une ligne de résultat, et la tu le parses pour obtenir le résultat désiré.
Exact, avec la commande "g" qui rapatrie le contenu de la mémoire annexe dans l'espace de travail en écrasant le contenu. La commande "G" faisant la me chose mais en ajoutant à la suite.
Tu avais rajouté le caractère '%' pour différencier les ';' des ',' et le tour est joué.
Yes, il me fallait bien un subterfuge pour faire la différence ;-))
C'est ça?
En gros oui ;-))
Pour de plus amples renseignements, voir la FAQ sur sed ;-))
Complément d'infos...
Concernant :
Que signifie exactement \#<listitem>#,\#</listitem># {?
C'est ce qu'on appelle des intervalles d'adressage ou plages d'adresses, en fait les commandes comprises entre { et } ne s'appliqueront qu'a chaque intervalle de lignes situées entre les 2 motifs.
En ce qui concerne les "\#", en fait les caractères délimiteurs par défaut sont normalement les slashs "/", mais comme ce caractère se retrouve dans le motif lui même et pour ne pas avoir à l'échapper avec un anti-slash, j'ai préféré initialiser un nouveau délimiteur (le dièse) et pour ce faire je l'introduis en le protégeant par un anti-slash "\#".
Tu me diras que ça revient presque au même que si j'avais laissé le délimiteur par défaut, c'est vrai, mais dans le cas de plusieurs slash dans le motif (comme un chemin ou URL) ça devient vite illisible ;-(
Concernant :
Que signifie exactement \#<listitem>#,\#</listitem># {?
C'est ce qu'on appelle des intervalles d'adressage ou plages d'adresses, en fait les commandes comprises entre { et } ne s'appliqueront qu'a chaque intervalle de lignes situées entre les 2 motifs.
En ce qui concerne les "\#", en fait les caractères délimiteurs par défaut sont normalement les slashs "/", mais comme ce caractère se retrouve dans le motif lui même et pour ne pas avoir à l'échapper avec un anti-slash, j'ai préféré initialiser un nouveau délimiteur (le dièse) et pour ce faire je l'introduis en le protégeant par un anti-slash "\#".
Tu me diras que ça revient presque au même que si j'avais laissé le délimiteur par défaut, c'est vrai, mais dans le cas de plusieurs slash dans le motif (comme un chemin ou URL) ça devient vite illisible ;-(