はじめに
昨今のWebサイトではブログの興盛にともない、RSS配信が当たり前のこととなりました。これにともなって、「RSSリーダー」や「アグリゲーター」と呼ばれるRSSを効率よく収集するためのツールが、出回るようになってきています。これらのソフトウェアのインタフェースで、Outlook的な3ペイン型のウインドウ構成になっているものをよく見かけます。例えば「goo RSSリーダー」です。
さてここで、RSSリーダーをOutlook風にするよりは、いつも使っているOutlookがRSSリーダーになる方が使いやすいのではないか…とだれもが思うことでしょう。Outlookを常用メーラーとして使用している人であれば、操作感も同じですし、RSSを読むということとメールを読むということが一体化し、情報収集能力もアップしそうな気がします。
対象読者
VBAを使ったプログラムの経験者を想定しています。
必要な環境
Microsoft Outlookと、MSXML 4.0 Service Pack 2以上が必要です。XMLの解析に複雑なことはしていないので、MSXML 3.0 Service Pack 5 (SP5)でも大丈夫でしょう。
COMアドインによるOutlookのRSSリーダー化
OutlookをRSSリーダーにする方法の一つとしては、Outlookの「COMアドイン」を使用するというのがあります。[ツール]→[オプション]→[その他]→[詳細オプション]を選択し、[COMアドイン]をクリックして、そういったRSS収集機能を持つアドイン(プラグイン)を追加することができます。
COMアドイン型のOutlook用のRSSリーダーとしては以下のものが現在あるようです(他にもあるかもしれませんが未調査)。
VBAで作る?
RSSの受信は限定的に(自分仕様で)実装するのであれば、プログラマーにとっては1日でできるような簡単な作業です。簡単なだけに「COM」的なちょっと大げさな仕組みに頼らなくても、よいのではないか? 例えばOutlookのVBAでできないのだろうか? という直感が沸いてきます。
OutlookのVBAがいったい世間では何に使用されているのか、ウイルスの作成くらいしか、思いつきませんが、マジメに使えばメール処理に絡んだ一通りのことは、処理として記述できるようなので、RSSリーダーができそう…な気がします。
RSS受信処理フロー
OutlookのVBAは本来はメーラーの処理を自動化するものです。端的に言うと、メールを作成したり、送信したり、といったことを自動的に行なえるわけです。このことを応用して、OutlookをRSSリーダー化するための処理フローとして、とりあえず以下のように定めてみます。
- RSSをWebサイトから取得する
- 取得したRSSの情報を切り分ける
- 切り分けたRSSの各情報を1つのメッセージとして作成(投稿)する
- 投稿したメッセージを所定のフォルダに移動する
対象RSS
対象とするRSSはRSS 1.0限定とします。他のバージョンへの対応は後から各自拡張してください。
RSS受信のためのインタフェース
RSS受信するためのインタフェースを以下のように決めます。
- RSSを受信するフォルダは[個人用フォルダ]以下に作成したメールアイテムを保存可能な任意のフォルダとする。
- 受信するRSSのURLはフォルダのプロパティにある[アドレス]に記述しておく。
- 受信処理用のメインルーチンはマクロとしてツールバーからクリックで呼び出す。
インタフェースの作成
- [個人用フォルダ]を右クリックして[フォルダの作成]を選択。
- [名前]を「RSSTest」とする。
- 作成したフォルダ「RssTest」を右クリックして[プロパティ]をクリック。
- [ホームページ]タブをクリックして「アドレス」に受信したいRSSへのURLを入力します。例えばここでは、@ITの「すべてのフォーラムの新着情報15本」のURLである「http://www.atmarkit.co.jp/rss/rss2dc.xml」というURLを入れておきます。
以上で、インタフェースの作成は終わりです。
ちなみに、たまたま、フォルダにURLを書ける欄があったのでこのようなお手軽仕様にしていますが、別に外部のコンフィグファイルにしておいて、それを読むような仕様にしてもいいです。各自自分の方法を考えることが大事です。
準備
RSSはXML文書として配信されています。受信したXMLファイルを解析するために、無料でMicrosoftより配布されている、MSXMLを利用します。ここでは、現時点での最新版の「4.0」をインストールしておけばよいでしょう。
また、RSSの仕様については、「RSS -- サイト情報の要約と公開」などがわかりやすいので読んでおくとよいでしょう。もちろん、わからなくても本家の「RDF Site Summary (RSS) 1.0」を読むことも重要です。
VBAの準備です。[ツール]→[マクロ]→[Visual Basic Editor]をクリックします(または[Alt]+[F11]キー)。Visual Basic Editorが起動したら、プロジェクトエクスプローラから[Project1]を右クリックして[挿入]→[標準モジュール]を選択します。「Module1」が追加されます。ここにコードを記述します。
今回、XMLの解析にMSXMLを使用するため、プロジェクトにMSXMLへの参照も追加しておきます。[ツール]→[参照設定]で、表示される[参照可能なライブラリファイル]の中から[Microsoft XML, v4.0]にチェックをつけて、[OK]をクリックします。
MAPIフォルダの取得
現在選択しているフォルダへの参照をActiveExplorer.CurrentFolder
によって取得し、そのフォルダからWebViewURL
プロパティによりURL情報を取得します。
Dim oRssFolder As MAPIFolder Dim rssUrl As String Set oRssFolder = ActiveExplorer.CurrentFolder rssUrl = oRssFolder.WebViewURL
ちなみに選択したフォルダは、MAPIFolder
というオブジェクトになっています。このオブジェクトはOutlookが扱うさまざまなアイテム(メールや予定表等)をすべて同列に扱うためのフォルダオブジェクトです。MAPIというのはMicrosoftが提唱する、メールを扱うための標準的なAPIです。
XMLの同期読み込み
URLを取得したら、XMLを同期的に読み込みます。非同期ではないことに注意してください(async
のデフォルトは「True
」(非同期))。「非同期」だと、読み込みが終わる前に次の行が実行されるため、そのための処理をきちんと書いておかないと、エラーになります。「同期」は処理が硬直的ですが、サンプルとしては簡単なので、ここでは同期でいきます。
'RSSデータの取得:非同期OFFにすること xmlDoc.async = False If (xmlDoc.Load(rssUrl) = False) Then Debug.Print xmlDoc.parseError.reason Exit Sub End If
エラーが起こったら、とりあえずイミディエイトウインドウに表示するようにしています。
チャンネルノードの処理
まずチャンネルノードを処理します。XMLのノードの操作は最低限、単数選択ならselectSingleNode
メソッド、複数選択(いわゆるコレクション)の選択ならselectNodes
メソッドを使用することを覚えておけばよいでしょう。以降、XMLノード操作の詳細な解説はしません。MSXML SDKのヘルプをご覧ください。
'RDF typeの場合 strxpath = "//channel" 'channel nodeの取得 Set chanNode = xmlDoc.selectSingleNode(strxpath) chantitle = chanNode.selectSingleNode("title").Text chanlink = chanNode.selectSingleNode("link").Text updatestr = chanNode.selectSingleNode("dc:date").Text chanupdate = ConvertStringToDate(updatestr)
日付がdc:date
という少し特殊な形式になっているので、ConvertStringToDate
というプライベート関数で日付型に変換しています。かなり適当な関数です。
'dc:dateタイプの文字列をDate型に変換(適当に) Private Function ConvertStringToDate(ByVal strDate) As Date 'dc:date = 2005-01-13T22:31:00+09:00 yy = Mid(strDate, 1, 4) mm = Mid(strDate, 6, 2) dd = Mid(strDate, 9, 2) t = Mid(strDate, 12, 8) ConvertStringToDate = CDate(yy & "/" & mm & "/" & dd & " " & t) End Function
アイテムノードの処理
各アイテム(ニュースの実体)を処理します。以下のようなコードを書きます。
'各Itemの取得 strxpath = "//item" Set itemNodeList = xmlDoc.selectNodes(strxpath) '日付の新しいものが上になるように逆順にとりだす Dim i As Long Dim posttitle As String Dim postcount As Long Dim itemlen As Long itemlen = itemNodeList.Length For i = itemlen - 1 To 0 Step -1 Set itemNode = itemNodeList.Item(i) itemtitle = itemNode.selectSingleNode("title").Text itemlink = itemNode.selectSingleNode("link").Text itemdesc = itemNode.selectSingleNode("description").Text dcdate = itemNode.selectSingleNode("dc:date").Text itemupdate = ConvertStringToDate(dcdate) '件名:同じタイトルを防ぐために日付情報を含める posttitle = itemtitle & " [" & dcdate & "]" '二重登録を防ぐためにタイトルを検索する:同じタイトルは登録しない Set findItem = oRssFolder.Items _ .Find("[件名] = """ & posttitle & """") If (findItem Is Nothing) Then 'Postitemの作成 Set oPostItem = CreateItem(olPostItem) oPostItem.UnRead = True oPostItem.Subject = posttitle strText = posttitle & vbCrLf & _ itemlink & vbCrLf & vbCrLf & _ itemdesc & vbCrLf oPostItem.Body = strText '直接保存はできない?ので 'いったん「受信トレイ」にPostしてMoveする oPostItem.Post oPostItem.Move oRssFolder postcount = postcount + 1 End If Next
日付の新しいものを上に
自分の好みで、日付の新しいものが件名リストの上に来てほしいので、逆順に取り出しています(もとデータが日付順に並んでいると仮定して)。
二重登録の防止
二重登録を防ぐために、タイトルを検索して同じメッセージがないかどうか調べてから追加するようにしています。これをしないと同じ件名のものがあった場合、メッセージが重複して作成されます。Outlookはメーラーですから、同じ件名であっても何の問題も無く作成されることに注意です。
メッセージの保存と移動
メッセージを作成しますが、このときMailIetm
オブジェクトではなくPostItem
オブジェクトを作成します。MailItem
オブジェクトは相手方に何かのメッセージを送信するのが目的なので、今回は、自分当てに投稿するだけで、誰にも送信しませんからPostItem
を作成します。PostItem
をPost
メソッドで投稿すると[受信フォルダ]にアイテムが保存されます。これをMove
メソッドで自分のRSS収集用のフォルダに移動させるようにします。
未読の処理
また、新たに追加したメッセージは未読状態になっていないと、メーラーっぽくありませんので、それの計算を行ないます。これはインタフェースの問題なので、よりシンプルにするのであれば、無くてもよい処理かもしれません。
itemtotal = oRssFolder.Items.Count '未読にする最初の位置を計算 firstindex = itemtotal - (postcount - 1) '追加したもののみ未読フラグをつける For i = itemtotal To firstindex Step -1 oRssFolder.Items(i).UnRead = True Next
マクロをツールバーに登録
完成したルーチンをマクロとして登録します。今回は、仮に「GetRss
」というプロシージャ名にしました。登録は以下のようにします。
- [ツール]→[ユーザー設定]→[コマンド]の[分類]から[マクロ]を選択。
- 右の[コマンド]から[Project1.GetRss]を選択して、ツールバーにドラッグします。
マクロの実行
RSSを取得したいフォルダを選択した状態で、ツールバーのボタンを押すとフォルダに続々とニュースのリストが降って来ます。
発展
以上で、OutlookでRSS1.0が読めるようになりました。
発展系としては、RSS2.0などへも対応するとよいでしょう。またOutlookはHTMLメーラーでもありますから、HTMLとして受信、表示できるようにもできます。具体的には、セキュリティ的な問題がありますが、IFRAME
の表示をONにしておき、IFRAME
のsrc
に各ニュースのリンク先を記述して、Outlookで表示させれば、即席HTML型RSSリーダーの出来上がりです。
課題
ポストメッセージを作成すると「差出人」欄がどうしても自分の現在アクティブなアカウント名になります。見栄えがちょっと悪いです(回避方法はあるのでしょうか?)。また、RSSの定期自動取得機能が欲しいところです。VBAだと、力技でできなくもないですが、そこまでやるのならCOMアドインを使ったほうがよいでしょう。
まとめ
既にあるものを使えば、わずか150行ほどのコードでもRSSリーダーが作れます。「~リーダー」など名前はたいそうですが、たいしたことはしていません。
また、今回は外部のXMLデータを切り分けて、その情報をOutlookに保存するということのサンプルにもなっています。RSSに限らず、インターネット上のさまざまなリソースをOutlookに保存するときの応用にも使えるでしょう。
- VBAでOutlookをRSSリーダーにできる。
- VBAでXMLを処理するときはMSXMLの使用が効率的。
- メッセージを送信せずに保存するには
PostItem
を使う。 IFRAME
タグを使えば、URLだけでHTML文書を表現できる。- RSSは単なるXML文書。