シェルからXPathワンライナーを実行する方法は?


192

UbuntuやCentOSのパッケージには、XPathワンライナーを実行できるコマンドラインツールがありますfoo //element@attribute filename.xmlか、またはfoo //element@attribute < filename.xml、結果を行ごとに返しますか?

私はちょうどapt-get install fooまたは私にできるようにする何かを探していますyum install foo、ラッパーやその他の適応が必要ない、そのまま、そのままですぐに機能するます。

近づくものの例をいくつか示します。

のこぎり。このラッパーを作成すると、上記の方法でラッパーを呼び出すことができます。

#!/usr/bin/ruby

require 'nokogiri'

Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
  puts row
end

XML :: XPath。このラッパーで動作します:

#!/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");
}

xpathXMLから:: XPathはあまりにも多くのノイズを返し、-- NODE --そしてattribute = "value"

xml_grep from XML :: Twigは要素を返さない式を処理できないため、それ以上の処理なしに属性値を抽出するために使用することはできません。

編集:

echo cat //element/@attribute | xmllint --shell filename.xml 同様のノイズを返します xpath

xmllint --xpath //element/@attribute filename.xml 戻り値 attribute = "value"

xmllint --xpath 'string(//element/@attribute)' filename.xml 私が欲しいものを返しますが、最初の一致についてのみです。

質問をほぼ満たす別の解決策として、任意のXPath式を評価するために使用できるXSLTを次に示します(XSLTプロセッサーでのdyn:evaluateサポートが必要です)。

<?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="'&#10;'"/>
    </xsl:for-each> 
  </xsl:template>
</xsl:stylesheet>

で実行しxsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xmlます。


良い質問と、複数の結果をそれぞれ改行で出力する簡単で信頼性の高い方法を見つけることに関するブレーンストーミングのための+1
Gilles Quenot

1
からの「ノイズ」xpathはSTDOUTではなくSTDERRにあることに注意してください。
miken32

@ miken32いいえ。出力の値のみが必要でした。hastebin.com/ekarexumeg.bash
2017

回答:


271

これらのツールを試してみてください:

  • xmlstarlet :編集、選択、変換できます...デフォルトではインストールされていません、xpath1
  • xmllint:デフォルトでlibxml2-utils、xpath1 とともにインストールされることが多い(ラッパーを確認して--xpath非常に古いリリースと改行区切りの出力(v <2.9.9)に切り替えるに)
  • xpath :perlのモジュールを介してインストール XML::XPath、xpath1
  • xml_grep:perlのモジュールXML::Twigxpath1 を介してインストール(xpathの使用は制限されています)
  • xidel:xpath3
  • saxon-lint :私自身のプロジェクト、@ Michael KayのSaxon-HE Javaライブラリ、xpath3のラッパー

xmllintが付属していますlibxml2-utils(インタラクティブシェルとして--shellスイッチ)

xmlstarlet です xmlstarlet

xpath perlのモジュールが付属 XML::Xpath

xml_grep perlのモジュールが付属 XML::Twig

xidel です xidel

saxon-lint使用SaxonHE 9.6XPathの3.xの(+レトロな互換性)

例:

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


7
優れた!xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xml私が望むことを正確に行います!
2013年

2
注:xmlstarletは放棄されると噂されていましたが、現在は再び活発な開発が行われています。
2013年

6
注:の一部の古いバージョンはxmllintコマンドライン引数をサポートしていません--xpathが、ほとんどはサポートしているようです--shell。わずかに汚れた出力ですが、バインドでも役立ちます。
kevinarpe

それでも、属性ではなくノードのコンテンツのクエリで問題が発生するようです。誰かがその例を提供できますか?どういうわけか、私はまだxmlstarletを理解し、一致、値、ルートを確認してドキュメント構造を表示するなどを正しく理解するのが難しいと感じていsel -t -m ... -v ...ます。このページの最初の例でも:arstechnica.com/information-technology/2005 / 11 / linuxの-2分の20051115、すべての一致するが、最後のノードと私のユースケースのような値式のための1、私はまだそれを得るように見えることができないことを保存、私は空白の出力を得る...
Pysis

xpathのバージョンで素晴らしいもの-私は、他の点では優れたxmllintのこの制限に
遭遇します

20

また、私のXidelを試すこともできます。リポジトリのパッケージには含まれていませんが、Webページからダウンロードできます(依存関係はありません)。

このタスクの簡単な構文は次のとおりです。

xidel filename.xml -e '//element/@attribute' 

また、XPath 2をサポートするこれらのツールの中でも珍しいツールの1つです。


2
Xidelは見た目はかなりかっこいいですが、このツールの作成者はあなたもお勧めであることをおそらくお伝えしておきます。
FrustratedWithFormsDesigner 2016

1
Saxonおよびsaxon-lintはxpath3を使用します;)
Gilles Quenot

Xidel(0..8.win32.zip)がVirustotalにマルウェアとして表示されます。だから、あなた自身のリスクで試してくださいvirustotal.com/#/file/...
JGFMK

すばらしい-個人用レンチツールボックスにxidelを追加します
maoizm

15

システムにインストールされる可能性が非常に高いパッケージの1つは、python-lxmlです。その場合、追加のパッケージをインストールしなくても可能です。

python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"

1
ファイル名を渡す方法は?
Ramakrishnan Kannan

4
これは上で動作しstdinます。それは含めての必要性がなくなりopen()およびclose()すでにかなり長いワンライナーでは。ファイルを解析するには、実行python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xmlしてシェルにファイルの検索、オープン、クローズを処理させるだけです。
2016

10

maven pom.xmlファイルを照会するための検索では、この質問に遭遇しました。ただし、次の制限がありました。

  • クロスプラットフォームで実行する必要があります。
  • 追加のモジュールをインストールせずに、すべての主要なLinuxディストリビューションに存在する必要があります
  • maven pom.xmlファイルなどの複雑なxmlファイルを処理する必要がある
  • 単純な構文

私は上記の多くを試しましたが成功しませんでした:

  • python lxml.etreeは標準のPythonディストリビューションの一部ではありません
  • xml.etreeは複雑ですが、複雑なmaven pom.xmlファイルを適切に処理しません。十分に掘り下げていません
  • 不明な理由により、python xml.etreeがmaven pom.xmlファイルを処理しない
  • xmllintも機能せず、ubuntu 12.04でコアダンプが頻繁に発生する「xmllint:libxmlバージョン20708を使用する」

私が遭遇した解決策は安定していて短く、多くのプラットフォームで機能し、成熟しているのは、rubyに組み込まれているrexml libです。

ruby -r rexml/document -e 'include REXML; 
     puts XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml

これを見つけようと思ったきっかけは、次の記事でした。


1
それは質問よりもさらに狭い基準なので、間違いなく答えとして適合します。あなたの状況に遭遇した多くの人々があなたの研究によって助けられると私は確信しています。それはxmlstarlet私のより広い基準に適合し、本当にすっきりしているので、私は受け入れられた答えとして保持しています。しかし、私はおそらくあなたの解決策を時々使うでしょう。
クラック

2
私がすることを追加した結果を囲む引用符を避けるため、使用putsの代わりにpRubyのコマンドで。
TomG

10

Saxonは、XPath 2.0だけでなく、XQuery 1.0および(商用バージョンの)3.0でもこれを行います。Linuxパッケージではなく、jarファイルとして提供されます。構文(簡単なスクリプトで簡単にラップできる)は

java net.sf.saxon.Query -s:source.xml -qs://element/attribute

2020年の更新

Saxon 10.0にはGizmoツールが含まれており、コマンドラインからインタラクティブに、またはバッチで使用できます。例えば

java net.sf.saxon.Gizmo -s:source.xml
/>show //element/@attribute
/>quit

SaxonBはUbuntuのパッケージにありますがlibsaxonb-java、実行するsaxonb-xquery -qs://element/@attribute -s:filename.xmlSENR0001: Cannot serialize a free-standing attribute node、たとえばと同じ問題が発生しxml_grepます。
2013年

3
このクエリで選択した属性ノードの詳細をすべて表示するには、コマンドラインで-wrapオプションを使用します。属性の文字列値だけが必要な場合は、クエリに/ string()を追加します。
マイケル・ケイ

ありがとう。/ string()の追加が近づきます。しかし、XMLヘッダーを出力し、すべての結果を1行に配置するため、葉巻はありません。
2013年

2
XMLヘッダーが不要な場合は、オプション!method = textを追加してください。
Michael Kay

使用するようにそれを追加し、名前空間-qs:次のように'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
囲碁

5

xshにも興味があるかもしれません。それはあなたがドキュメントで好きなことをすることができるインタラクティブモードを備えています:

open 1.xml ;
ls //element/@id ;
for //p[@class="first"] echo text() ;

少なくともUbuntuでは、パッケージとして利用できないようです。
2013年

1
@clacke:ありませんが、CPANからでインストールできますcpan XML::XSH2
チョロバ

@ choroba、OS Xで試してみましたが、なんらかのメイクファイルエラーが発生してインストールできませんでした。
cnst

@cnst:XML :: LibXMLがインストールされていますか?
チョロバ2014年

@チョロバ、わからない。でも私のポイントはcpan XML::XSH2何もインストールできないことです。
cnst 2014年

5

clackeの答えは素晴らしいですが、ソースが通常のHTMLではなく整形式のXMLである場合にのみ機能すると思います。

通常のWebコンテンツに対して同じことを行うには、必ずしも整形式のXMLである必要はないHTMLドキュメント:

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'))"

また、代わりにhtml5libを使用します(ブラウザーのパーサーと同様に、html5libは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'))

はい、私は質問で私自身の仮定に落ちました、XPathはXMLを暗示するということです。この回答は、他の回答を補完するものであり、html5libについて教えてくれてありがとう!
2016

3

Mikeとclackeの答えと同様に、pom.xmlファイルに通常dtdまたはデフォルトの名前空間なので、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)"

MacとLinuxでテストされており、追加のパッケージをインストールする必要はありません。


2
今日使ったよ!私たちのビルドサーバーには、Ruby lxmlxmllint、Ruby もありませんでした。私自身の回答のフォーマットの精神で、私はpython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"bashのようにそれを書きました。.getroot()必要ないようです。
18年

2

加えて、XML :: XSHXML :: XSH2いくつか存在するgrep様ユーティリティはとして吸うApp::xml_grep2XML::Twig(含むxml_grepのではなくxml_grep2)。これらは、迅速なワンライナーまたはMakefileターゲット用の大きなまたは多数のXMLファイルで作業する場合に非常に役立ちます。 and オファーよりも処理を少し増やしたい場合XML::Twigは、perlスクリプトアプローチで作業すると特に便利です。$SHELLxmllint xstlproc

アプリケーション名の番号付けスキームは、「2」バージョンが他のモジュール(またはperlそれ自体)の新しいバージョンを必要とする可能性がある基本的に同じツールの新しいバージョンまたは新しいバージョンであることを示しています。


xml_grep2 -t //element@attribute filename.xml動作し、期待どおりに動作します(xml_grep --root //element@attribute --text_only filename.xmlまだ動作しませんが、「認識されない式」エラーを返します)。すごい!
2014年

どうxml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xmlですか?わからない何が起こっているのか、どのようなXPathはについて言う[]このケースではなく、周囲の @attribute角括弧では、のために働くxml_grepxml_grep2
G. Cito 2014年

つまり//element/@attributeじゃない//element@attribute。どうやらそれを編集することはできませんが、このディスカッションの履歴を混乱させないために、削除+置換ではなく、そのままにしてください。
2014年

//element[@attribute]element属性を持つタイプの要素を選択しますattribute。要素は必要ありません。属性だけが必要です。完全ではなく、<element attribute='foo'/>fooに与えるべきです<element attribute='foo'/>
2014年

...そして--text_only、そのコンテキストでは<element attribute='foo'/>、テキストノードが含まれていないような要素の場合、空の文字列が返されます。
2014年


2

私はいくつかのコマンドラインXPathユーティリティを試してみましたが、グーグルに費やして、それらがどのように機能するかを理解するのに時間がかかりすぎていることに気付いたので、Pythonで必要なことを行う最も単純なXPathパーサーを作成しました。

以下のスクリプトは、XPath式が文字列に評価される場合は文字列値を示し、結果がノードの場合はXMLサブノード全体を示します。

#!/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))

それは使用しますlxml—標準のPythonライブラリに含まれていないCで書かれた高速XMLパーサー。でインストールしpip install lxmlます。Linux / OSXでは、接頭辞が必要になる場合がありますsudoます。

使用法:

python xmlcat.py file.xml "//mynode"

lxmlは、URLを入力として受け入れることもできます。

python xmlcat.py http://example.com/file.xml "//mynode" 

エンクロージャノードの下のurl属性を抽出します<enclosure url="http:...""..>)

python xmlcat.py xmlcat.py file.xml "//enclosure/@url"

Google ChromeのXpath

無関係な補足として:偶然にもWebページのマークアップに対してXPath式を実行したい場合は、Chrome devtoolsから直接実行できます。Chromeでページを右クリックし、[Inspect]を選択してから、DevToolsでXPath式をコンソールに貼り付けます $x("//spam/eggs")

このページのすべての著者を取得します。

$x("//*[@class='user-details']/a/text()")

ワンライナーではなく、あなたの回答より何年も前lxmlにすでに他の2つ回答で言及されていました。
18年

2

このタイプのXMLからネストされた要素elem1、elem2からテキストの1行にデータを抽出するxmlstarletの使用例を1つ示します(名前空間の処理方法も示しています)。

<?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>

出力は

0.586 10.586 cue-in outro

このスニペットでは、-mはネストされたelem2に一致し、-vは属性値(式と相対アドレッシングを含む)を出力し、-oリテラルテキスト、-nは改行を追加します。

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

elem1からさらに属性が必要な場合は、次のように実行できます(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

名前空間(ns、-Nで宣言)の(IMO不要)複雑化に注意してください。これにより、xpathとxmlstarletをほとんどあきらめ、簡単なアドホックコンバーターを作成しました。


xmlstarletはすばらしいですが、受け入れられたメインランキングの回答にはすでに言及されています。名前空間の処理方法に関する情報は、もしあれば、コメントとして関連している可能性があります。名前空間とxmlstarletの問題に実行している誰もが優れた見つけることができるドキュメントの議論
clacke

2
確かに、@ clacke、xmlstarletは何度か言及されていますが、把握するのが難しく、文書化も不十分です。ネストされた要素から情報を取得する方法を1時間ぐらい推測していました。私はその例があればよかったので、他の人が時間を無駄にしないようにここに投稿しています(そして、例がコメントには長すぎます)。
diemo

2

私のPythonスクリプトxgrep.pyはまさにこれを行います。ファイル内attributeの要素のすべての属性を検索するには、次のように実行します。elementfilename.xml ...

xgrep.py "//element/@attribute" filename.xml ...

-c一致のカウント-i、一致するパーツのインデントなど、出力を制御するためのさまざまなスイッチがあります。-lファイル名のみの出力ます。

スクリプトはDebianまたはUbuntuパッケージとしては入手できませんが、その依存関係はすべて入手できます。


そして、あなたはsourcehutでホスティングしています!いいね!
clacke


1

HTML XPathクエリ用のPythonワンライナーに満足できなかったので、自分で作成しました。python-lxmlパッケージをインストールまたは実行したと仮定します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 }

取得したら、次の例のように使用できます。

> curl -s https://slashdot.org | htmlxpath '//title/text()'
Slashdot: News for nerds, stuff that matters

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.