XMLStarlet入門

コマンド・ラインからXMLを使えるオープン・ソース・ツールキット

XMLStarletコマンド・ライン・ユーティリティーで簡単なコマンドを使ってXMLの書式化、変換、修正、および編集を行う方法を学びます。Jack Herringtonが、このパワフルなツールの導入がいかに簡単で、作業をいかに単純化するかを説明します。

Jack Herrington (jherr@pobox.com), Editor-in-Chief, Code Generation Network

Jack D. Herringtonは、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。著者には、「Code Generation in Action」、「Podcasting Hacks」、そして近々刊行予定の「PHP Hacks」の3冊があります。彼は30本以上の技術記事も執筆しています。



2005年 6月 10日

XMLStarletは、UNIX®、Mac OS® X、またはMicrosoft® Windows®コマンド・ラインで使用できるオープン・ソースのXMLツールキットです。XMLStarletを使用して、XMLの検証、書式化、部分選択、XSLTでの変換を行うことができ、編集もできます。つまり、PerlやJava®のようなプログラミング言語でカスタム・コードを書かなくても、XMLユーティリティーをシェル・スクリプトに入れることができます。

XMLStarletを使用するには、インストールする必要があります。しかし、そのためには、libxml2およびlibxslt2ライブラリーが必要です。Windowsでは、libxml2とlibxslt2をインストールする必要はありません。Win32パッケージに含まれています。コマンド・ラインから簡単に実行できるように、Win32実行ファイルをダウンロードして、パス上のどこかにインストールすることができます。UNIXを実行していて、マシンにlibxml2とlibxslt2がまだインストールされていない場合は、ダウンロードしてインストールする必要があります(参考文献を参照)。

次に、XMLStarletホーム・ページに行き、最新のビルドをダウンロードします(参考文献を参照)。ビルド・スクリプトをセットアップするには、./configureスクリプトを実行します。次に、make installを実行して、パッケージをビルドし、インストールします。スーパー・ユーザーでない場合は、コマンドがシステム・ディレクトリーにインストールされるように、sudo make installを使用する必要があります。

XML、XSLT、およびXML Path Language(XPath)のページに行き、この3つの標準の最新情報もチェックした方がよいかもしれません。これらはXMLStarletの活用に不可欠です(参考文献を参照)。

基本

インストールが済んだら、XMLStarletのファイルを見てみましょう。まず、xmlコマンドを単独で実行してください(リスト1)。

リスト1. XMLStarletヘルプ・ページ
% xml
XMLStarlet Toolkit: command-line utilities for XML
Usage: xml [<options>] <command> [<cmd-options>]
where <command> is one of:
ed    (or edit)      - Edit/Update XML document(s)
sel   (or select)    - Select data or query XML document(s) (XPATH, etc)
tr    (or transform) - Transform XML document(s) using XSLT
val   (or validate)  - Validate XML document(s) (well-formed/DTD/XSD/RelaxNG)
fo    (or format)    - Format XML document(s)
el    (or elements)  - Display element structure of XML document
c14n  (or canonic)   - XML canonicalization
ls    (or list)      - List directory as XML
esc   (or escape)    - Escape special XML characters
unesc (or unescape)  - Unescape special XML characters
pyx   (or xmln)      - Convert XML into PYX format (based on ESIS - ISO 8879)
p2x   (or depyx)     - Convert PYX into XML
<options> are:
--version            - show version
--help  - show help
Wherever file name mentioned in command help it is assumed
that URL can be used instead as well.

Type: xml <command> --help <ENTER> for command help

XMLStarlet is a command line toolkit to query/edit/check/transform
XML documents (for more information see http://xmlstar.sourceforge.net/)

各コマンドの基本的な形式はxml<command>であり、その後にオプションを続けます。各オプションのヘルプを表示するには、xml<command>--helpと入力するだけです。たとえば、リスト2は、編集(ed)コマンドのヘルプを示しています。

リスト2. 編集コマンドのヘルプ
% xml ed --help
XMLStarlet Toolkit: Edit XML document(s)
Usage: xml ed <global-options> {<action>} [ <xml-file-or-uri> ... ]
where
<global-options>  - global options for editing
<xml-file-or-uri> - input XML document file name/uri (stdin otherwise)

<global-options> are:
-P (or --pf)        - preserve original formatting
-S (or --ps)        - preserve non-significant spaces
-O (or --omit-decl) - omit XML declaration (<?xml ...?>)
-N <name>=<value>   - predefine namespaces (name without 'xmlns:')
ex: xsql=urn:oracle-xsql
Multiple -N options are allowed.
-N options must be last global options.
--help or -h        - display help

where <action>
-d or --delete <xpath>
-i or --insert <xpath> -t (--type) elem|text|attr -n <name> -v (--value) <value>
-a or --append <xpath> -t (--type) elem|text|attr -n <name> -v (--value) <value>
-s or --subnode <xpath> -t (--type) elem|text|attr -n <name> -v (--value) <value>
-m or --move <xpath1> <xpath2>
-r or --rename <xpath1> -v <new-name>
-u or --update <xpath> -v (--value) <value>
-x (--expr) <xpath> (-x is not implemented yet)

XMLStarlet is a command line toolkit to query/edit/check/transform
XML documents (for more information see http://xmlstar.sourceforge.net/)

このヘルプは複雑に見えるかもしれませんが、重要なのは、一番後にあります。そこには、XMLノードの削除、挿入、値の変更などの方法が示されています。


XMLディレクトリー・リスト

長いコード行

この記事のコード行の中には、切り詰めないとウィンドウに収まらない長いコード行がいくつかあります。このような行は、コード・リストでは折り返されていますが、実際のコマンド・ラインでは1行で表示されます。このような行には、>>記号が付けてあります(たとえば、リスト3を参照)。

XMLStarletで遊ぶには、XMLが必要です。これによって、最初のコマンドxml lsが使えるようになり、XMLのカレント・ディレクトリーのリストを表示できます。リスト3に例を示します。

リスト3. XMLのディレクトリー・リスト
% xml ls
<xml>
<d p="rwxr-xr-x" a="2005.05.04 23:03:46" 
» m="2004.03.24 16:21:02" s="374" n="."/>
<d p="rwxr-xr-x" a="2005.05.04 23:03:46" 
» m="2005.05.04 22:13:41" s="1938"n=".."/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 01:13:43" s="6148"n=".DS_Store"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:41:46" s="173" n="build.xml"/>
<d p="rwxr-xr-x" a="2005.04.30 11:34:27" 
» m="2004.03.24 01:13:43" s="544" n="docs"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.21 18:41:58" s="641" n="input.xml"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.23 23:41:15" s="3587"n="main.xsl"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:37:10" s="184" n="Makefile"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:36:41" s="3869"n="MyGenerator.class"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:36:33" s="5265"n="MyGenerator.java"/>
<d p="rwxr-xr-x" a="2005.04.30 11:34:25" 
» m="2004.03.24 00:20:07" s="272" n="output"/>
</xml>

このディレクトリー・リストに表示される情報が多すぎると思うかもしれません。その場合は、たとえばリスト4に示されているように、ディレクトリー・ノードを削除することができます。

リスト4. ディレクトリー・ノードのないディレクトリー・リスト
% xml ls | xml ed -d "//d"
<?xml version="1.0"?>
<xml>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 01:13:43" s="6148" n=".DS_Store"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:41:46" s="173" n="build.xml"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.21 18:41:58" s="641" n="input.xml"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.23 23:41:15" s="3587" n="main.xsl"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:37:10" s="184" n="Makefile"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:36:41" s="3869" n="MyGenerator.class"/>
<f p="rw-r--r--" a="2005.03.24 17:53:52" 
» m="2004.03.24 00:36:33" s="5265" n="MyGenerator.java"/>
</xml>

編集(ed)コマンドを使用して、XMLからdノードを削除することができます。lsコマンドは、ディレクトリーを標準出力に出力します。次に、パイプ(|)が標準出力を編集コマンドの標準入力にリダイレクトして、編集コマンドがリストからdノードを削除します。dノードを指定するには、XPath式//dを使います。これは、ツリー内の任意のレベルのdノードにマッチします。/xml/dを使用すると、このコマンドをさらに具体的にできます。

今度はaおよびm属性を削除したいとします(リスト5)。

リスト5. aおよびm属性のないディレクトリー・リスト
% xml ls | xml ed -d "//d" -d "//@a" -d "//@m" -d "//@p"
<?xml version="1.0"?>
<xml>
<f s="6148" n=".DS_Store"/>
<f s="173" n="build.xml"/>
<f s="641" n="input.xml"/>
<f s="3587" n="main.xsl"/>
<f s="184" n="Makefile"/>
<f s="3869" n="MyGenerator.class"/>
<f s="5265" n="MyGenerator.java"/>
</xml>

この方が実用的です。ファイルだけのリストになり、ファイル・ノード内のファイルのサイズと名前だけが表示されています。表示を調べやすくするために、ls.xmlという名前のファイルに結果を保存することができます。また、rename編集関数を使用して、fタグをfileに変更することもできます(リスト6)。

リスト6. サイズおよび名前属性の付いたディレクトリー・リスト
% cat ls.xml | xml ed -r "//f" -v "file"
<?xml version="1.0"?>
<xml>
<file s="6148" n=".DS_Store"/>
<file s="173" n="build.xml"/>
<file s="641" n="input.xml"/>
<file s="3587" n="main.xsl"/>
<file s="184" n="Makefile"/>
<file s="3869" n="MyGenerator.class"/>
<file s="5265" n="MyGenerator.java"/>
</xml>

さらに、sやnなど、タグや属性の短縮名を使用する代わりに、sizeやnameに変更することもできます(リスト7)。

リスト7. fileタグの付いたディレクトリー・リスト
% cat ls.xml | xml ed -r "//f" -v "file" -r "//@s" -v "size" -r "//@n" -v "name"
<?xml version="1.0"?>
<xml>
<file size="6148" name=".DS_Store"/>
<file size="173" name="build.xml"/>
<file size="641" name="input.xml"/>
<file size="3587" name="main.xsl"/>
<file size="184" name="Makefile"/>
<file size="3869" name="MyGenerator.class"/>
<file size="5265" name="MyGenerator.java"/>
</xml>

読みやすくなりました。また、XSLT、Perl、Javaコードは1行も書いていません。このファイルをls2.xmlという名前で保存しましょう。


検証

新しいディレクトリー・リストはすばらしいですが、まだ妥当でしょうか。それを確かめる方法をリスト8に示します。

リスト8. XMLの整形式の確認
% xml val ls2.xmlls2.xml - valid

ええ、妥当です。整形式(開始タグと終了タグが対応していることを意味します)という意味では、文字は正しくエンコードされています。しかし、必要なタグがすべてそろっていなかったり、正しいタグが使われていない可能性はあります。それを確かめるには、ファイルの正しい構造を知る必要があります。そのためには、スキーマが必要です。XMLドキュメントをスキーマと比較対照チェックして、チェックに合格したことを確認するまでは、本当に妥当とは言えません。

リスト9は、XMLディレクトリー・リスト・ファイルの基本的なRELAX NGスキーマを示しています。

リスト9. RELAX NGスキーマ
<?xml version="1.0" encoding="UTF-8"?>
<grammar ns="" xmlns=http://relaxng.org/ns/structure/1.0
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<element name="xml">
<oneOrMore>
<element name="file">
  <attribute name="name">
    <data type="NMTOKEN"/>
  </attribute>
  <attribute name="size">
    <data type="integer"/>
  </attribute>
</element>
</oneOrMore>
</element>
</start>
</grammar>

RELAX NGは読みやすいです。最初に、elementタグによって、xmlという名前がベース・タグとして定義されています。次に、xmlタグ内のoneOrMoreタグにfileとsizeという名前が付けられます。

ls2.xmlファイルは、この新しいスキーマに対して妥当でしょうか。リスト10を見てください。

リスト10. スキーマに対するチェック
% xml val -e -r ls.rng ls2.xml
ls2.xml - valid

あなたが私と似た性格の人なら、失敗するのを見なければ満足できないでしょう。そこで、ls3.xmlという名前のファイル内のファイル項目の1つにsomeAttributeという属性を追加し、もう一度チェックします(リスト11)。

リスト11. スキーマに対する不正なファイルのチェック
% xml val -e -r ls.rng ls3.xml
ls3.xml:4: element file: Relax-NG validity error : 
» Invalid attribute someAttribute for element file
ls3.xml - invalid

結局、これは失敗します。ファイルが整形式であるだけでなく、正しいタグと属性のすべてがそろっていることがわかりました。


テキストへ

選択関数で遊ぶこともできます。選択関数を使用すると、XMLからデータの要素を抽出することができます。リスト12の例は、XMLディレクトリー・リストからファイル名をプレーン・テキストとして抽出します。

リスト12. ファイル名の抽出
% xml sel -t -m "/xml/file" -v "concat(@name,'
')" ls2.xml
.DS_Store
build.xml
input.xml
main.xsl
Makefile
MyGenerator.class
MyGenerator.java

ここでは、2つのことに注目してください。まず、ファイル名を取得するためのXPathは、/xml/file指定です。第2に、出力指定で-vオプションを使うと、fileタグのname属性がキャリッジ・リターンで連結されます。

これで、-sオプションを追加すれば、size属性でファイルをソートできます(リスト13)。A:N:-構文は、数字の昇順ソートを使うようにXMLStarletに指示します。(このコードでは、結果を確認するために、concat文にsizeパラメーターを追加しています。)

リスト13. リストのソート
% xml sel -t -m "/xml/file" -s A:N:- "@size" -v "concat 
» ( @name,':',@size,'
' ) " ls2.xml
build.xml:173
Makefile:184
input.xml:641
main.xsl:3587
MyGenerator.class:3869
MyGenerator.java:5265
.DS_Store:6148

交通情報で楽しむ

xmlコマンドで楽しむために、トラフィック・レポートを解析してみることができます。Yahoo! ® Mapsは、交通情報サービスを提供しています。curlコマンドに-g(GET)オプションを付けて使用すると、RSSから最新の交通情報をダウンロードできます。たとえば、リスト14では、?csz=94101引数を追加して自宅の郵便番号を指定したので、サンフランシスコの最新のトラフィック・レポートが表示されています。

リスト14. RSSでのサンフランシスコ交通情報
% curl -g "http://maps.yahoo.com/traffic.rss?csz=94101" -s
<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="2.0">
<channel>
<title>Yahoo! Maps Traffic -- San Francisco,  CA 94101</title>
<link>http://us.rd.yahoo.com/maps/mapresults/trfrssarea/*
» http://maps.yahoo.com/maps_result?csz=
» San+Francisco%2C++CA+94101&country=
» us&lat=37.775&lon=
» -122.4183&trf=1&mag=5</link>
<category>Traffic</category>
<description>Yahoo! Maps Traffic -- 
» San Francisco,  CA 94101</description>
<language>en-us</language>
<ttl>3</ttl>
<lastBuildDate>Fri, 06 May 2005 16:33:59 -0700<
» /lastBuildDate>
<pubDate>Fri, 06 May 2005 18:31:27 CDT<
» /pubDate>
<copyright>Copyright (c) 2005 Yahoo! Inc. 
» All rights reserved.</copyright>
<item>
<title>
Incident, On I-580 At Seminary Ave
</title>
<description>
Traffic Collision, Severity: Major, Started: 04:20pm 05/06/05, 
» Estimated End: 04:50pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
</description>
<link>http://us.rd.yahoo.com/maps/mapresults/trfrssitem/*
» http://maps.yahoo.com/maps_result?csz=
» San+Francisco%2C++CA+94101&mlt=
» 37.778234&mln=-122.168438&lat=
» 37.775&lon=-122.4183&trf=
» 1&exctrf=1&mag=4</link>
<pubDate>Fri, 06 May 2005 16:20:00 -0700</pubDate>
<category>Incident </category>
<severity>Major</severity>
<endDate>Fri, 06 May 2005 16:50:00 -0700</endDate>
<updatedDate>Fri, 06 May 2005 16:25:00 -0700<
» /updatedDate>
</item>
...

curlコマンドの出力をXMLStarletコマンドにパイプして、説明だけを取得することもできます(リスト15)。

リスト15. トラフィックRSSのXMLStarletへのパイプ
% curl -g "http://maps.yahoo.com/traffic.rss?csz=94101" 
» -s | xml sel -t -m "/rss/channel/item/description" -v "."
Traffic Collision, Severity: Major, Started: 04:20pm 05/06/05, 
» Estimated End: 04:50pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
Disabled Vehicle, Severity: Moderate, Started: 04:20pm 05/06/05, 
» Estimated End: 04:50pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
Disabled Vehicle, Severity: Moderate, Started: 04:19pm 05/06/05, 
» Estimated End: 04:49pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
Pedestrian On The Roadway, Severity: Critical, 
» Started: 04:17pm 05/06/05, 
» Estimated End: 04:47pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
Traffic Collision, Severity: Major, Started: 04:15pm 05/06/05, 
» Estimated End: 04:45pm 05/06/05, 
» Last Updated: 04:25pm 05/06/05
...

-mオプションは、各項目の説明を拾い出します。次に、-vオプションを使ってピリオド(.)を指定すると、ノードのテキストだけを出力できます。


まとめ

この記事では、この非常にパワフルなXMLツールの表面を撫でたにすぎません。時間があれば、XMLStarletのXSLT変換関数、手軽なエスケープ関数とエスケープ解除関数、XML書式化関数などを試してみてください。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=241340
ArticleTitle=XMLStarlet入門
publish-date=06102005