オリジナルコレクションの作成
今回も前回 に続いてLive Labs Pivotです。前回はPivotの使い方とその仕組みについて簡単に紹介しました。今回は、Pivotで閲覧できるコレクションを作成してみましょう。
コレクションは、Collection XML(CXML)とDeep Zoom形式の画像から成っています。どちらもプログラムから生成することが可能ですが、より簡単にコレクションを作成できるようMicrosoft Office Excelのアドインが用意されています。今回はこれを使用したコレクションの作成を紹介します。
Pivot Collection Tool for Excel
コードを書かずにPivotのコレクションを生成できるExcelアドイン、Pivot Collection Tool for Excel は、PivotのWebサイトからダウンロードできます。Excel 2007以降に対応したアドインです。現在、Office 2010のBeta版 がダウンロードが可能ですのでOfficeの試用と併せてアドインを使ってみるのもよいかもしれません。
インストールするとExcelのリボンにPivot Collectionsが表示されます。図1 はNew Collectionボタンをクリックして新しいコレクションを作成したところです。
図1 コレクションの作成
さっそく、コレクションを作成していきましょう。まずNew Collectionボタンをクリックします。クリックにより作成されたシートにコレクションの情報を入力していくことでコレクションを作成できます。
シートの1行がコレクションのひとつのアイテムに対応し、各列がFacet Category、各セルの値がFacetに対応しています。
画像の追加
簡単な例としてWindowsのサンプルピクチャのコレクションを作成します。コレクションに追加する画像は、Image Location列にパスを直接入力するか、Choose Imageボタンから追加またはImport Imagesからまとめて追加します(図2 ) 。
図2 画像の追加
Image Location列には、httpから始まるURLも入力できます。パスが入力されると自動でPreview列にその画像が表示されます。このPreviewの表示は、Excel操作中に何度も画像の読み込み・表示される場合があるため、その他の項目から入力し最後に画像パスを設定するほうがよいでしょう。また、URLを入力した場合、コレクション生成時に正しく画像をダウンロードできない場合があるようです。画像を一度ダウンロードして、ローカルパスを指定したほうが確実です。
基本情報の入力
コレクションの基本的な情報として、アイテムの名前とリンク先(アイテムから移動できるWebサイト)をName列とHref列に入力します(図3 ) 。
図3 基本情報の入力
名前とリンク先は省略可能です(画像を省略してもコレクションは生成できます) 。名前とリンク先はFacet Categoryではなく、アイテムの基本的な情報としてCXMLに記述されます。
同様にDescription列にはアイテムの説明を記述します(省略可) 。この説明もFacet Categoryではなく特別な値として扱われます。入力した内容はインフォパネルの説明欄に表示されることになります(図4 ) 。
図4 インフォパネル
参考までにCXMLは次のように記述されています。名前とリンク先はItem要素の属性として、説明はDescription要素として記述されていることがわかります。
<? xml version = "1.0" encoding = "utf-8" ?>
< Collection xmlns:p = "http://schemas.microsoft.com/livelabs/pivot/collection/2009" SchemaVersion = "1.0" Name = "New Collection2" xmlns = "http://schemas.microsoft.com/collection/metadata/2009" >
< Items ImgBase = "New Collection2_files\evrc05n1.m5u.xml" HrefBase = "http://ja.wikipedia.org/wiki/" >
< Item Id = "0" Img = "#0" Name = "菊" Href = "%E3%82%AD%E3%82%AF" >
< Description > キク科キク属の植物。 </ Description >
</ Item >
...
</ Items >
</ Collection >
コレクションのプレビューと生成
入力が完了したらPivotで閲覧してみましょう。Quick Previewボタンをクリックすると、Deep Zoom形式の画像は生成せずにその他の情報がどのように反映されるかを確認できます(図5 ) 。
図5 コレクションのプレビュー
Publish Collectionボタンをクリックすると、CXMLとDeep Zoom形式の画像ファイル群が生成されます。この結果をWebで公開すればPivotユーザーが閲覧可能です。ぜひ、おもしろいコレクションを公開して、開発元へもフィードバックしていきましょう。
Facet Categoryの追加
以上で一応のコレクションは作成できましたが、Facet Categoryがまったくないコレクションです。アイテムにより多くの情報を付加するにはFacet Categoryを追加する必要があります。Facet CategoryとFacetの追記は、空いている列に情報を追記して行います(図6 ) 。
図6 Facet Categoryの追加
この例では評価というFacet Categoryを追加しました。このようにいくつも列を増やしていくことでFacet Categoryを追加します。Facet CategoryおよびFacetはインフォパネルの表示やフィルターパネルに反映されます(図7 ) 。
図7 Facet Category・Facetのあるコレクション
Facet Categoryに使用できる値の型は、文字列や数値、日付、リンクなどがあります。セルの形式を数値や日付などに設定すると、型の反映が行われます。評価の例では、数値型が反映されフィルターパネルではスライダーによるフィルタリングが可能になっています。ただし、空白セルや西暦1年など突出した値がある場合は文字列型となってしまう場合があります。
ひとつアイテムに対して、同じFacet Categoryに複数の値を持つFacetの設定も可能です。その場合、区切りに「||」を使用して入力するか、同名の列を複数追加します(図8 ) 。
図8 複数の値の入力
複数の値が設定されているアイテムは図9 のように表示されます。
図9 インフォパネルでの複数の値の表示
またFacet Categoryごとに、Facetの値をフィルターパネルに表示するかどうか(フィルタリングに利用するかどうか) 、インフォパネルに表示するかどうか、キーワードによるフィルタリング時に利用するかどうかを選択が可能です。Facet Categoryに対応する各列にフォーカスがあるときリボンのCategory Propertiesのチェックボックスをチェック・非チェックすることで選択します(図10 ) 。
図10 Category Properties
コレクション情報の入力
最後にコレクション自体の基本情報の入力についてです。アイテム情報を入力したシートの下段のほうにも注釈があるように、Collection Propertiesシートに切り替えることでコレクションの基本情報を入力できます(図11 ) 。
図11 コレクションの基本情報の入力
gihyo.jp 連載記事のコレクション
もう少し大きめのコレクションのサンプルとしてgihyo.jpの連載記事のコレクションを作成してみます(図12 ) 。Excelを利用することには変わりありませんが、入力するデータはプログラムにより収集します。
図12 gihyo.jp 連載記事コレクション
前回、コレクションの種類にはシンプル・リンク・ダイナミックコレクションの3種類があることを紹介しました。Excelのアドインにより作成できるコレクションは、シンプルコレクションです。シンプルコレクションで扱えるアイテム数は3000個程度までです。gihyo.jpの記事数もこの記事の執筆時点では範囲内のようですのでサンプルとしてちょうどよいでしょう。
コレクション作成にあたって
gihyo.jpに連載記事の情報を取得するAPIなどは特にありませんので、HTMLを取得し必要な部分を抽出することになります。簡単なサンプルコードを載せていますが、記事数分だけアクセスすることになります。アクセス過多にならないよう十分注意してください。まったく別の情報源からコレクションを作成してみるのもよいでしょう。
今回のサンプルコードは、Visual Studio 2010のBeta2を利用したコンソールアプリケーションの使用を想定しています。言語もVisual Basicの新しいバージョンの10.0の記述になっています。特に難しいことはしていませんので、古いバージョンでも読み替えは簡単だと思います。
情報の選択
次にコレクションに使用する記事の情報(抽出する情報)を決定します。実際には、この作業の前にコレクションの目的や範囲、想定するユーザーを定義する必要がありますが、省略します。
アイテムの基本情報にあたる名前とリンク先を各記事のWebページのタイトルとURLとします。アイテムの説明は省略することにします。また、アイテムの画像は各連載に対してアイコンが使用されていますので、これを使います。
Deep Zoomの機能を活かすには高解像度な画像がよいですが、今回は文章主体の情報のため難しいですね。Pivot Collection GalleryにあるWikipediaコレクションでは文章も画像化して利用しています。こちらも参考にするとよいかもしれません。
連載記事のURLをみると「http://gihyo.jp/dev/serial/01/wl-sdk/0032」というようにディレクトリが設定されています。このdev部分は連載記事のカテゴリーを表しています。wl-sdk部分は連載ごとの決められている文字列です。便宜上ここでは連載IDと呼ぶことにします。記事のカテゴリーと連載IDのふたつをFacet Categoryにします。さらに記事の掲載された日付と著者を取得し、これらもFacet Categoryとして使います。
情報の抽出
それでは、記事の情報を取得していきます。各記事のURLは、検索エンジン用のXMLファイルからまとめて取得し、カテゴリーと連載IDを抽出します。その後、各記事のURLへアクセスし、Webページのタイトル、日付、著者名を抽出します。
プログラムで使用するクラスを次に示します。連載を表すクラスの中に、その連載の記事が複数ある構成にしています。記事もひとつのクラスになっています。
Public Class Serial
Property Category As String
Property Id As String
Property LogoPath As String
Private _Articles As New List(Of Article)
ReadOnly Property Articles As IList(Of Article)
Get
Return _Articles
End Get
End Property
End Class
Public Class Article
Property Uri As Uri
Property Title As String
Property Author As String
Property [Date ] As DateTime
End Class
次にメイン処理部分を示します。Visual Basicのモジュールに記述します。記事URLを取得後、各ページにアクセスし情報を抽出し、最終的にSerialDictionaryというPrivate変数のコレクションに必要な情報が格納された連載オブジェクトが追加されます。
Private SerialDictionary As New Dictionary(Of String , Serial)
Sub Main()
Dim doc = XDocument.Load("http://image.gihyo.co.jp/sitemap.xml" )
For Each el In doc...
Dim loc = el..Value
If Not loc.Contains("/serial/" ) Then
Continue For
End If
Dim values = loc.Substring(16 ).Split(New Char () {"/"c }, StringSplitOptions.RemoveEmptyEntries)
If values.Length <= 4 Then
Continue For
End If
Dim category = values(0 )
Dim serialId = values(3 )
Dim no = values(4 )
Dim key = category & "/" & serialId
If Not SerialDictionary.ContainsKey(key) Then
SerialDictionary.Add(category & "/" & serialId, New Serial)
SerialDictionary(key).Category = category
SerialDictionary(key).Id = serialId
End If
Dim article = New Article With {
.Uri = New Uri(loc)}
FillArticleInfo(article)
SerialDictionary(key).Articles.Add(article)
Next
End Sub
上記コードで必要なメソッドの内容を示します。
Private Sub FillArticleInfo(ByVal article As Article)
Dim content = GetContent(article.Uri)
Dim match As Match
match = Regex.Match(content, "<title>(?<title>.+)</title>" )
If match.Success Then
article.Title = match.Groups("title" ).Value.Trim
End If
match = Regex.Match(content, "<p class="" date""="">(?<date>.+)</date></p>" )
If match.Success Then
article.Date = DateTime.Parse(match.Groups("date" ).Value)
End If
match = Regex.Match(content, "<p class="" author""="">(?<author>.+)</author></p>" )
If match.Success Then
article.Author = match.Groups("author" ).Value.Trim
End If
End Sub
Private Function GetContent(ByVal uri As Uri) As String
Dim content As String =
Dim request = DirectCast (WebRequest.Create(uri), HttpWebRequest)
Using response = request.GetResponse
Using reader = New System.IO.StreamReader(response.GetResponseStream)
content = reader.ReadToEnd
End Using
End Using
Return content
End Function
ネットワークにアクセスしていますが、例外処理は入っていませんので、ネットワークの状況やサーバーの状態により例外が発生する場合があります。また、HTMLから情報の抽出には正規表現を用いていますが、今後もこの記述で抽出できるとは限りませんので、参考程度に使用してください。
次に、連載を表す画像を取得するコードです。画像ファイル名は、カテゴリーと連載IDから導き出せませんので、連載を一覧できるページから抽出しています。Mainメソッドの最後に次のメソッドを呼ぶように変更します。
Private Sub GetImages()
Dim folder = System.IO.Path.Combine(My.Application.Info.DirectoryPath, "logos" )
My.Computer.FileSystem.CreateDirectory(folder)
For i = 0 To 200 Step 40
Dim matchs = Regex.Matches(GetContent(New Uri("http://gihyo.jp/serial&start=" & i.ToString)),
"<div class="" logo""=""><a href="" http:="" gihyo.jp="" (?=""><category>.*?)/serial/01/(?<s_id>.*?)""><img src="" (?=""><img>.*?)"".*?/></s_id></category></a></div>" )
For Each m As Match In matchs
Dim category = m.Groups("category" ).Value
Dim serialId = m.Groups("s_id" ).Value
Dim imgUrl = m.Groups("img" ).Value
Dim key = category & "/" & serialId
If Not SerialDictionary.ContainsKey(key) Then
Continue For
End If
Dim path = System.IO.Path.Combine(folder, serialId & ".png" )
Try
My.Computer.Network.DownloadFile(imgUrl, path)
Catch ex As Exception
End Try
SerialDictionary(key).LogoPath = path
Next
Next
End Sub
画像のURLを取得後、ダウンロードもしています。
以上で、必要な情報はすべて抽出・取得できました。これらの情報をクリップボードに書き出し、Excelのシートにペーストできるようにしましょう。次のメソッドをGetImageメソッド呼出し後に、Mainメソッドから呼び出します。
Private Sub SetText()
Dim sb = New System.Text.StringBuilder
For Each s In SerialDictionary.Values
For Each a In s.Articles
sb.Append(s.LogoPath & vbTab)
sb.Append(a.Title & vbTab)
sb.Append(a.Uri.ToString & vbTab)
sb.Append(s.Category & vbTab)
sb.Append(s.Id & vbTab)
sb.Append(a.Author & vbTab)
sb.Append(a.Date.ToString & vbCrLf)
Next
Next
My.Computer.Clipboard.SetText(sb.ToString)
End Sub
これでタブ区切りのテキストデータができました。このままPivotのコレクションシートにはペーストできませんので、Excelのブックを作成し一時的に別のシートにペーストします。そこから画像パス列部分とそれ以外の部分をわけて、Pivotのコレクションシートにペーストします。すると図13 のようになります。
図13 gihyo.jp 連載記事コレクションの作成
Facet Categoryの名前も設定しています。また、日付の列はセルの値を日付形式にする必要があります。連載IDの値はキーワードフィルタリング時のみ利用できるようにしました。
さて、Publish Collectionボタンをクリックすればコレクションの完成です。大量の画像を生成する必要があるため、コレクションの生成にはそれなりの時間を要します(筆者の環境では1アイテム0.1秒程度でした) 。その間はExcelの操作ができなくなりますので注意しましょう。正しく抽出できていないところがあれば、コレクションの作成に失敗やPivotで表示が反映されません。適当な値を入力するかアイテムを削除するかで対応しましょう。
以下にコレクションの表示結果を示します。
図14 結果1
図15 結果2
その他のコレクションの作成
今回は、Excelのアドインを使用しましたが、頻繁にコレクションの内容が更新される場合、今回のように人手による作業は非常に手間になります。そのような特性を持つコレクションは、CXMLもDeep Zoom形式の画像もプログラムから生成するのが望ましいでしょう。
プログラムからCXMLの作成は、それほど難しいものではありません。実際に生成されたXMLファイルやPivotのWebサイトを確認しながら作成できると思います。また、Pivot Collection Tools for Pivot by Live Labs というクラスからPivot用のコレクションファイルを生成しようとしているオープンソースプロジェクトも登場しています。こちらも参考になるかもしれません。
Deep Zoom形式の画像生成は、自作するとなると少し手間かもしれませんが情報やツール、ライブラリは豊富です。プログラムとの連携は難しいですが、GUIアプリケーションのDeep Zoom Composer もリリースされています。コマンドラインのツールや.NET Frameworkのライブラリも用意されており、こちらは参考になるのではないかと思います。Live Labs SeadragonのWebサイト からダウンロード可能です。また、このほかにもサードパーティ製のツールが同サイトのCreating Content で紹介されています。
Deep Zoom形式の画像生成には、時間とCPUパワーが必要です。現在のPivotの仕組みでは動的に画像自体が変化していくコレクションは対象に向いていません。コレクションのひとつ、ダイナミックコレクションも画像はあらかじめ生成しておき、XMLファイルのみ動的に生成することが想定されたものとなっていることに留意しておく必要があるでしょう。
おわりに
Live Labs Pivotについては今回で終了です。いかがでしたでしょうか。このプロジェクトが、この先どうなるかはわかりませんが、おもしろい分野でもあり、おもしろいアプリケーションでもあると思いますので、ぜひ実際にさわって、オリジナルのコレクションを作成してみてください。