web-dev-qa-db-ja.com

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

UbuntuやCentOS向けに、foo //element@attribute filename.xmlfoo //element@attribute < filename.xmlなどのXPathワンライナーを実行し、結果を1行ずつ返すことができるコマンドラインツールを備えたパッケージがありますか?

私はちょうど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");
}

XML :: XPathからのxpathは、-- NODE --およびattribute = "value"という非常に多くのノイズを返します。

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

編集:

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

xmllint --xpath //element/@attribute filename.xmlattribute = "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で実行します。

173
clacke

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

  • xmlstarlet:編集、選択、変換できます...デフォルトではインストールされません、xpath1
  • xmllint:多くの場合、デフォルトでlibxml2、xpath1とともにインストールされます(改行を区切るには wrapper をチェックしてください)
  • xpath:PerlのモジュールXML::XPath、xpath1を介してインストールされます
  • xml_grep:PerlのモジュールXML::Twig、xpath1(xpathの使用制限)を介してインストールされます
  • xidel:xpath3
  • saxon-lint:私自身のプロジェクト、@ Michael KayのSaxon-HE Javaライブラリ、xpath3のラッパー

xmllintにはlibxml2-utilsが付属しています(--Shellスイッチを使用して対話型シェルとして使用できます)

xmlstarletxmlstarletです。

xpathにはPerlのモジュールが付属しています XML::Xpath

xml_grepにはPerlのモジュールが付属しています XML::Twig

xidelxidelです

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

235
Gilles Quenot

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

このタスクの単純な構文があります。

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

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

18
BeniBela

システムに既にインストールされている可能性が非常に高いパッケージの1つはpython-lxmlです。その場合、追加のパッケージをインストールせずにこれを実行できます。

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

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; 
     p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml

これを見つけるきっかけになったのは、次の記事です。

10
Mike

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

Java net.sf.saxon.Query -s:source.xml -qs://element/attribute
10
Michael Kay

xsh にも興味があるかもしれません。それはあなたが文書であなたが好きなことをすることができるインタラクティブなモードを特徴とします:

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

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を使用するには(Webブラウザーと同じ解析動作を確保するために-ブラウザーパーサーのように、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'))
4
sideshowbarker

Mikeとclackeの答えと同様に、pom.xmlファイルには通常dtdが含まれていないという事実を回避するpom.xmlファイルからビルドバージョンを取得するためのPythonワンライナー(python> = 2.5を使用)があります。デフォルトの名前空間なので、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でテストされており、追加のパッケージをインストールする必要はありません。

3
pdr

XML :: XSH および XML :: XSH2 に加えてgrepのようなユーティリティは、 App::xml_grep2 および XML::Twigxml_grepを含む) xml_grep2ではなく)。これらは、迅速なonelinersまたはMakefileターゲットの大規模または多数のXMLファイルで作業する場合に非常に役立ちます。 XML::Twigは、$ShellPerlxmllintのオファーよりも少し処理をしたい場合に、xstlprocのスクリプティングアプローチに特に適しています。

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

2
G. Cito

Nokogiri自体にはコマンドラインツールが付属しており、gem install nokogiriとともにインストールする必要があることに言及する必要があります。

このブログ投稿が便利 を見つけるかもしれません。

2
Geoff Nixon

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

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

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

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

1
Andreas Nolda

私はいくつかのコマンドラインXPathユーティリティを試しましたが、グーグルとそれらの動作を理解するのに時間がかかりすぎることに気付いたので、私は必要なことをした最も簡単なXPathパーサーをPythonで書きました。

以下のスクリプトは、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" 

Enclosureノードの下の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()")
1
ccpizza

このプロジェクトは明らかにかなり新しいので、 https://github.com/jeffbr13/xq をチェックしてください。これはlxmlのラッパーのようですが、本当に必要なのはそれだけです(アドホックソリューションを投稿しました)他の回答でもlxmlを使用してください)

1
mgrandi

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

<?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をほとんどあきらめ、簡単なアドホックコンバーターを作成しました。

0
diemo