Gibt es ein Paket für Ubuntu und/oder CentOS, das ein Befehlszeilentool enthält, das einen XPath-Einzeiler wie foo //[email protected] filename.xml
oder foo //[email protected] < filename.xml
ausführen und die Ergebnisse Zeile für Zeile zurückgeben kann?
Ich bin auf der Suche nach etwas, das mir erlaubt, nur apt-get install foo
oder yum install foo
zu verwenden, und dann funktioniert es sofort, es sind keine Wrapper oder andere Anpassungen erforderlich.
Hier einige Beispiele von Dingen, die nahe kommen:
Nokogiri Wenn ich diesen Wrapper schreibe, könnte ich den Wrapper auf die oben beschriebene Weise aufrufen:
#!/usr/bin/Ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML :: XPath. Würde mit diesem Wrapper funktionieren:
#!/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
aus XML :: XPath liefert zu viel Rauschen, -- NODE --
und attribute = "value"
.
xml_grep
aus XML :: Twig kann keine Ausdrücke verarbeiten, die keine Elemente zurückgeben. Daher können Attributwerte nicht ohne weitere Verarbeitung extrahiert werden.
BEARBEITEN:
echo cat //element/@attribute | xmllint --Shell filename.xml
liefert ein ähnliches Rauschen wie xpath
.
xmllint --xpath //element/@attribute filename.xml
gibt attribute = "value"
zurück.
xmllint --xpath 'string(//element/@attribute)' filename.xml
gibt zurück, was ich will, aber nur für den ersten Treffer.
Für eine andere Lösung, die die Frage beinahe erfüllt, gibt es hier ein XSLT, mit dem beliebige XPath-Ausdrücke ausgewertet werden können (erfordert Dyn: Evaluierungsunterstützung im XSLT-Prozessor):
<?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>
Führen Sie mit xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
aus.
Sie sollten diese Tools ausprobieren:
xmlstarlet
: kann bearbeiten, auswählen, transformieren ... Standardmäßig nicht installiert, xpath1xmllint
: wird häufig standardmäßig mit libxml2
, xpath1 installiert (aktivieren Sie mein wrapper , um die Ausgabe durch Zeilenumbrüche zu begrenzenxpath
: installiert über das Perl-Modul XML::XPath
, xpath1xml_grep
: wird über das Perl-Modul XML::Twig
, xpath1 (eingeschränkte Xpath-Nutzung) installiertxidel
: xpath3saxon-lint
: mein eigenes Projekt, Wrapper über die Saxon-HE-Java-Bibliothek von @Michael Kay, xpath3xmllint
wird mit libxml2-utils
geliefert (kann als interaktive Shell mit dem --Shell
-Schalter verwendet werden)
xmlstarlet
ist xmlstarlet
.
xpath
wird mit Perls Modul XML::Xpath
ausgeliefert
xml_grep
wird mit Perls Modul XML::Twig
geliefert.
xidel
ist xidel
saxon-lint
mit SaxonHE 9.6 , XPath 3.x (+ Retro-Kompatibilität)
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
.
Sie können auch meine Xidel ausprobieren. Es befindet sich nicht in einem Paket im Repository, aber Sie können es einfach von der Webseite herunterladen (es hat keine Abhängigkeiten).
Es hat eine einfache Syntax für diese Aufgabe:
xidel filename.xml -e '//element/@attribute'
Und es ist eines der wenigen dieser Tools, das XPath 2 unterstützt.
Ein Paket, das sehr wahrscheinlich bereits auf einem System installiert wird, ist python-lxml
. Wenn ja, ist dies ohne Installation eines zusätzlichen Pakets möglich:
python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"
Saxon macht dies nicht nur für XPath 2.0, sondern auch für XQuery 1.0 und (in der kommerziellen Version) 3.0. Es kommt nicht als Linux-Paket, sondern als JAR-Datei. Syntax (die Sie leicht in ein einfaches Skript einwickeln können) ist
Java net.sf.saxon.Query -s:source.xml -qs://element/attribute
Bei meiner Suche nach maven pom.xml-Dateien habe ich diese Frage ausgeführt. Ich hatte jedoch die folgenden Einschränkungen:
Ich habe viele davon ohne Erfolg ausprobiert:
Die einzige Lösung, die ich gefunden habe, ist stabil, kurz und funktioniert auf vielen Plattformen, und sie ist ausgereift, ist die in Ruby integrierte rexml-Bibliothek:
Ruby -r rexml/document -e 'include REXML;
p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
Was mich dazu inspiriert hat, waren folgende Artikel:
Vielleicht interessieren Sie sich auch für xsh . Es verfügt über einen interaktiven Modus, in dem Sie mit dem Dokument alles tun können, was Sie möchten:
open 1.xml ;
ls //element/@id ;
for //p[@class="first"] echo text() ;
Antwort von clacke ist großartig, aber ich denke, es funktioniert nur, wenn Ihre Quelle aus wohlgeformtem XML und nicht aus normalem HTML besteht.
So machen Sie dasselbe für normale Webinhalte: HTML-Dokumente, die nicht notwendigerweise wohlgeformtes XML sind:
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'))"
Verwenden Sie stattdessen html5lib (um sicherzustellen, dass Sie dasselbe Parsing-Verhalten wie Webbrowser erhalten. Da html5lib wie Browser-Parser den Parser-Anforderungen in der HTML-Spezifikation entspricht).
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'))
Zusätzlich zu XML :: XSH und XML :: XSH2 gibt es einige grep
-ähnliche Hilfsprogramme wie App::xml_grep2
und XML::Twig
(die xml_grep
statt xml_grep2
enthalten). Dies kann sehr nützlich sein, wenn Sie an großen oder zahlreichen XML-Dateien für schnelle Oneliner oder Makefile
-Ziele arbeiten. XML::Twig
ist besonders nett, wenn Sie für einen Perl
-Skriptansatz arbeiten möchten, wenn Sie ein wenig mehr Verarbeitungsaufwand wünschen als Ihr $Shell
- und xmllint
xstlproc
-Angebot.
Das Nummerierungsschema in den Anwendungsnamen gibt an, dass es sich bei den "2" -Versionen um neuere/spätere Versionen von im Wesentlichen demselben Tool handelt, für die möglicherweise spätere Versionen anderer Module (oder von Perl
selbst) erforderlich sind.
Ähnlich wie Mikes und Clackes Antworten gibt es hier den Python-Einzeiler (mit Python> = 2.5), um die Build-Version aus einer pom.xml-Datei abzurufen, die die Tatsache umgeht, dass pom.xml-Dateien normalerweise keine Dateisysteme haben Standard-Namespace, erscheinen Sie also in libxml nicht wohlgeformt:
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)"
Getestet unter Mac und Linux und erfordert keine zusätzlichen Pakete zur Installation.
Es ist zu erwähnen, dass nokogiri selbst ein Befehlszeilentool enthält, das mit gem install nokogiri
installiert werden sollte.
Mein Python Skript xgrep.py macht genau das. Um nach allen Attributen attribute
von Elementen element
in Dateien filename.xml ...
zu suchen, würden Sie es wie folgt ausführen:
xgrep.py "//element/@attribute" filename.xml ...
Es gibt verschiedene Schalter zur Steuerung der Ausgabe, z. B. -c
zum Zählen von Übereinstimmungen, -i
zum Einrücken der übereinstimmenden Teile und -l
nur zum Ausgeben von Dateinamen.
Das Skript ist nicht als Debian- oder Ubuntu-Paket verfügbar, aber alle Abhängigkeiten sind vorhanden.
Ich habe ein paar Befehlszeilen-XPath-Hilfsprogramme ausprobiert, und als ich merkte, dass ich zu viel Zeit damit verbringe, zu googeln und herauszufinden, wie sie funktionieren, schrieb ich den einfachsten XPath-Parser in Python, der das tat, was ich brauchte.
Das folgende Skript zeigt den Zeichenfolgewert, wenn der XPath-Ausdruck zu einer Zeichenfolge ausgewertet wird, oder zeigt den gesamten XML-Unterknoten, wenn das Ergebnis ein Knoten ist:
#!/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))
Es verwendet lxml
- einen schnellen, in C geschriebenen XML-Parser, der nicht in der Standard-Python-Bibliothek enthalten ist. Installieren Sie es mit pip install lxml
. Unter Linux/OSX muss möglicherweise Sudo
vorangestellt werden.
Verwendungszweck:
python xmlcat.py file.xml "//mynode"
lxml kann auch eine URL als Eingabe akzeptieren:
python xmlcat.py http://example.com/file.xml "//mynode"
Extrahieren Sie das URL-Attribut unter einem Enclosure-Knoten, d. H. <Enclosure url="http:...""..>)
:
python xmlcat.py xmlcat.py file.xml "//Enclosure/@url"
Nicht nebenstehende Anmerkung: Wenn Sie zufällig einen XPath-Ausdruck gegen das Markup einer Webseite ausführen möchten, können Sie dies direkt von Chrome devtools aus tun: Klicken Sie mit der rechten Maustaste auf die Seite in Chrome> wählen Sie Inspect und dann in den DevTools Console Fügen Sie Ihren XPath-Ausdruck als $x("//spam/eggs")
ein.
Holen Sie sich alle Autoren auf dieser Seite:
$x("//*[@class='user-details']/a/text()")
Da dieses Projekt anscheinend ziemlich neu ist, checken Sie aus https://github.com/jeffbr13/xq , es scheint ein Wrapper um lxml
zu sein, aber das ist alles, was Sie wirklich brauchen (und Ad-hoc-Lösungen mit Lxml in auch andere Antworten)
Hier ist ein xmlstarlet-Anwendungsfall zum Extrahieren von Daten aus geschachtelten Elementen elem1, elem2 in eine Textzeile aus diesem XML-Typ (der auch zeigt, wie Namespaces behandelt werden):
<?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>
Die Ausgabe wird sein
0.586 10.586 cue-in outro
In diesem Snippet entspricht -m dem verschachtelten Element elem2, -v gibt Attributwerte aus (mit Ausdrücken und relativer Adressierung), -o wörtlicher Text, -n fügt eine neue Zeile hinzu:
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
Wenn mehr Attribute von elem1 benötigt werden, kann man dies folgendermaßen tun (auch die concat () - Funktion wird angezeigt):
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
Beachten Sie die (IMO unnötige) Komplikation mit Namespaces (ns, die mit -N deklariert wurden), bei der ich fast auf xpath und xmlstarlet verzichten und einen schnellen Ad-hoc-Konverter schreiben musste.