Existe-t-il un package, pour Ubuntu et / ou CentOS, qui dispose d'un outil de ligne de commande capable d'exécuter un XPath one-liner comme foo //element@attribute filename.xml
or foo //element@attribute < filename.xml
et de renvoyer les résultats ligne par ligne?
Je suis à la recherche de quelque chose qui me permettrait juste apt-get install foo
ou yum install foo
et puis juste de travailler hors de la boîte, aucun emballage ou autre adaptation nécessaire.
Voici quelques exemples de choses qui se rapprochent:
Nokogiri. Si j'écris ce wrapper, je pourrais appeler le wrapper de la manière décrite ci-dessus:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML :: XPath. Travaillerait avec ce wrapper:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
my $root = XML::XPath->new(ioref => 'STDIN');
for my $node ($root->find($ARGV[0])->get_nodelist) {
print($node->getData, "\n");
}
xpath
de XML :: XPath renvoie trop de bruit, -- NODE --
et attribute = "value"
.
xml_grep
from XML :: Twig ne peut pas gérer les expressions qui ne renvoient pas d'éléments, et ne peut donc pas être utilisée pour extraire des valeurs d'attribut sans traitement supplémentaire.
ÉDITER:
echo cat //element/@attribute | xmllint --shell filename.xml
renvoie un bruit similaire à xpath
.
xmllint --xpath //element/@attribute filename.xml
revient attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
renvoie ce que je veux, mais uniquement pour le premier match.
Pour une autre solution satisfaisant presque la question, voici un XSLT qui peut être utilisé pour évaluer des expressions XPath arbitraires (nécessite dyn: evaluer le support dans le processeur XSLT):
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">
<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
<xsl:template match="/">
<xsl:for-each select="dyn:evaluate($pattern)">
<xsl:value-of select="dyn:evaluate($value)"/>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Courez avec xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
la source
xpath
est sur STDERR et non sur STDOUT.Réponses:
Vous devriez essayer ces outils:
xmlstarlet
: peut éditer, sélectionner, transformer ... Non installé par défaut, xpath1xmllint
: souvent installé par défaut aveclibxml2-utils
, xpath1 (vérifiez mon wrapper pour avoir le--xpath
commutateur sur les très anciennes versions et la sortie délimitée par les nouvelles lignes (v <2.9.9)xpath
: installé via le module de perlXML::XPath
, xpath1xml_grep
: installé via le module de perlXML::Twig
, xpath1 (utilisation limitée de xpath)xidel
: xpath3saxon-lint
: mon propre projet, wrapper sur la bibliothèque Java Saxon-HE de @Michael Kay, xpath3xmllint
livré aveclibxml2-utils
(peut être utilisé comme shell interactif avec le--shell
commutateur)xmlstarlet
estxmlstarlet
.xpath
livré avec le module de perlXML::Xpath
xml_grep
livré avec le module de perlXML::Twig
xidel
estxidel
saxon-lint
en utilisant SaxonHE 9.6 , XPath 3.x (+ compatibilité rétro)Ex:
xmllint --xpath '//element/@attribute' file.xml xmlstarlet sel -t -v "//element/@attribute" file.xml xpath -q -e '//element/@attribute' file.xml xidel -se '//element/@attribute' file.xml saxon-lint --xpath '//element/@attribute' file.xml
.
la source
xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xml
fait exactement ce que je veux!xmllint
ne prennent pas en charge l'argument de ligne de commande--xpath
, mais la plupart semblent prendre en charge--shell
. Sortie légèrement plus sale, mais toujours utile dans une liaison.sel -t -m ... -v ...
exemple de cette page: arstechnica.com/information-technology/2005 / 11 / linux-20051115/2 , correspondant à tous les nœuds sauf le dernier et sauvegardant celui-ci pour l'expression de valeur comme mon cas d'utilisation, je n'arrive toujours pas à l'obtenir, je reçois juste une sortie vide ..Vous pouvez également essayer mon Xidel . Ce n'est pas dans un package dans le référentiel, mais vous pouvez simplement le télécharger à partir de la page Web (il n'a pas de dépendances).
Il a une syntaxe simple pour cette tâche:
xidel filename.xml -e '//element/@attribute'
Et c'est l'un des rares de ces outils à prendre en charge XPath 2.
la source
find . -name "*.xml" -printf '%p : ' -exec xidel {} -s -e 'expr' \;
Un package qui est très susceptible d'être installé sur un système l'est déjà
python-lxml
. Si tel est le cas, cela est possible sans installer de package supplémentaire:python -c "from lxml.etree import parse; from sys import stdin; print('\n'.join(parse(stdin).xpath('//element/@attribute')))"
la source
stdin
. Cela élimine le besoin d'inclureopen()
etclose()
dans une doublure déjà assez longue. Pour analyser un fichier, exécutez simplementpython -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xml
et laissez votre shell gérer la recherche, l'ouverture et la fermeture du fichier.Dans ma recherche pour interroger les fichiers maven pom.xml, j'ai parcouru cette question. Cependant, j'avais les limitations suivantes:
J'ai essayé plusieurs des solutions ci-dessus sans succès:
La solution que j'ai rencontrée qui est stable, courte et qui fonctionne sur de nombreuses plates-formes et qui est mature est la librairie rexml intégrée à ruby:
ruby -r rexml/document -e 'include REXML; puts XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
Ce qui m'a inspiré pour trouver celui-ci, ce sont les articles suivants:
la source
xmlstarlet
comme réponse acceptée, car elle correspond à mes critères plus larges et elle est vraiment soignée . Mais j'aurai probablement besoin de votre solution de temps en temps.puts
plutôt quep
dans la commande Ruby.Saxon le fera non seulement pour XPath 2.0, mais aussi pour XQuery 1.0 et (dans la version commerciale) 3.0. Il ne s'agit pas d'un package Linux, mais d'un fichier jar. La syntaxe (que vous pouvez facilement envelopper dans un simple script) est
java net.sf.saxon.Query -s:source.xml -qs://element/attribute
MISE À JOUR 2020
Saxon 10.0 inclut l'outil Gizmo, qui peut être utilisé de manière interactive ou par lots à partir de la ligne de commande. Par exemple
java net.sf.saxon.Gizmo -s:source.xml />show //element/@attribute />quit
la source
libsaxonb-java
, mais si je lance ,saxonb-xquery -qs://element/@attribute -s:filename.xml
j'obtiens leSENR0001: Cannot serialize a free-standing attribute node
même problème qu'avec par exemplexml_grep
.-qs
comme ceci:'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
Vous pourriez également être intéressé par xsh . Il dispose d'un mode interactif où vous pouvez faire ce que vous voulez avec le document:
open 1.xml ; ls //element/@id ; for //p[@class="first"] echo text() ;
la source
cpan XML::XSH2
.cpan XML::XSH2
ne parvient pas à installer quoi que ce soit.La réponse de clacke est excellente mais je pense que cela ne fonctionne que si votre source est du XML bien formé, pas du HTML normal.
Donc, pour faire de même pour le contenu Web normal - des documents HTML qui ne sont pas nécessairement du XML bien formé:
Et d'utiliser à la place html5lib (pour vous assurer d'obtenir le même comportement d'analyse que les navigateurs Web, car comme les analyseurs de navigateur, html5lib est conforme aux exigences d'analyse de la spécification HTML).
la source
Semblable aux réponses de Mike et de Clacke, voici le one-liner python (en utilisant python> = 2.5) pour obtenir la version de construction à partir d'un fichier pom.xml qui contourne le fait que les fichiers pom.xml n'ont normalement pas de dtd ou espace de noms par défaut, donc ne semble pas bien formé à libxml:
python -c "import xml.etree.ElementTree as ET; \ print(ET.parse(open('pom.xml')).getroot().find('\ {http://maven.apache.org/POM/4.0.0}version').text)"
Testé sur Mac et Linux, et ne nécessite l'installation d'aucun package supplémentaire.
la source
lxml
nixmllint
, ni même Ruby. Dans l'esprit du format de ma propre réponse , je l'ai écrit commepython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"
dans bash..getroot()
ne semble pas nécessaire.En plus de XML :: XSH et XML :: XSH2, il existe des
grep
utilitaires semblables à sucer commeApp::xml_grep2
etXML::Twig
(qui incluentxml_grep
plutôt quexml_grep2
). Ceux-ci peuvent être très utiles lorsque vous travaillez sur des fichiers XML volumineux ou nombreux pour des oneliners ou desMakefile
cibles rapides .XML::Twig
est particulièrement agréable àperl
utiliser pour une approche de script lorsque vous voulez un peu plus de traitement que votre$SHELL
etxmllint
xstlproc
offre .Le schéma de numérotation dans les noms d'applications indique que les versions «2» sont des versions plus récentes / plus récentes du même outil qui peut nécessiter des versions ultérieures d'autres modules (ou de
perl
lui - même).la source
xml_grep2 -t //element@attribute filename.xml
fonctionne et fait ce que j'attends (xml_grep --root //element@attribute --text_only filename.xml
ne le fait toujours pas, renvoie une erreur "expression non reconnue"). Génial!xml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xml
? Je ne sais pas ce qui se passe là-bas ou ce que XPath dit[]
dans ce cas, mais entourer un@attribute
avec des crochets fonctionne pourxml_grep
etxml_grep2
.//element/@attribute
non//element@attribute
. Je ne peux pas le modifier apparemment, mais le laisser là plutôt que supprimer + remplacer pour ne pas confondre l'historique de cette discussion.//element[@attribute]
sélectionne les éléments de typeelement
qui ont un attributattribute
. Je ne veux pas l'élément, seulement l'attribut.<element attribute='foo'/>
devrait me donnerfoo
, pas le plein<element attribute='foo'/>
.--text_only
dans ce contexte me donne la chaîne vide dans le cas d'un élément comme<element attribute='foo'/>
sans nœud de texte à l'intérieur.Il convient de mentionner que nokogiri lui-même est livré avec un outil de ligne de commande, qui doit être installé avec
gem install nokogiri
.Vous trouverez peut-être ce billet de blog utile .
la source
J'ai essayé quelques utilitaires XPath en ligne de commande et quand j'ai réalisé que je passais trop de temps à chercher sur Google et à comprendre comment ils fonctionnent, j'ai donc écrit l'analyseur XPath le plus simple possible en Python, qui a fait ce dont j'avais besoin.
Le script ci-dessous montre la valeur de la chaîne si l'expression XPath est évaluée comme une chaîne, ou affiche le sous-nœud XML entier si le résultat est un nœud:
#!/usr/bin/env python import sys from lxml import etree tree = etree.parse(sys.argv[1]) xpath = sys.argv[2] for e in tree.xpath(xpath): if isinstance(e, str): print(e) else: print((e.text and e.text.strip()) or etree.tostring(e))
Il utilise
lxml
- un analyseur XML rapide écrit en C qui n'est pas inclus dans la bibliothèque python standard. Installez-le avecpip install lxml
. Sous Linux / OSX, il peut être nécessaire de préfixersudo
.Usage:
python xmlcat.py file.xml "//mynode"
lxml peut également accepter une URL en entrée:
python xmlcat.py http://example.com/file.xml "//mynode"
Extrayez l'attribut url sous un nœud de boîtier, c'est
<enclosure url="http:...""..>)
-à- dire :python xmlcat.py xmlcat.py file.xml "//enclosure/@url"
Xpath dans Google Chrome
En guise de remarque secondaire: si par hasard vous souhaitez exécuter une expression XPath sur le balisage d'une page Web, vous pouvez le faire directement à partir des outils de développement Chrome: cliquez avec le bouton droit sur la page dans Chrome> sélectionnez Inspecter, puis dans les DevTools console collez votre expression XPath comme
$x("//spam/eggs")
.Obtenez tous les auteurs sur cette page:
$x("//*[@class='user-details']/a/text()")
la source
lxml
a déjà été mentionné dans deux autres réponses des années avant la vôtre.Voici un cas d'utilisation de xmlstarlet pour extraire les données des éléments imbriqués elem1, elem2 vers une ligne de texte de ce type de XML (montrant également comment gérer les espaces de noms):
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <mydoctype xmlns="http://xml-namespace-uri" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml-namespace-uri http://xsd-uri" format="20171221A" date="2018-05-15"> <elem1 time="0.586" length="10.586"> <elem2 value="cue-in" type="outro" /> </elem1> </mydoctype>
La sortie sera
0.586 10.586 cue-in outro
Dans cet extrait, -m correspond à l'élem2 imbriqué, -v renvoie les valeurs d'attribut (avec expressions et adressage relatif), -o texte littéral, -n ajoute une nouvelle ligne:
xml sel -N ns="http://xml-namespace-uri" -t -m '//ns:elem1/ns:elem2' \ -v ../@time -o " " -v '../@time + ../@length' -o " " -v @value -o " " -v @type -n file.xml
Si plus d'attributs sont nécessaires à partir de elem1, on peut le faire comme ceci (montrant également la fonction concat ()):
xml sel -N ns="http://xml-namespace-uri" -t -m '//ns:elem1/ns:elem2/..' \ -v 'concat(@time, " ", @time + @length, " ", ns:elem2/@value, " ", ns:elem2/@type)' -n file.xml
Notez la complication (IMO inutile) avec les espaces de noms (ns, déclaré avec -N), qui m'a presque fait abandonner xpath et xmlstarlet, et écrire un rapide convertisseur ad-hoc.
la source
Mon script Python xgrep.py fait exactement cela. Afin de rechercher tous les attributs
attribute
des élémentselement
dans les fichiersfilename.xml ...
, vous l'exécuterez comme suit:xgrep.py "//element/@attribute" filename.xml ...
Il existe différents commutateurs pour contrôler la sortie, par exemple
-c
pour compter les correspondances,-i
pour indenter les parties correspondantes et-l
pour sortir uniquement les noms de fichiers.Le script n'est pas disponible en tant que package Debian ou Ubuntu, mais toutes ses dépendances le sont.
la source
Étant donné que ce projet est apparemment assez nouveau, consultez https://github.com/jeffbr13/xq , semble être un wrapper
lxml
, mais c'est tout ce dont vous avez vraiment besoin (et publié des solutions ad hoc utilisant lxml dans d'autres réponses également)la source
Je n'étais pas satisfait des one-liners Python pour les requêtes HTML XPath, alors j'ai écrit le mien. Suppose que vous avez installé le
python-lxml
package ou exécutépip install --user lxml
:function htmlxpath() { python -c 'for x in __import__("lxml.html").html.fromstring(__import__("sys").stdin.read()).xpath(__import__("sys").argv[1]): print(x)' $1 }
Une fois que vous l'avez, vous pouvez l'utiliser comme dans cet exemple:
> curl -s https://slashdot.org | htmlxpath '//title/text()' Slashdot: News for nerds, stuff that matters
la source
Installez la base de données BaseX , puis utilisez son "mode de ligne de commande autonome" comme ceci:
basex -i - //element@attribute < filename.xml
ou
basex -i filename.xml //element@attribute
Le langage de requête est en fait XQuery (3.0), pas XPath, mais comme XQuery est un sur-ensemble de XPath, vous pouvez utiliser les requêtes XPath sans jamais vous en rendre compte.
la source