【シェルと遊ぼう】はてなブログAPIのレスポンス解析 その1 必要な情報を拾って、形を揃える

はじめに

前回は、はてなブログAPIサービスにリクエスト送ってレスポンスを受け取るスクリプトを作成した。

今回は、受け取ったレスポンスから必要な情報を集めて、XMLタグの形を揃えるところまでを作ってみよう。

つくるもの

今回のスクリプトは、2つに分ける。

  1. レスポンスデータから必要な項目を抜き出す。
  2. 同じXMLタグの形に揃える。

1 は必要なデータをgrepsedで拾うだけ。
必要になりそうなパターンは、予め引数で簡単に指定できるようにしよう。

2 は後で扱いやすいように、XMLタグを同じ形に統一する。

動作例

以下の、こちらのページのサンプルを加工する例を見てみよう。

加工前のデータ

> cat SAMPLE | ./h-entry-pickup simple  
<?xml version="1.0" encoding="utf-8"?>  
<feed xmlns="http://www.w3.org/2005/Atom"  
      xmlns:app="http://www.w3.org/2007/app">  
  <link rel="first" href="https://blog.hatena.ne.jp/{はてなID}}/{ブログID}/atom/entry" />  
  <link rel="next" href="https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/entry?page=1377584217" />  
  <title>ブログタイトル</title>  
  <link rel="alternate" href="http://{ブログID}/"/>  
  <updated>2013-08-27T15:17:06+09:00</updated>  
  <author>  
    <name>{はてなID}</name>  
  </author>  
  <generator uri="http://blog.hatena.ne.jp/" version="100000000">Hatena::Blog</generator>  
  <id>hatenablog://blog/2000000000000</id>  

  <entry>  
    <id>tag:blog.hatena.ne.jp,2013:blog-{はてなID}-20000000000000-3000000000000000</id>  
    <link rel="edit" href="https://blog.hatena.ne.jp/{はてなID}/ブログID}/atom/edit/2500000000"/>  
    <link rel="alternate" type="text/html" href="http://{ブログID}/entry/2013/09/02/112823"/>  
    <author><name>{はてなID}</name></author>  
    <title>記事タイトル</title>  
    <updated>2013-09-02T11:28:23+09:00</updated>  
    <published>2013-09-02T11:28:23+09:00</published>  
    <app:edited>2013-09-02T11:28:23+09:00</app:edited>  
    <summary type="text"> 記事本文 リスト1 リスト2 内容 </summary>  
    <content type="text/x-hatena-syntax">  
      ** 記事本文  
      - リスト1
      - リスト2
      内容  
    </content>  
    <hatena:formatted-content type="text/html" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">  
      &lt;div class=&quot;section&quot;&gt;  
      &lt;h4&gt;記事本文&lt;/h4&gt;  
      &lt;ul&gt;  
      &lt;li&gt;リスト1&lt;/li&gt;  
      &lt;li&gt;リスト2&lt;/li&gt;  
      &lt;/ul&gt;&lt;p&gt;内容&lt;/p&gt;  
      &lt;/div&gt;  
    </hatena:formatted-content>  
    <app:control>  
      <app:draft>no</app:draft>  
    </app:control>  
  </entry>  
  <entry>  
  ...  
  </entry>  
  ...  
</feed>  

必要なデータを拾う

1. 記事内容以外の必要そうな情報を全て拾う例
> cat SAMPLE | h-entry-pickup detail  
  <entry>  
    <link rel="edit" href="https://blog.hatena.ne.jp/{はてなID}/ブログID}/atom/edit/2500000000"/>  
    <link rel="alternate" type="text/html" href="http://{ブログID}/entry/2013/09/02/112823"/>  
    <author><name>{はてなID}</name></author>  
    <title>記事タイトル</title>  
    <updated>2013-09-02T11:28:23+09:00</updated>  
    <published>2013-09-02T11:28:23+09:00</published>  
    <app:edited>2013-09-02T11:28:23+09:00</app:edited>  
    <summary type="text"> 記事本文 リスト1 リスト2 内容 </summary>  
      <app:draft>no</app:draft>  
  </entry>  
  <entry>  
  </entry>  
2. 上の例を絞って、一覧作成時に必要になりそうな情報を拾う例
> cat SAMPLE | h-entry-pickup simple  
  <entry>  
    <link rel="edit" href="https://blog.hatena.ne.jp/{はてなID}/ブログID}/atom/edit/2500000000"/>  
    <link rel="alternate" type="text/html" href="http://{ブログID}/entry/2013/09/02/112823"/>  
    <author><name>{はてなID}</name></author>  
    <title>記事タイトル</title>  
    <published>2013-09-02T11:28:23+09:00</published>  
      <app:draft>no</app:draft>  
  </entry>  
  <entry>  
  </entry>  
3. 記事の中身を拾う例
> cat SAMPLE | h-entry-pickup content  
    <content type="text/x-hatena-syntax">  
      ** 記事本文  
      - リスト1
      - リスト2
      内容  
    </content>  
4. 整形済みの記事の中身を拾う例
> cat SAMPLE | h-entry-pickup formated  
    <hatena:formatted-content type="text/html" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">  
      &lt;div class=&quot;section&quot;&gt;  
      &lt;h4&gt;記事本文&lt;/h4&gt;  
      &lt;ul&gt;  
      &lt;li&gt;リスト1&lt;/li&gt;  
      &lt;li&gt;リスト2&lt;/li&gt;  
      &lt;/ul&gt;&lt;p&gt;内容&lt;/p&gt;  
      &lt;/div&gt;  
    </hatena:formatted-content>  

タグをキレイにする

以下の加工前のデータを、、、

> cat SAMPLE | h-entry-pickup detail  
  <entry>  
    <link rel="edit" href="https://blog.hatena.ne.jp/{はてなID}/ブログID}/atom/edit/2500000000"/>  
    <link rel="alternate" type="text/html" href="http://{ブログID}/entry/2013/09/02/112823"/>  
    <author><name>{はてなID}</name></author>  
    <title>記事タイトル</title>  
    <updated>2013-09-02T11:28:23+09:00</updated>  
    <published>2013-09-02T11:28:23+09:00</published>  
    <app:edited>2013-09-02T11:28:23+09:00</app:edited>  
    <summary type="text"> 記事本文 リスト1 リスト2 内容 </summary>  
      <app:draft>no</app:draft>  
  </entry>  
  <entry>  
  </entry>  

以下のように整形する。

> cat SAMPLE | h-entry-pickup detail | h-entry-cleantags  
<entry>  
<edit>https://blog.hatena.ne.jp/{はてなID}/ブログID}/atom/edit/2500000000</edit>  
<alternate>http://{ブログID}/entry/2013/09/02/112823</alternate>  
<author>{はてなID}</author>  
<title>記事タイトル</title>  
<updated>2013-09-02T11:28:23+09:00</updated>  
<published>2013-09-02T11:28:23+09:00</published>  
<app:edited>2013-09-02T11:28:23+09:00</app:edited>  
<summary> 記事本文 リスト1 リスト2 内容 </summary>  
<app:draft>no</app:draft>  
</entry>  
<entry>  
</entry>  

例が良くない。
はてな公式のサンプルにはカテゴリがないことに今気づいてしまった。。。

ま、やっていることは以下です。

  1. 行の先頭・末尾の空白を除去。
  2. <link rel="Name" href="URL" /><Name>URL</Name>
  3. <author><name>{はてなID}</name></author>のnameタグを除去
  4. <category term="カテゴリ名" /><category>カテゴリ名</category>
  5. タグの属性(<tag attr="value">の`attr="value")を削除

なお、記事内容に対してこのスクリプトを使うことは想定していない。

コード

前述の通り、今回のコードは2つに分けている。

拾うスクリプト

引数のキーワードに応じて、grepするパターンを設定している。
-E拡張正規表現を使う指定。POSIXにもこのオプションあったんだね。
今まで無理してBREで頑張ってたYo。

USE_SEDをセットすることで、grepの代わりに、sedを使う。
USE_SED-sオプションで強制でき、予め用意したワード以外の場合は、引数をそのまま検索パターンとして使用する。
<entry>タグは必ず拾う。

キレイにするスクリプト

やっていることは、前述した下記の通り。

  1. 行の先頭・末尾の空白を除去。
  2. <link rel="Name" href="URL" /><Name>URL</Name>
  3. <author><name>{はてなID}</name></author>のnameタグを除去
  4. <category term="カテゴリ名" /><category>カテゴリ名</category>
  5. タグの属性(<tag attr="value">の`attr="value")を削除

空白の除去以外は、関数化してコメントに書いたので分かると思う。
正規表現はコメントないと読みづらいよね。

最後に

今回は、データを同じ形にするところまで作った。

しかし、UNIXのコマンドで扱うには行形式に変えたいところ。
(コンテンツ以外はね)

次回は、このdetailsimpleで拾った箇所を1記事1行にまとめるところまで作ってみよう。

確認環境

PC Thinkpad X1 Carbon 2nd Gen
OS 12.0-RELEASE-p7

参考

以上。