XMLファイルから特定の要素や属性を抽出して整形する方法をまとめました。Shellのgrep、sed、xmllintコマンドを組み合わせて、要素や属性を取得します。
下記ファイル(samle.xml)を考えます。
※実際には要素間に改行とスペースが入っていないファイルです。
<?xml version="1.0" encoding="utf-8"?> <members> <member id="1"> <name>hoge</name> <age>21</age> </member> <member id="2"> <name>piyo</name> <age>34</age> </member> <member id="3"> <name>foo</name> <age>25</age> </member> <member id="4"> <name>bar</name> <age>18</age> </member> <member id="5"> <name>fuga</name> <age>100</age> </member> </members>
grepとsedで抽出
XMLの要素は、抽出対象の要素に子要素を含んでいないのであれば(例のnameやage)、oオプションを指定したgrepで取得できそうです。
$ grep -o "<name[^>]*>[^<]*</name>" sample.xml <name>hoge</name> <name>piyo</name> <name>foo</name> <name>bar</name> <name>fuga</name>
要素の内容はパイプでつないでsed等で抽出できます。
$ grep -o "<name[^>]*>[^<]*</name>" sample.xml | sed -e "s/<name>\(.*\)<\/name>/\1/" hoge piyo foo bar fuga
抽出対象の要素に子要素を含んでいるのであれば(例のmember)、例えば要素の前に改行を埋め込み、行単位でgrepするように仕掛ければ取得できそうです。
$ sed -e "s/<member /\n<member /g" sample.xml | grep -o "^<member [^>]*>.*</member>" <member id="1"><name>hoge</name><age>21</age></member> <member id="2"><name>piyo</name><age>34</age></member> <member id="3"><name>foo</name><age>25</age></member> <member id="4"><name>bar</name><age>18</age></member> <member id="5"><name>fuga</name><age>100</age></member>
属性はさらにパイプしてsedで取得。
$ sed -e "s/<member /\n<member /g" sample.xml | grep -o "^<member [^>]*>.*</member>" | sed -e "s/^<member [^>]*id=\"\([^\"]*\)\".*$/\1/g" 1 2 3 4 5
工夫の余地はたくさんありそうです。
xmllintとsedで抽出
xmllintではXPathが利用できるので、これを利用して抽出します。
$ xmllint --xpath "/members/member/name" sample.xml <name>hoge</name><name>piyo</name><name>foo</name><name>bar</name><name>fuga</name>
要素の内容はtext()で取り出します。
$ xmllint --xpath "/members/member/name/text()" sample.xml hogepiyofoobarfuga
改行無しの出力となるので、終了タグの直後に改行を入れる等して見やすくします。(出力結果を見やすく整形するオプションが見当たらなかった)
$ xmllint --xpath "/members/member/name" sample.xml | sed -e "s/<\/name>/<\/name>\n/g" <name>hoge</name> <name>piyo</name> <name>foo</name> <name>bar</name> <name>fuga</name>
要素の内容の抽出。
$ xmllint --xpath "/members/member/name" sample.xml | sed -e "s/<\/name>/<\/name>\n/g" | sed -e "s/<name>\(.*\)<\/name>/\1/" hoge piyo foo bar fuga
抽出対象の要素に子要素を含んでいたとしても、XPathならばシンプルな記述で抽出できそうです。
$ xmllint --xpath "/members/member" sample.xml | sed -e "s/<\/member>/<\/member>\n/g" <member id="1"><name>hoge</name><age>21</age></member> <member id="2"><name>piyo</name><age>34</age></member> <member id="3"><name>foo</name><age>25</age></member> <member id="4"><name>bar</name><age>18</age></member> <member id="5"><name>fuga</name><age>100</age></member>
属性の抽出は、XPathに@を使います。
$ xmllint --xpath "/members/member/@id" sample.xml id="1" id="2" id="3" id="4" id="5"
空白区切りの出力のようなので、それを利用して整形できそうです。
$ xmllint --xpath "/members/member/@id" sample.xml | sed -e "s/ id=\"\([^\"]*\)\"/\1\n/g" 1 2 3 4 5