Existe-t-il un paquet, pour Ubuntu et/ou CentOS, qui possède un outil de ligne de commande pouvant exécuter une ligne unique XPath telle que foo //element@attribute filename.xml
ou foo //element@attribute < filename.xml
et renvoyer les résultats ligne par ligne?
Je cherche quelque chose qui me permettrait de simplement apt-get install foo
ou yum install foo
et que cela fonctionne ensuite immédiatement, sans emballage ni autre adaptation nécessaire.
Voici quelques exemples de choses qui se rapprochent:
Nokogiri. Si j'écris ce wrapper, je pourrais l'appeler 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
from 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é pour extraire des valeurs d'attribut sans traitement supplémentaire.
MODIFIER:
echo cat //element/@attribute | xmllint --Shell filename.xml
renvoie un bruit similaire à xpath
.
xmllint --xpath //element/@attribute filename.xml
renvoie attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
renvoie ce que je veux, mais uniquement pour le premier match.
Pour une autre solution répondant presque à la question, voici un XSLT qui peut être utilisé pour évaluer des expressions XPath arbitraires (requiert la prise en charge de dyn: evalu 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>
Exécuter avec xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
Vous devriez essayer ces outils:
xmlstarlet
: peut éditer, sélectionner, transformer ... Non installé par défaut, xpath1xmllint
: souvent installé par défaut avec libxml2
, xpath1 (vérifiez mon wrapper pour avoir une sortie délimitée par des nouvelles lignesxpath
: installé via le module Perl XML::XPath
, xpath1xml_grep
: installé via le module Perl XML::Twig
, xpath1 (utilisation limitée de xpath)xidel
: xpath3saxon-lint
: mon propre projet, enveloppe sur la bibliothèque Java Saxon-HE de Michael Kay, xpath3xmllint
est livré avec libxml2-utils
(peut être utilisé en tant que shell interactif avec le commutateur --Shell
)
xmlstarlet
est xmlstarlet
.
xpath
est livré avec le module Perl XML::Xpath
xml_grep
est livré avec le module Perl XML::Twig
xidel
est xidel
saxon-lint
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
.
Vous pouvez aussi essayer mon Xidel . Il ne fait pas partie d'un paquet 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 outils prenant en charge XPath 2.
python-lxml
est un paquet qui est très probablement installé sur un système. Si c'est le cas, cela est possible sans installer de paquet supplémentaire:
python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"
Saxon le fera non seulement pour XPath 2.0, mais également pour XQuery 1.0 et (dans la version commerciale) 3.0. Cela ne vient pas comme un paquet Linux, mais comme un fichier jar. La syntaxe (que vous pouvez facilement envelopper dans un script simple) est
Java net.sf.saxon.Query -s:source.xml -qs://element/attribute
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 seule solution que j'ai trouvée qui soit stable, courte et fonctionne sur de nombreuses plates-formes et qui est mature est la librairie rexml intégrée dans Ruby:
Ruby -r rexml/document -e 'include REXML;
p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
Ce qui m'a inspiré pour trouver celui-ci était les articles suivants:
Vous pourriez aussi être intéressé par xsh . Il comporte 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 réponse de clacke est excellente, mais je pense que cela ne fonctionne que si votre source est un XML bien formé, pas du HTML normal.
Il en va de même pour le contenu Web normal - les documents HTML qui ne sont pas nécessairement bien formés en XML:
echo "<p>foo<div>bar</div><p>baz" | python -c "from sys import stdin; \
from lxml import html; \
print '\n'.join(html.tostring(node) for node in html.parse(stdin).xpath('//p'))"
Et d'utiliser plutôt html5lib (pour vous assurer d'obtenir le même comportement d'analyse que les navigateurs Web car, tout comme les analyseurs syntaxiques de navigateur, html5lib est conforme aux exigences d'analyse de la spécification HTML).
echo "<p>foo<div>bar</div><p>baz" | python -c "from sys import stdin; \
import html5lib; from lxml import html; \
doc = html5lib.parse(stdin, treebuilder='lxml', namespaceHTMLElements=False); \
print '\n'.join(html.tostring(node) for node in doc.xpath('//p'))
En plus de XML :: XSH et XML :: XSH2 , il existe des utilitaires de type grep
- ressemblant à App::xml_grep2
et XML::Twig
(qui inclut xml_grep
plutôt que xml_grep2
). Celles-ci peuvent être très utiles lorsque vous travaillez sur un fichier XML volumineux ou sur de nombreux fichiers XML pour obtenir des résultats rapides ou des cibles Makefile
. XML::Twig
est particulièrement agréable à utiliser avec une approche de script Perl
lorsque vous souhaitez un peu plus de traitement que vos offres $Shell
et xmllint
xstlproc
.
Le schéma de numérotation dans les noms d'applications indique que les versions "2" sont des versions plus récentes/ultérieures du même outil, ce qui peut nécessiter des versions ultérieures d'autres modules (ou de Perl
elle-même).
Semblable aux réponses de Mike et de Clacke, voici la ligne de texte python one-liner (utilisant python> = 2.5) pour obtenir la version de construction à partir d’un fichier pom.xml qui évite le fait que les fichiers pom.xml n’ont normalement pas de dtd ou namespace par défaut, donc ne semblez pas bien formé pour 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 paquet supplémentaire.
Il convient de mentionner que nokogiri est livré avec un outil de ligne de commande, qui devrait être installé avec gem install nokogiri
.
Vous pourriez trouver ce billet de blog utile .
Mon Python script xgrep.py fait exactement cela. Pour rechercher tous les attributs attribute
des éléments element
dans les fichiers filename.xml ...
, vous devez l'exécuter comme suit:
xgrep.py "//element/@attribute" filename.xml ...
Il existe différents commutateurs pour contrôler la sortie, tels que -c
pour compter les correspondances, -i
pour indenter les parties correspondantes et -l
pour ne fournir que les noms de fichiers.
Le script n'est pas disponible en tant que paquet Debian ou Ubuntu, mais toutes ses dépendances le sont.
J'ai essayé quelques utilitaires XPath en ligne de commande et quand j'ai réalisé que je passais trop de temps à googler et à comprendre comment ils fonctionnaient, 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 chaîne si l'expression XPath est évaluée à une chaîne ou affiche le sous-noeud XML complet 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 standard Python. Installez-le avec pip install lxml
. Sous Linux/OSX, il peut être nécessaire de préfixer Sudo
.
Usage:
python xmlcat.py file.xml "//mynode"
lxml peut également accepter une URL en tant qu'entrée:
python xmlcat.py http://example.com/file.xml "//mynode"
Extrayez l’attribut url sous un nœud de boîtier, c.-à-d. <Enclosure url="http:...""..>)
:
python xmlcat.py xmlcat.py file.xml "//Enclosure/@url"
Remarque secondaire non liée: Si, par hasard, vous souhaitez exécuter une expression XPath par rapport au balisage d’une page Web, vous pouvez le faire directement à partir de Chrome devtools: faites un clic droit sur la page dans Chrome> sélectionnez Inspecter, puis dans DevTools console collez votre expression XPath sous la forme $x("//spam/eggs")
.
Obtenez tous les auteurs sur cette page:
$x("//*[@class='user-details']/a/text()")
Comme ce projet est apparemment relativement nouveau, consultez https://github.com/jeffbr13/xq , semble être un wrapper autour de lxml
, mais c’est tout ce dont vous avez besoin d'autres réponses aussi)
Voici un cas d'utilisation xmlstarlet pour extraire des données d'éléments imbriqués elem1, elem2 sur une ligne de texte à partir 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'elem2 imbriqué, -v fournit les valeurs d'attribut (avec les expressions et l'adressage relatif), -o le 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 vous avez besoin de plus d'attributs de elem1, vous pouvez 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 (OMI inutile) avec les espaces de noms (ns, déclarés avec -N), qui m'a fait presque renoncer à xpath et xmlstarlet et à l'écriture d'un convertisseur ad-hoc rapide.