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 28/10/2019, à 10:37

Gulian

Parser XML Bash [Résolu]

Bonjour à tous,

Je début le bash, et j'ai décidé de tenter de programmer un parser XML en Bash.

Le fichier a parser :
https://www.w3schools.com/xml/plant_catalog.xml

Voici mon code :

 #!/bin/bash

common="";
botanical="";
zone="";
light="";
price="";
availability="";

while read line

do
        if  echo $line |grep "<COMMON>" -q
        then
        common=`echo -n $line | sed 's/<[^>]*>//g'`

        elif echo $line |grep "<BOTANICAL>" -q
        then
        botanical=`echo -n  $line | sed 's/<[^>]*>//g'`

        elif echo $line |grep "<ZONE>" -q
        then
        zone=`echo $line | sed 's/<[^>]*>//g'`

        elif echo $line |grep "<LIGHT>" -q
        then
        light=`echo $line | sed 's/<[^>]*>//g'`

        elif echo $line |grep "<PRICE>" -q
        then
        price=`echo $line | sed 's/<[^>]*>//g'`

        elif echo $line |grep "<AVAILABILITY>" -q
        then
        availability=`echo $ine | sed 's/<[^>]*>//g'`
        fi

        if echo $line |grep "</PLANT>" -q
        then
        echo "$common;$botanical;$zone"
        fi

done

Jusqu'ici tout va bien, le problème vient juste du dernier echo. L'affichage ne se fait pas bien, j'obtiens un résultat de la sorte :

;4anguinaria canadensis
;3quilegia canadensis
;4altha palustris
;4altha palustris
;3icentra cucullaria
;3sarum canadense
;4epatica americana
;4epatica americana
;4risaema triphyllum
;3odophyllum peltatum
;3hlox divaricata
;3hlox divaricata
;7laytonia Virginica
;5rillium grandiflorum
;5rillium grandiflorum
;4rythronium americanum
;4rythronium americanum
;4rythronium americanum
;6nemone blanda
;6nemone blandawer
;4onarda didyma
;4onarda didyma
;Annualkia hirta
;4anunculus
;4anunculus
;Annualias tuberosa
;Annualilla
;3 - 5hera
;4entiana
;4entianaian
;Annualnium caeruleum
;Annualnium caeruleum
;Annualholzia californica
;Annualtheonr
;Annualfuga
;2obelia cardinalis

Je suppose un probleme avec le ';' dans le echo, mais rien de concluant ...
Auriez-vous un conseil a me donner ?

Merci bien smile

Dernière modification par Gulian (Le 28/10/2019, à 12:54)

Hors ligne

#2 Le 28/10/2019, à 11:59

pingouinux

Re : Parser XML Bash [Résolu]

Bonjour,
Les lignes du fichier .xml se terminent par \r\n au lieu de \n.
Pour supprimer le caractère excédentaire, tu peux ajouter cette ligne en début de boucle :

        line=$(sed 's/\r//' <<<"$line")

D'autre part, il y a une faute de frappe à la ligne n°36 ($ine au lieu de $line).

        availability=`echo $ine | sed 's/<[^>]*>//g'`

Ajouté :
Au lieu d'ajouter une ligne en début de boucle, tu peux aussi modifier tes sed.
Par exemple :

        common=`echo -n $line | sed -r 's/.*>(.*)<.*/\1/'`

Dernière modification par pingouinux (Le 28/10/2019, à 12:35)

Hors ligne

#3 Le 28/10/2019, à 12:52

Gulian

Re : Parser XML Bash [Résolu]

Merci !

L'erreur était bien du au \r\n et j'ai corrigé la faute de frappe haha

J'aurai pu chercher des heures dans mon code ...

Je te remercie pour la réponse !

Hors ligne

#4 Le 28/10/2019, à 17:18

kamaris

Re : Parser XML Bash [Résolu]

Tu peux indiquer directement à la commande read que le délimiteur de ligne est \r\n au lieu de \n, par l'option -d $'\r\n'.
Tu pourrais aussi utiliser un tableau associatif pour factoriser un peu ton code :

#!/bin/bash

declare -A tags=( [COMMON]='' [BOTANICAL]='' [ZONE]='' \
  [LIGHT]='' [PRICE]='' [AVAILABILITY]='' )

while read -rd $'\r\n' line; do
  for tag in "${!tags[@]}"; do
    grep -q "<$tag>" <<< "$line" \
      && tags[$tag]=$(sed 's/<[^>]*>//g' <<< "$line")
  done
  grep -q '</PLANT>' <<< "$line" \
    && echo "${tags[COMMON]};${tags[BOTANICAL]};${tags[ZONE]}"
done < "$1"

Ce script s'appelle en passant en argument le fichier xml à parser.

Ensuite, une fois que tu l'as exécuté, tu peux faire l'expérience suivante : remplacer les grep par des tests équivalents en bash :

#!/bin/bash

declare -A tags=( [COMMON]='' [BOTANICAL]='' [ZONE]='' \
  [LIGHT]='' [PRICE]='' [AVAILABILITY]='' )

while read -rd $'\r\n' line; do
  for tag in "${!tags[@]}"; do
    [[ $line == *"<$tag>"* ]] && tags[$tag]=$(sed 's/<[^>]*>//g' <<< "$line")
  done
  [[ $line =~ '</PLANT>' ]] && echo "${tags[COMMON]};${tags[BOTANICAL]};${tags[ZONE]}"
done < "$1"

et tu l'exécutes à nouveau : tu devrais voir une petite différence au niveau du temps de traitement wink.

PS : et puis, quand tu en es là, tu peux essayer de remplacer le sed par une substitution équivalente en bash, et là, tu vas voir ton script s'envoler cool.

Dernière modification par kamaris (Le 28/10/2019, à 18:32)

Hors ligne

#5 Le 28/10/2019, à 18:43

Watael

Re : Parser XML Bash [Résolu]

et quand tu auras fini, tu passeras à un vrai parser de XML :

xmlstarlet sel -T -t -m "//CATALOG/PLANT" -v "concat(COMMON,';',BOTANICAL,';',ZONE)" --nl /tmp/plant_catalog.xml

il ne faut pas vous laisser influencer par cet exercice (stupide) : un fichier XML ne se parse jamais en bash. c'est pataud. c'est lent. ce n'est vraiment pas fait pour ça.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#6 Le 28/10/2019, à 20:06

kamaris

Re : Parser XML Bash [Résolu]

Gulian a écrit :

Je début le bash, et j'ai décidé de tenter de programmer un parser XML en Bash.

Il n'y a pas de jamais en matière d'exercice, on fait simplement ce qu'on veut smile
Cet exercice en vaut bien d'autres.

Hors ligne

#7 Le 28/10/2019, à 20:45

Watael

Re : Parser XML Bash [Résolu]

c'est stupide de donner en exercice de parser en shell une sortie versatile, telle que ls, xml, json

comme je l'ai dit, ça laisse entendre que c'est un bon usage de cet outil.
vis cruciforme, tournevis plat ...


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne