だいたいきままなエンジニア志望のブログ

エンジニア志望の大学院生の考えたことあれこれ

難しいこと考えずKotlinでJSONをパース

Kotlinを使ってJSONをパースしてみました.

今回はWikipedia APIのデータをパースして「記念日・年中行事」のデータを取得します.

WikipediaAPIを叩いてデータを用意

日付を指定してWikipedia APIを叩きます.
https://ja.wikipedia.org/w/api.php?format=json&utf8&action=query&prop=revisions&rvprop=content&titles=4月1日
とすると以下の構造のデータが得られます.

{
   "batchcomplete": "",
   "warnings": {},
   "main": {},
   "query": {
        "pages": {
             "2004": {
                  "pageid": 2004,
	          "ns": 0,
                  "title": "2月18日",
                  "revisions": [
		       {
			"contentformat": "text/x-wiki",
			"contentmodel": "wikitext",
			"*": "{{カレンダー 4月}}\n'''4月1日'''(しがつついたち)は、[[グレゴリオ暦]]で年始から91日目([[閏年]]では92日目)にあたり
		       }
		  ]
	      }
          }
    }
}

パースしたい階層

今回のターゲットは
"query"."pages"."2004"."revisions".[0].["*"]
に記述されている本文です.


ここで"2004"はpageidであり,日毎に変わるキー名となることに注意してください.

(4月1日の記事におけるpageidは2004)


本来ならばJSONの形式に沿ったクラスを用意して変換するべきなのですが,今回は力技でパースすることにします.

Kotlinでパース

// wikiResponse:wikipediaAPIのレスポンス(String型)
val parentJsonObj = JSONObject(wikiResponse)

val queryObj = parentJsonObj.getJSONObject("query")

val pagesObj = queryObj.getJSONObject("pages")

// ページidは記事によって異なるのでpagesObjectの一番目のキーとして名前を取得
val pageNumJsonObj = JSONObject(pagesObj.getString(pagesObj.keys().next().toString()))

// revisionsの次はキー名が存在しない.次の階層はインデックスで指定するJsonArrayに変換
val revisionsJsonArray = pageNumJsonObj.getJSONArray("revisions")

val zeroJsonObj = revisionsJsonArray.getJSONObject(0)

var today_article = zeroJsonObj.getString("*")

これで記事の本文を取得することができます.


取得した記事のノイズ取りや整形

本文の内容は以下の記事によって構成されています
== できごと ==
== 誕生日 ==
== 忌日 ==
== 記念日・年中行事 ==
== フィクションのできごと ==
== 誕生日(フィクション) ===
== 出典 ==
== 関連項目 ==

今回は記念日の部分を取得したいのでsubstringで記念日・年中行事とフィクションの出来事の間を切り抜いてあげるといいでしょう

var today_anniv = today_article.substring( today_anniv.indexOf("==記念日・年中行事=="), today_article.indexOf("==フィクションのできごと==") )

とすればOK

ただこのままだと区切り記号 [ ] や,記念日の国情報( {{JPN}}や{{USA}} )も乗っているので綺麗にしたい場合は

today_anniv.replace("[", "")
today_anniv.replace("]", "")
today_anniv.replace("""\{\{...\}\}""".toRegex(), "")

とするといいかもしれません.