web-dev-qa-db-fra.com

Jeu de commandes Native Shell pour extraire la valeur du noeud à partir de XML

J'essaie d'extraire la valeur d'un nœud d'un pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <parent>
        <groupId>org.me.labs</groupId>
        <artifactId>my-random-project</artifactId>
        <version>1.5.0</version>
    </parent>
    ...
</project>

J'ai besoin d'extraire artifactId et la version XML à l'aide d'une commande Shell. J'ai les exigences/observations suivantes:

  1. Le script Shell sera créé dans un fichier Assembly de construction utilisé au travail. Plus le script est petit, mieux c'est.
  2. Comme il sera utilisé sur plusieurs systèmes (généralement RHEL5), je cherche quelque chose qui puisse fonctionner en mode natif sur des images par défaut.
  3. Des balises comme celles-ci peuvent se trouver ailleurs dans le pom, je ne peux donc pas tout simplement les impressionner.

J'ai essayé ce qui suit:

  1. xpath fonctionne sur mon Mac, mais n'est pas disponible par défaut sur les machines RHEL. De même pour xmllint --xpath, qui, je suppose, n'est disponible que sur les versions ultérieures de xmllint, que je n'ai pas et que je ne peux pas appliquer.
  2. xmllint --pattern semblait prometteur, mais je n'arrive pas à obtenir une sortie sur xmllint --pattern '//project/parent/version' pom.xml (affiche tout le code XML) ou xmllint --stream --pattern '//project/parent/version' pom.xml (pas de sortie).

Je me rends compte que c’est une question courante ici sur les SO, mais les points ci-dessus expliquent pourquoi je ne peux pas utiliser ces réponses. TIA pour votre aide.

25
Karthik. V

J'ai réussi à le résoudre pour le moment avec ce script plutôt involontaire en utilisant xmllint --Shell.

echo "cat //project/parent/version" | xmllint --Shell pom.xml | sed '/^\/ >/d' | sed 's/<[^>]*.//g'

Si les noeuds XML ont des attributs d'espace de noms comme ceux de mon pom.xml, les choses deviennent plus lourdes, en extrayant le noeud par son nom:

echo "cat //*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']" | xmllint --Shell pom.xml | sed '/^\/ >/d' | sed 's/<[^>]*.//g'

J'espère que ça aide. Si quelqu'un peut simplement ces expressions, je vous en serais reconnaissant.

14
Karthik. V

--format est utilisé uniquement pour formater (indenter, etc.) le document. Vous pouvez le faire en utilisant --xpath (testé dans Ubuntu, libxml v20900):

$ xmllint --xpath "//project/parent/version/text()" pom.xml
1.5.0
15
Salem

Je suis venu ici à la recherche d'un bon moyen de gratter une valeur d'un site Web. L'exemple suivant peut être utile à ceux (contrairement à l'affiche) qui ont une version de xmllint qui prend en charge --xpath.

J'avais besoin d'extraire la version stable la plus récente du fichier .debfile d'elasticsearch et de l'installer. Les responsables ont utilement placé le numéro de version dans une plage avec la classe "version".

version=`curl -s http://www.elasticsearch.org/download/ |\
 xmllint --html --xpath '//span[@class="version"]/text()'\
 2>/dev/null - `;

Ce qui se passe:

Nous utilisons l'option curl -s (silencieuse).

curl -s http://www.elasticsearch.org/download/

Nous utilisons les commutateurs xmllint --html et --xpath. Les arguments xpath (entre guillemets simples)

'//span[@class="version"]/text()'

... recherche un noeud <span> avec l'attribut de classe (@class) "version" et extrait la valeur de texte (/ text ()).

Puisque xmllint est (surprise!) Un linter, il gémira à propos des déchets inévitables dans votre flux HTML. Nous dirigeons le stderr vers/dev/null de la manière habituelle:

 2>/dev/null

Enfin, notez le "-" à la fin de la commande xmllint, qui indique à xmllint que le flux provient de stdin. 

5
lysdexia

L'utilisation de la fonction text() XPath vous donne la valeur de l'élément, sans avoir à supprimer les balises XML

echo "cat //project/parent/version/text()" | xmllint --Shell pom.xml
3
jpwilksch

Avec les POM, vous pouvez créer des problèmes d'espaces de nommage empêchant xmllint de fonctionner comme prévu. This articles vous indique une solution de rechange très efficace (regardez le paragraphe sed).

0
Antonio Petricca

Tu peux essayer

xmllint --xpath "/*[name()='project']/*[name()='groupId']/text()" pom.xml

0
Tex