はじめに
前回は、はてなブログAPIのレスポンスから必要な情報を拾って、後で扱いやすいように同じ形のXMLにするところまでを作った。
今回は、前回作成したスクリプトの出力を標準入力から受けて、それを1つの記事(entryタグ)ごとに1行ずつにまとめて出力するものを作ろう。
簡単に言えば、XMLを任意のタグごとに1行にまとめる1つの例になると思う。
つくるもの
使い方は、前回の出力をパイプで受け取る感じ。
(h-entry-perline
が今回のスクリプト)
> cat SAMPLE | h-entry-pickup detail | h-entry-cleantags | h-entry-perline
入力は、前回作ったh-entry-pickup
の引数がdetail
かsimple
であることを想定している。
つまりコンテンツは、想定していない。
動作例
以下が加工前のデータ。2つの記事(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>記事タイトル1</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> <category>カテゴリ1</category> <category>カテゴリ2</category> <app:draft>no</app:draft> </entry> <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>記事タイトル2</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> 記事本文 リスト3 リスト4 内容 </summary> <category>カテゴリ3</category> <category>カテゴリ4</category> <app:draft>no</app:draft> </entry>
それを1つの記事ごとに1行ずつ、以下のようにまとめる。
> cat SAMPLE | h-entry-pickup detail | h-entry-cleantags | h-entry-perline <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>記事タイトル1</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><category>カテゴリ1</category><category>カテゴリ2</category><app:draft>no</app:draft></entry> <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>記事タイトル2</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> 記事本文 リスト3 リスト4 内容 </summary><category>カテゴリ3</category><category>カテゴリ4</category><app:draft>no</app:draft></entry>
コード
今回のコードはこちら。
何か変なところがあればご指摘下さいまし。
今回のXMLを1行にまとめる方法は、だいぶ手間取った。
実際は最後のたった6行だが、意図が読み取り辛いと思うので説明しておこう。
今回、複数行をまとめるにあたり、1度全部改行を消して1行にまとめている。
後で、</entry>
を改行に置き換える。
tr
コマンドで簡単に置換えられるように、あらかじめ</entry>
を1文字の記号に置き換えている。
この記号のことを、以降では改行記号と呼ぶ。
この改行記号は、他で絶対出てこない文字を使う必要がある。
後で、この改行記号を実際の改行文字に置き換える際、間違った箇所で改行してしまわないようにするためだ。
幸い、はてなブログAPIからのレスポンスは、XML要素の中身がサニタイズされているようだ。
つまり、XMLタグ以外で<
と>
は出てきそうにない。
そこで今回は、改行記号として、>
を使うことにした。
以降で、変換する過程を示しておこう。
XMLを1行にまとめる過程詳細
[入力データ]
<entry> <tag>value1</tag> </entry> <entry> <tag>value2</tag> </entry>
Step1. 改行記号として使うタグの>
を、別の文字('<`)にしておく
tr '>' '<' \
<entry< <tag<value1</tag< </entry< <entry< <tag<value2</tag< </entry<
Step2. 行の区切りになる</entry>
を>
に置き換える
| sed "s#</entry<#$LF_CHAR#g" \
<entry< <tag<value1</tag< > <entry< <tag<value2</tag< >
Step3. 改行を一度全部削除する
| tr -d '\n' \
<entry<<tag<value1</tag<><entry<<tag<value2</tag<>
Step4. 改行記号としておいた(>
)を、改行に置き換える
| tr "$LF_CHAR" '\n' \
<entry<<tag<value1</tag< <entry<<tag<value2</tag<
Step5. XMLタグの'>'を元に戻す
| sed 's#<\([^<]*\)<#<\1>#g' \
<entry><tag>value1</tag> <entry><tag>value2</tag>
Step6. </entry>
を元に戻す
| sed 's#$#</entry>#'
<entry><tag>value1</tag></entry> <entry><tag>value2</tag></entry>
うーん、効率が良い方法とは思えないよね。
僕はネットでいい方法見つけられなかった。
いったい他の人は普通どうやっているのだろうか。
POSIXや他の環境を気にしなかったら、もっと簡単な方法があるのだろうか。
教えておじいさん。教えてアルムのもみの木よ。トライの人でもいいから。
sed
が改行文字を最初から検索対象にしてくれれば、楽なのだけれども。。。
そもそもシェルスクリプトでやることかと言われると、他の言語使いたーい。
最後に
今回は、UNIXの各コマンドで扱いやすいように、1つの記事を1つにまとめる処理を作った。
ここまでくれば、UNIXお得意の表形式データまであと一歩。
次回は、今回の出力から、指定したXMLタグの要素だけを抜き出すスクリプトを作ってみよう。
そういえば、今回のスクリプトをちょっと変えれば、特定のXML要素ごとに1行に置き換える汎用的なスクリプトになる。
他でも流用できるものを作りたい人はやってみてはいかがだろうか。
確認環境
PC | Thinkpad X1 Carbon 2nd Gen |
OS | 12.0-RELEASE-p7 |
以上。