全般的に非力なマシンやサーバでXMLをパースするのはちょっと面倒だったり、プログラム書くの面倒だったりするので、できればシェルだけでXML分解できないかなーっていう、管理人の考えから。
xmllintコマンドを使って分解すればいいじゃん、という結論に至り、スクリプトを書いてみた。
xmllintは
redhat系だとlibxml2のパッケージに含まれている
debian系だとlibxml2-utilsに入っている
OSXは10.3以降は標準で入っていて、見当たらないときはApple Developerで拾ってくる
大まかな使い方
xpathを使う場合は--xpathですが、シェルで使うので--shellオプションを付けます
まずは、xmlの標準書式に従っていないデータを校正する必要があったりするので、その場合は
xmllint --format "元のファイル" > "標準化したファイル"
というように実行します
次に要素の取り出し方、たとえば、RSSを取得してタイトルと要素を引っ張り出す場合は
cat /rss/channel/item[0]/title" | xmllint --shell "抽出したいxmlファイル"
こう実行すると、"抽出したいxmlファイル"の<rss> <channel> 0番目の<item> <title>取り出される文字</title>を抽出します
以下のスクリプトはこのサイトのRSS feedを分解して、[ 更新日|タイトル|リンク|オーナー ]を一覧表示するスクリプト
#!/bin/sh IFS=" " XTEMP="loaded.tmp" XTEXT="loaded.xml" #XML取得 curl -s -S "http://dorodorodoroid.hatenablog.com/rss" >> "${XTEMP}" #XMLの標準化 xmllint --format "${XTEMP}" > "${XTEXT}" count=1 while : do #アイテムの終端検出 end_xml=`echo "cat /rss/channel/item[${count}]/title" | xmllint --shell "${XTEXT}"` #要素分解 PUBDATE=`echo "cat /rss/channel/item[${count}]/pubDate" | xmllint --shell "${XTEXT}" | grep "<pubDate>" | sed -e "s/^.*<pubDate.*>\(.*\)<\/pubDate>.*$/\1/"` TITLE=`echo "cat /rss/channel/item[${count}]/title" | xmllint --shell "${XTEXT}" | grep "<title>" | sed -e "s/^.*<title.*>\(.*\)<\/title>.*$/\1/"` LINK=`echo "cat /rss/channel/item[${count}]/link" | xmllint --shell "${XTEXT}" | grep "<link>" | sed -e "s/^.*<link.*>\(.*\)<\/link>.*$/\1/"` AUTHOR=`echo "cat /rss/channel/item[${count}]/author" | xmllint --shell "${XTEXT}" | grep "<author>" | sed -e "s/^.*<author.*>\(.*\)<\/author>.*$/\1/"` # 全て取得した場合、ループを抜ける if [ "${end_xml}" = "/ > / > " ]; then break else if [ "x${PUBDATE}" = "x" ]; then break fi #日付のフォーマット変換 PUBDATE=`date -d"${PUBDATE}" +%Y%m%d` echo "${PUBDATE}|${TITLE}|${LINK}|${AUTHOR}" fi count=${count}+1 done
こんな感じで、xmlが分解できます