Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

XMLにパターンマッチを行って値を取り出せたら便利なのではないか

Webスクレイピングをしていて,「こういう構造にマッチしたときのここの文字列を取り出したい」というのはまあよくある話.

こういったXMLからデータを取り出す用途においてはXPathを使うのが一般的なのではないだろうか.HTMLであれば,tidyコマンドを使うことでHTMLをXMLに変換することができるから,スクレイピングでも使うことができる.

ただしXPathには分かりにくく書きにくいという欠点がある.正直に言うと自分が書いたXPathが一発で動いた試しなどほぼない.たいていの人は根からHTMLを見てなくて,葉から見ているとおもう.「こういうタグのときにここの文字列が欲しい」というイメージはあるのだから,直接ノードの構造を示してパターンマッチさせることはできないのだろうか.そしてxpathコマンドは構造化された出力をしないのでパイプで繋ぐのが大変面倒だ.

そこで今回は,XMLに対してパターンマッチを行い,テキストノードを取り出すソフトウェアを書いてみて使い勝手を見てみることにした.

リポジトリ

github.com

実装言語はCommon Lisp.パターンマッチライブラリとXMLライブラリの両者があり,なおかつ言語に慣れているため選んだ.

実行には処理系マネージャであるRoswellが必要.

Steamのユーザページからステータスを取得してみる.Steam Community :: WindymeltをcurlでGETしてきてtidy -asxml < windy.html 2>/dev/null > windy.xmlをかけたという想定である.

ユーザのステータスは以下のようなタグになっている:

<div class="profile_in_game_header">現在オンラインです。</div>

これを表現するパターンファイルは次のような形になる:

<?xml version="1.0" encoding="UTF-8"?>
<pattern>
    <div class="profile_in_game_header"><string var="status" /></div>
</pattern>

取り出したい箇所に<string var="status" />という空タグを入れている.

これでxmatch.rosを動かす.

$ ./xmatch.ros -e steam.xml windy.xml
WARNING: found
VARS: ("Currently Online")

ステータスを読み込むことができた.JSONを出力させるようにするともっと便利だと思う.

仕組み

CXMLというライブラリを使ってソースファイルとパターンファイルのXMLからS式を生成し,パターンマッチライブラリに放り込んでいる.マッチするかどうかリストを走査していくので,コストは高そう.賢いことをすると時間を削減できるかもしれない.いまのところ5秒くらいかかってしまう.わざわざS式に変換する手間で時間をロスしているのかもしれない(未測定).

終わり

もっと良さそうな実装ができそうだけど,Proof of Conceptということで今回は満足した.そのうち改良してみたい.

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?