Idéalement, ce que je voudrais être en mesure de faire est :
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
Idéalement, ce que je voudrais être en mesure de faire est :
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
C'est vraiment juste une explication de Yuzem's répondre, mais je n'avais pas l'impression qu'autant d'édition devait être faite par quelqu'un d'autre, et les commentaires ne permettent pas le formatage, donc...
rdom () { local IFS=\> ; read -d \< E C ;}
Appelons cela "read_dom" au lieu de "rdom", espaçons-le un peu et utilisons des variables plus longues :
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
}
Ok, donc il définit une fonction appelée read_dom. La première ligne rend IFS (le séparateur de champ d'entrée) local à cette fonction et le change en >. Cela signifie que lorsque vous lisez des données, au lieu d'être automatiquement séparées par un espace, une tabulation ou une nouvelle ligne, elles sont séparées par '>'. La ligne suivante dit de lire l'entrée de stdin, et au lieu de s'arrêter à une nouvelle ligne, de s'arrêter quand vous voyez un caractère '<' (le drapeau -d pour deliminator). Ce qui est lu est ensuite divisé en utilisant l'IFS et assigné aux variables ENTITY et CONTENT. Prenons l'exemple suivant :
<tag>value</tag>
Le premier appel à read_dom
obtient une chaîne vide (puisque le '<' est le premier caractère). Elle est divisée par IFS en seulement '', puisqu'il n'y a pas de caractère '>'. Read attribue alors une chaîne vide aux deux variables. Le deuxième appel obtient la chaîne 'tag>value'. Elle est alors divisée par l'IFS en deux champs 'tag' et 'value'. Read assigne ensuite les variables comme suit : ENTITY=tag
et CONTENT=value
. Le troisième appel obtient la chaîne '/tag>'. Celle-ci est divisée par l'IFS en deux champs '/tag' et ''. Read assigne ensuite les variables comme : ENTITY=/tag
et CONTENT=
. Le quatrième appel renverra un état non nul car nous avons atteint la fin du fichier.
Maintenant sa boucle while a été nettoyée un peu pour correspondre à ce qui précède :
while read_dom; do
if [[ $ENTITY = "title" ]]; then
echo $CONTENT
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
La première ligne dit simplement "tant que la fonction read_dom renvoie un état nul, faites ce qui suit". La deuxième ligne vérifie si l'entité que nous venons de voir est "title". La ligne suivante fait écho au contenu de la balise. La quatrième ligne sort. Si ce n'était pas l'entité "title", la boucle se répète à la sixième ligne. Nous redirigeons "xhtmlfile.xhtml" vers l'entrée standard (pour la balise read_dom
) et redirige la sortie standard vers "titleOfXHTMLPage.txt" (l'écho obtenu plus tôt dans la boucle).
Maintenant, étant donné ce qui suit (similaire à ce que vous obtenez en listant un seau sur S3) pour input.xml
:
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>sth-items</Name>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>item-apple-iso@2x.png</Key>
<LastModified>2011-07-25T22:23:04.000Z</LastModified>
<ETag>"0032a28286680abee71aed5d059c6a09"</ETag>
<Size>1785</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
et la boucle suivante :
while read_dom; do
echo "$ENTITY => $CONTENT"
done < input.xml
Tu devrais avoir :
=>
ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/" =>
Name => sth-items
/Name =>
IsTruncated => false
/IsTruncated =>
Contents =>
Key => item-apple-iso@2x.png
/Key =>
LastModified => 2011-07-25T22:23:04.000Z
/LastModified =>
ETag => "0032a28286680abee71aed5d059c6a09"
/ETag =>
Size => 1785
/Size =>
StorageClass => STANDARD
/StorageClass =>
/Contents =>
Donc si nous avons écrit un while
boucle comme celle de Yuzem :
while read_dom; do
if [[ $ENTITY = "Key" ]] ; then
echo $CONTENT
fi
done < input.xml
Nous obtiendrons une liste de tous les fichiers dans le seau S3.
EDIT Si pour une raison quelconque local IFS=\>
ne fonctionne pas pour vous et que vous l'avez défini globalement, vous devez le réinitialiser à la fin de la fonction comme :
read_dom () {
ORIGINAL_IFS=$IFS
IFS=\>
read -d \< ENTITY CONTENT
IFS=$ORIGINAL_IFS
}
Sinon, tout découpage de ligne que vous ferez plus tard dans le script sera perturbé.
EDIT 2 Pour séparer les paires nom/valeur d'attributs, vous pouvez augmenter la fonction read_dom()
comme ça :
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local ret=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $ret
}
Puis écrivez votre fonction pour analyser et obtenir les données que vous voulez comme ceci :
parse_dom () {
if [[ $TAG_NAME = "foo" ]] ; then
eval local $ATTRIBUTES
echo "foo size is: $size"
elif [[ $TAG_NAME = "bar" ]] ; then
eval local $ATTRIBUTES
echo "bar type is: $type"
fi
}
Alors pendant que vous read_dom
appelez parse_dom
:
while read_dom; do
parse_dom
done
Puis, étant donné l'exemple de balisage suivant :
<example>
<bar size="bar_size" type="metal">bars content</bar>
<foo size="1789" type="unknown">foos content</foo>
</example>
Vous devriez obtenir ce résultat :
$ cat example.xml | ./bash_xml.sh
bar type is: metal
foo size is: 1789
EDIT 3 un autre utilisateur a dit qu'ils avaient des problèmes avec FreeBSD et a suggéré de sauvegarder le statut de sortie de read et de le retourner à la fin de read_dom comme :
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local RET=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $RET
}
Je ne vois pas pourquoi ça ne marcherait pas.
Les outils de ligne de commande qui peuvent être appelés à partir des scripts du shell comprennent :
4xpath - autour de la ligne de commande de Python. 4Suite paquet
xpath - enveloppe de ligne de commande autour de la bibliothèque XPath de Perl
sudo apt-get install libxml-xpath-perl
Xidel - Fonctionne aussi bien avec les URL qu'avec les fichiers. Fonctionne également avec JSON
J'utilise aussi xmllint et xsltproc avec des petits scripts de transformation XSL pour faire du traitement XML à partir de la ligne de commande ou dans des scripts de shell.
Vous pouvez le faire très facilement en utilisant uniquement bash. Il vous suffit d'ajouter cette fonction :
rdom () { local IFS=\> ; read -d \< E C ;}
Maintenant vous pouvez utiliser rdom comme read mais pour les documents html. Lorsqu'il est appelé, rdom attribue l'élément à la variable E et le contenu à la var C.
Par exemple, pour faire ce que vous vouliez faire :
while rdom; do
if [[ $E = title ]]; then
echo $C
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
Vous pouvez utiliser l'utilitaire xpath. Il est installé avec le paquetage Perl XML-XPath.
Utilisation :
/usr/bin/xpath [filename] query
o XMLStarlet . Pour l'installer sur opensuse, utilisez :
sudo zypper install xmlstarlet
ou essayez cnf xml
sur d'autres plateformes.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.