この記事と関連の高い記事
関連キーワード:.NET関連キーワード:Java
「Javaと.NET、どっちがいいの?」 プログラミングの現場では、こんな質問に出会う場面もあるかもしれません。もちろん「絶対○○の方が優れてます!」なんてお気軽な答えはあるわけもありません1。筆者の場合は「それぞれの技術の特性から、得意分野、苦手分野がありますので、それを鑑みる必要がありますね。で、ここの仕様なんですが…」とさっくりと流して逃げるのが常套手段となっています。
サーバサイドで地歩を確立したJavaと、以前のVisual Basic開発者など、開発者数の大きさ等を考えると今後の拡大が見込まれる.NET、これからの進展がどうなっていくのかは興味が尽きません。さて、XMLに関してはどうでしょうか。
Java発表時(1995年)にはXML1.0はまだ存在しておらず、当然ながら標準ライブラリ等でXMLをサポートすることはできませんでした。それに対して.NETはXMLの普及期に発表されており、ライブラリの対応をはじめ、設定ファイルがすべてXML化されているなど、XMLとの結びつきが強い環境といえます。
しかし、JavaもXMLの普及を黙ってみているわけではありませんでした。XMLをサポートするためのXMLパーサやXSLTプロセッサが開発され、J2SE1.3からはXMLパーサ・XSLTプロセッサが付属するようになり、XMLを扱うための追加のライブラリは不要となりました。
さらに、ただXMLを読み書きできる、というだけではなく、データバインディングという技術も進歩していきました。今回はこのデータバインディングがテーマです。
データバインディングについて説明する前に、プログラミング言語でXMLにアクセスするための方法についてまとめておきましょう。主に以下の三つの方法があります2。
1.テキストファイルとして読み書き
XMLは単なるテキストファイルですから、文字コードにさえ注意を払えばどんなプログラミング言語からも特別なライブラリ無しに読み書きすることができます。しかし、テキストファイルとして扱いますので、XMLの持つ階層構造を生かすことはできず、プログラミングの効率は悪くなってしまいます。特別な理由がなければ、XMLをわざわざテキストファイルとして扱うメリットはありません。
2. DOM - XMLの構成要素(要素・属性・テキスト内容など)に対応するオブジェクトを介してアクセス
DOMは、XMLを読み込み、その木構造に対応するオブジェクトを介してアクセスする方法です。たとえば、XML文書全体に対してはDocumentというオブジェクトを、要素に対してはElementというオブジェクトを使ってアクセスします(表1)。DOMを使用すれば、XMLの階層構造にしたがってアクセスすることができますので、テキストファイルを直接読み書きする方法よりもずっと効率よくコードを記述することができます。
しかし、DOMはXMLのスキーマとは無関係に、ただXMLの構成要素を対応するオブジェクトに置き換えてくれるだけです。もし元のXMLがスキーマに基づいているのならば、スキーマを使用して少しでも楽をしたい、というのが本音ではないでしょうか。それがデータバインディングという方法です。
3. データバインディング - XMLのスキーマ(要素名・属性名・出現順序等)に基づいて定義されたオブジェクトを介してアクセス
データバインディングは、XMLのスキーマを読み込み、そのスキーマに対応するオブジェクトを生成する方法です。実際にはスキーマコンパイラというツールでスキーマからオブジェクトを定義するソースコードを生成します。そして、そのスキーマに基づくXMLインスタンスを読み込むと、対応するオブジェクトに変換してくれますので、そのオブジェクトを介してXMLの内容にアクセスすることができる、というわけです。
たとえば、DOMではどんな要素であってもElementオブジェクトを使用してアクセスする必要がありますが、データバインディングでは、要素名がそのままオブジェクト名になっており、子要素や属性はそのオブジェクトのプロパティとしてアクセスすることができます。DOMと比べると直感的で便利な方法ですが、もちろん弱点もあります。スキーマを元にしてオブジェクト定義を行う以上、スキーマの変更に弱い、という避けられない欠点です。ですが、頻繁にスキーマが変更されるので無ければ、お手軽にXMLを扱うことができますのでオススメです。
では、本題(Java vs .NET)に戻していきましょう。Java・.NETのどちらでもデータバインディング技術を使用することができます。
JavaではJAXB・Relaxer・Castor等のデータバインディングツールが存在し、DTD・XML Schema・Relax NG等からJavaのオブジェクト定義を出力することができます。CastorやRelaxerについては、ただオブジェクト定義を出力するだけでなく、リレーショナルデータベースとのマッピングを行うO/Rマッピング(Object / Relational Mapping : オブジェクトとRDBとの対応付け)機能も持っています。JavaのデータバインディングツールについてはDigitalXpressバックナンバーや参考URLをご参照ください3。
それに対して.NET上のデータバインディングツールとして、xsd.exeというツールが標準で存在します。これはXML SchemaからC#、VB.NET、J#、JScript.NETのソースコードを生成するツールです。また、XMLファイルを元にXML Schemaを生成する機能も持っており、XML Schemaが存在しないXMLでも使用することができます4。今回はこのxsd.exeを使って.NET(C#言語)でデータバインディングを試してみることにしましょう。
では、このデータバインディングを用いて何をしてみようか、というお題なのですが、最近の流行り物であるブログを扱ってみましょう。
ブログの語源はWebLog(Web上の日記的なサイト)にあるようで、略してblog、さらに最近はカタカナ化してブログと呼ばれています。厳密な定義は難しいのですが、他のニュース記事やサイトを紹介し、リンクを掲載するスタイルが流行っているようです。これまでのいわゆるホームページよりも簡単に更新が行え、テンプレートに従うだけで見栄えのよいサイトが作成できる辺りも人気の秘密かもしれません。有名人が自分のブログで日記を付けたりして、大変な人気を博したりもしていますね。
さて、このブログですが、RSS5という形式で記事の更新内容を出力するのが一般的になっています。RSSはXML形式のファイルで、ブログのタイトルやURL、記事のタイトルや内容が含まれていますので、このRSSを解析すれば、ブログサイトを見に行かなくても内容を読むことができます。最近では、RSSビューワと呼ばれるソフトがあり、RSSのURLを投稿しておけばそのソフトの中で複数のブログの更新記事を読むことができます。 RSSの内容は、たとえば以下のように書かれています(リスト1)。
リスト1:サンプル RSS 2.0の内容
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule">
<channel>
<title>D</title>
<description>よしなしごと</description>
<link>http://blogs.yahoo.co.jp/d_labo256</link>
<language>jp</language>
<image>
<title>D</title>
<url>http://img.yahoo.co.kr/blog/manage/banner_img01.gif</url>
<description>よしなしごと</description>
<link>http://blogs.yahoo.co.jp/d_labo256</link>
</image>
<item>
<title>執筆順調</title>
<description>何とか執筆のめどが立ってきました<br /> サンプルもどうにか間に合いそう…</description>
<link>http://blogs.yahoo.co.jp/d_labo256/636474.html</link>
<pubDate>Fri, 18 Mar 2005 02:38:04 +0900</pubDate>
<category>練習用</category>
</item>
<item>
<title>今日の日記</title>
<description>DigitalXpressの締め切りに追われております。<br /> 果たして間に合うのか?!?</description>
<link>http://blogs.yahoo.co.jp/d_labo256/636409.html</link>
<pubDate>Fri, 18 Mar 2005 02:33:09 +0900</pubDate>
<category>練習用</category>
</item>
</channel>
</rss>
ルート要素がrss要素で、その下にサイトに相当するchannel要素が存在し、その下に更新記事に相当するitem要素が存在する構造となっています。今回はこのRSSをASP.NET(言語はC#)でデータバインディングを使ってお手軽に6読み込み、更新内容をブラウザで表示する簡易RSSビューワを作ってみましょう。
まずはxsd.exeを使ってこのRSSファイルに相当するC#のオブジェクト定義を生成する必要があります。残念ながらRSS 2.0にはXML Schemaが存在しませんので、今回は一旦XMLファイルからXML Schemaを生成し、そこからC#のオブジェクト定義を生成しました。
1. XML Schemaの生成
まず、XML Schemaを生成するためのサンプルとなるRSSファイルをローカルにrss.xmlというファイル名で保存しておきます。xsd.exeはコマンドラインツールとなっています。実体はVisual Studio.NET 2003をデフォルトインストールしていればC:¥Program Files¥Microsoft Visual Studio .NET 2003¥SDK¥v1.1¥bin¥ にあるはずです。通常のコマンドプロンプトではパス指定が面倒ですので、あらかじめパスが指定されたスタートメニュー¥プログラム¥Microsoft Visual Studio.NET 2003¥Visual Studio.NETツール¥ Visual Studio.NET 2003 コマンド プロンプトを実行してください。その後RSSファイルを保存したフォルダへ移動し、以下のコマンドを実行します。
XML Schema出力コマンド
xsd.exeはオプションを指定せずにXMLファイルだけを指定すると、そのXMLファイルからXML Schemaを生成します。ここではrss.xsdが出力されます(リスト2)。
リスト2:出力されたRSSのXML Schema(rss.xsd)
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="rss">
<xs:complexType>
<xs:sequence>
<xs:element name="channel" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string" minOccurs="0" />
<xs:element name="description" type="xs:string" minOccurs="0" />
<xs:element name="link" type="xs:string" minOccurs="0" />
<xs:element name="language" type="xs:string" minOccurs="0" />
<xs:element name="image" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string" minOccurs="0" />
<xs:element name="url" type="xs:string" minOccurs="0" />
<xs:element name="description" type="xs:string" minOccurs="0" />
<xs:element name="link" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string" minOccurs="0" />
<xs:element name="description" type="xs:string" minOccurs="0" />
<xs:element name="link" type="xs:string" minOccurs="0" />
<xs:element name="pubDate" type="xs:string" minOccurs="0" />
<xs:element name="category" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="version" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="ja-JP">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element ref="rss" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
XMLファイルからXML Schemaを生成すると、データ型などは推測に基づいて決められますので、厳密なスキーマは生成されず、大半はxs:string型として処理されます。また、出現順序も本来の定義とは異なる可能性もあります。この段階で出力されたXML Schemaの内容を確認しておきましょう。
2. C#オブジェクト定義の生成
1.で定義したXML SchemaファイルからC#のオブジェクト定義を生成します。先ほどと同じようにVisual Studio.NET 2003 コマンド プロンプトを実行し、以下のコマンドを実行します。
オブジェクト定義出力コマンド
/c(/classes)オプションを指定すると、xsd.exeは指定されたXML Schemaファイルに基づくオブジェクト定義のソースコードを出力します。ここではrss.csファイルが出力されます(リスト3)。
リスト3:出力されたrssクラスのソースコード(rss.cs)
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version: 1.1.4322.2032
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
//
// このソース コードは xsd によって自動生成されました。Version=1.1.4322.2032 です。
//
using System.Xml.Serialization;
/// <remarks/>
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]
public class rss {
/// <remarks/>A
[System.Xml.Serialization.XmlElementAttribute("channel", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public rssChannel[] channel;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string version;
}
/// <remarks/>
public class rssChannel {
~~~中略~~~
}
/// <remarks/>
public class rssChannelImage {
~~~中略~~~
}
/// <remarks/>
public class rssChannelItem {
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string title;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string description;
~~~中略~~~
}
出力言語の切り替えは/l(/language)オプションで行います。デフォルトではC#言語で出力します7。
出力されたC#のソースコードを見ると分かるとおり、要素はC#のクラスに、子要素や属性はメンバ変数として定義されています。要素はどうやら階層構造に合わせて名前を連結しているようで、rss要素の子のchannel要素の子のitem要素はrssChannelItemクラスとして定義されています。XML Schemaと見比べると分かりますが、出現回数・順序等は特に反映されていません。ちなみにXMLの要素名が小文字で始まる場合、出力されたオブジェクト定義でもクラス名は小文字で定義されます8。
これで.NETのデータバインディングツールであるxsd.exeを用いてRSSに対応するオブジェクト定義を生成することができました。
さて簡易RSSビューワの製作に取りかかりましょう。ここではVisual Studio.NET 2003がインストールされていることを前提とします9。
1. ASP.NET Webアプリケーションプロジェクトの作成
まずはVisual Studio.NET 2003の新規プロジェクト作成でVisual C#プロジェクトのASP.NET Webアプリケーションを選択しましょう(図1)。
2. rss.csファイルのコピー
前項で生成したrss.csファイルをWebアプリケーションを作成した場所(デフォルトではC:¥Inetpub¥wwwroot¥{プロジェクト名})にコピーします。その後[ファイル]メニューから[既存項目の追加]を選び、rss.csファイルを選択してください。
3. Webフォームコントロールの配置
デフォルトのWebForm.aspxを開き、プロパティウィンドウでDOCUMENTを選択し、pageLayoutプロパティをFlowLayoutに設定します。これは、ボタンや文字を絶対座標ではなく、通常のHTMLと同様に上から下に順に描画されるようにするためです(図2)。
続いて、WebフォームツールボックスからTextBox , Button , Literalコントロールを順に貼り付けてください。それぞれ次のようにプロパティを設定します。
・TextBoxコントロール
(RSSのURLを入力するテキストボックス)
プロパティ名 | 値 |
Name | rssTextBox |
・Buttonコントロール(RSSを開くボタン)
プロパティ名 | 値 |
Name | openRSSButton |
Text | Open RSS |
・Literalコントロール
(RSSの内容を表示するための文字列コントロール)プロパティ名 | 値 |
Name | contentLiteral |
図3のような画面になるはずです。
4. クリックイベント処理記述
openRssButtonコントロールをダブルクリックし、クリックイベントを記述します。以下のようにイベント処理を記述します(リスト4)。
リスト4:クリックイベント処理記述
private void openRSSButton_Click(object sender, System.EventArgs e)
{
if(rssTextBox.Text != "")
{
XmlReader xmlreader = new XmlTextReader(rssTextBox.Text);
XmlSerializer serializer = new XmlSerializer(typeof(rss));
rss rss1 = (rss)serializer.Deserialize(xmlreader);
contentLiteral.Text = "";
foreach(rssChannel channel in rss1.channel)
{
contentLiteral.Text += "<p>";
contentLiteral.Text += "<a href=¥"" + channel.link + "¥">" + channel.title + "</a><br/>";
contentLiteral.Text += "<b>" + channel.description + "</b><br/>";
contentLiteral.Text += "</p>";
foreach(rssChannelItem item in channel.item)
{
contentLiteral.Text += "<hr/>";
contentLiteral.Text += "<b>" + item.title + "</b><br/>";
contentLiteral.Text += item.description + "<br/>";
}
}
}
}
幾つかのライブラリを使用していますので、C#ファイルの先頭のusingを記述している箇所に以下の3行を追加してください。
using System.Xml;
using System.Xml.Serialization;
using System.IO;
5. 実行
これで簡易RSSビューワは完成です。早速実行してみましょう。RSSのURLを入力するテキストボックスと、RSSを開くボタンが表示されるはずです(図4)。
ここでテキストボックスにRSSのURL (たとえばhttp://blogs.yahoo.co.jp/d_labo256/rss.xml) を入力すると、RSSを読み込み、以下のように内容を表示します(図5)。
さて、処理内容を確認しましょう。
1. XmlReaderオブジェクトの生成
rssTextBoxに入力されたURLから、XMLを読み込むためのXmlReaderオブジェクトを生成します10。
2. XmlSerializerオブジェクトの生成
XMLをデータバインディングで定義したオブジェクトに変換するためのXmlSerializerオブジェクトを生成します。この際、XmlSerializerのコンストラクタにxsd.exeで出力されたrss.csクラスで定義されているrssクラスを渡しています。こうすることで、「これから読み込むXMLファイルはrssクラスに対応するものですのできちんと変換してくださいね」と教えているわけです。
3. rssオブジェクトの取得
RSSのURLからXMLファイルを読み込み、rssクラスのオブジェクトに変換します。 XmlSerializer.Deserializeメソッドはobject型を返しますので、rssクラスへキャストします。
もちろんRSSの定義に合わないファイル(正確には、rss.csで記述されたオブジェクト定義に合わないXMLファイル)だった場合は、変換することができず、例外が送出されます。
ここまでの3行でデータバインディング処理は終わってしまいました。お手軽っぷりが味わえたのではないでしょうか。後は通常のC#のオブジェクトですので、好きなように料理してあげましょう。
4. ブログのタイトル・URL・内容表示
foreach(rssChannel channel in rss1.channel)contentLiteralは文字を表示するためのコントロールで、ここに出力したい文字を流し込んでいます11。まずforeach文12を用いてrss要素の子要素のchannel要素を順番に処理します。channel要素以下のlink要素・title要素・description要素をcontentLiteralオブジェクトに出力しています。ソースコードを見れば分かるとおり、子要素へのアクセスは通常のメンバ変数へのアクセスとして記述されているため、非常にシンプルです。
5. 更新記事のタイトル・内容出力
foreach(rssChannelItem item in channel.item)再び我が愛しのforeach文を使って、今度は更新記事に相当するchannnel要素の下のitem要素を順番に処理します。hrタグを用いて記事間に線を引き、item要素の子要素のtitle要素・description要素を出力しています。やはり通常のメンバ変数へのアクセスですので直感的ですね。
ここまででひとまず簡易RSSビューワ完成としておきましょう。もちろんエラー処理や他の細々した処理を入れなければ実用的ではありませんが。今はタイトルと内容しか出力していませんが、更新時間を出力するように、また、更新内容すべてを1ページで表示してしまうのではなく、1ページ1記事表示とし、次の記事に移動するリンクを表示するようにしてもいいかもしれません。そうすれば携帯から読むのにも便利ですね。
今回はxsd.exeを使ってASP.NETで簡易RSSビューワを作成してみました。実際のコーディング量が非常に短いことに気づかれたことでしょう (なんと20行弱) 。xsd.exeを使えば、特定のスキーマに基づくXMLを扱う.NETアプリケーションの構築が格段に楽になります。
筆者はJavaでJAXBを使ってXMLを扱うちょっとしたユーティリティを作ることがありますが、複数種類の子要素があった場合などは、xsd.exeの方がメンバ変数として簡単に扱えるため、最近ではC#でユーティリティを作る事が増えています13。是非皆さんも.NETでのデータバインディングに触れてみてください。 JavaでJAXBやRelaxerがあるように、.NETにはxsd.exeがあるんだ!と声を大にして14宣伝していきましょう。
今回の記事ではRSS 2.0を対象としましたが、世の中には幾つかのRSSのバージョンが存在します。おまけにこれらのバージョンが必ずしも上位互換・下位互換となっていないところがまた泣き所です。
基本的にはRSS 0.91 , RSS 1.0 , RSS 2.0の3つのバージョンで大体のブログサイトのRSS出力を受け付けることができるでしょう。参考までにYahoo!ブログ、gooブログの対応するRSSバージョンと、対応するURLを示しておきます。
■ Yahoo!ブログ RSS 2.0(標準)/ RSS 1.0 / RSS 0.91対応
RSS 2.0 http://blogs.yahoo.co.jp/{ブログ名}/rss.xml
http://blogs.yahoo.co.jp/{ブログ名}/rss2.xml
RSS 1.0 http://blogs.yahoo.co.jp/{ブログ名}/rss1.xml
RSS 0.91 http://blogs.yahoo.co.jp/{Yahoo!ID}/rss091.xml
■ gooブログ RSS 1.0 / RSS 2.0 対応
http://blog.goo.ne.jp/{ブログ名}index.rdf
今回はRSS 2.0のみに対応する記事でしたが、他のバージョンのRSSについても、やはり同様にxsd.exeを使用してスキーマ生成・C#コード生成を行えば簡単に対応できると思います。是非試してみてください。