概要
ブログっぽいものを作成。
一般に“ブログ”と呼ばれてるようなものほどちゃんとしたツールを作るつもりはなくて、 以下のような仕様のものを。
-
Web フォーム自体に書き込み機能は持たせない。
-
記事は、ローカル上で(XML 形式で)書いたものを FTP などでサーバにアップする。
-
記事は、20070630.xml というように、日付に応じて yyyyMMdd.xml 形式のファイル名で保存。
-
日付に応じた XML を XSLT して表示するだけ。
-
トラックバック機能はおろか、コメント機能すら作らない。
今どき、ブログのデータは(記事、コメント、トラックバック含め全部)データベースに持つのがいいと思うんですが、 自分のサイトにそこまでの機能が必要ないのと、 過去に自分の書きためてるものが XML 形式だったのでこういう仕様に。
技術的な面でいうと、ここで説明する内容は以下の通り。
-
Web コントロール
-
XSLT
-
クエリ文字列
-
HTTP リクエストのリライト・リダイレクト
-
RSS の作成
長く成りそうなので、3つに分割。 このページではまず、最新の日付のブログを表示するところまで。 技術面で言うと、1 と 2 を説明。
仕様
ブログもどきの仕様ですが、以下のような感じ。
-
XML 形式で保存しておいたデータを読んで、XSLT を掛けた結果を表示するだけ。
-
コメント機能もトラックバック機能もなし。
-
XML は、2007年7月1日のブログなら 20070701.xml というように、 yyyyMMdd.xml という形式のファイル名を付ける。
以下のような XML データに対して、 図1のような結果を表示します。
<?xml version="1.0" encoding="Shift_JIS"?>
<content>
<blog>
<p>
全く会話をしないまま1日が過ぎた。
見た目がカタい人間にうつるからかもしれないと思い、
馬車内で今日は兜をかぶらなかった。
</p>
<p>
誰もそれに気付かないようだった。
</p>
</blog>
</content>
ちなみに、ここで使った XSL スタイルシートはこんな感じ → main.xsl。 XSL “Transformation” と言うほど賢い処理はしていなくて、 ほとんど HTML タグを素通ししてるだけ。
で、以下のような3つの Web フォームを作ります。
-
BlogLatest.aspx … クエリ文字列で「何日前か」を指定してブログを表示。
-
BlogDate.aspx … クエリ文字列で日付を指定してブログを表示。
-
BlogSelect.aspx … ページ中にドロップダウンリストやカレンダーコントロールを配置して、日付を選択してブログを表示。
また、これらの3つのページの共通部品として、 XML に XSLT を掛けた物を表示するだけの Web コントロールを作ります。
Web コントロールの作成
Web コントロールというのは、 asp:Button や asp:Label などのように、 Web フォームページ中に配置する部品です。 System.Web.UI.UserControl を継承したクラスを作ることで自作することも可能です。
ここでは、 「仕様」で説明したような用途向けに、 XML 形式のデータを読み込んで、XSLT を掛けたものを表示するコントロールを作ってみます。
Web コントロール(拡張子 .ascx)の作り方は Web フォーム(.aspx)とほとんど同じです。 違いは、<%@ Page %> の変わりに <%@ Control %> ディレクティブを使うことと、 コードビハインド中のクラスの継承元が Page クラスから UserControl クラスに変わることです。
Visual Studio を使う場合、 ソリューションエクスプローラから、 [追加]→[新しい項目]→[Web ユーザコントロール] を選ぶことで雛形を作ってもらえます。
で、XML 表示コントロールですが、 まず、ascx ファイル中に、XSLT 結果を表示するための <div> タグを配置しておきます。 (ファイル名は ShowXml.ascx としておきます。)
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="ShowXml.ascx.cs" Inherits="WebsiteSample.ShowXml" %>
<div runat="server" id="content" />
コードビハインド側は以下のような感じ。 (例外処理とかはサボっています。)
using System;
using System.Web;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using System.Text;
namespace WebsiteSample
{
public partial class ShowXml : System.Web.UI.UserControl
{
#region プロパティ
string xmlFileName = null;
public string XmlFileName
{
get { return xmlFileName; }
set { xmlFileName = value; }
}
string xslFileName = null;
public string XslFileName
{
get { return xslFileName; }
set { xslFileName = value; }
}
#endregion
protected void Page_PreRender(object sender, EventArgs e)
{
if (this.xmlFileName == null || this.xslFileName == null
|| !File.Exists(this.xmlFileName)
|| !File.Exists(this.xslFileName)
)
return;
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(this.XslFileName);
XmlDocument xml = new XmlDocument();
xml.Load(this.xmlFileName);
XmlNodeReader reader = new XmlNodeReader(xml);
MemoryStream s = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(s, Encoding.UTF8);
xslt.Transform(reader, writer);
s.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(s);
string result = sr.ReadToEnd();
this.content.InnerHtml = result;
s.Dispose();
}
}
}
XML のファイル名と XSL のファイル名を public なプロパティにしておきます。 ShowXml コントロールを使う側では、これらのプロパティにファイル名を指定して使います。
XML がらみの処理自体は、System.Xml 名前空間中のクラスを使って XML / XSLT の処理をしているだけなので、 詳しくは System.Xml や System.Xml.Xsl あたりのヘルプを参照してください。 XSLT 結果は、単純に <div id="content" /> の InnerHtml として表示します。
1つ注意が必要なのは、 表示処理を行っているイベントが、 今までよく使っていた Page_Load ではなく、 Page_PreRender なことです。
ASP.NET の処理の順番は、 Page_Load → プロパティの値の設定 → Page_PreRender の順番になっているようで、 Page_Load に処理を書いても、プロパティの値の設定結果が反映されません。
ちなみに、ASP.NET にはデータテンプレートという、 XML やデータベース中から取り出してきたデータを任意の形式で表示するための機構が用意されてたりするんで、 (使い方次第ではあるけど)そちらを使ってみることも推奨。
Web コントロールの利用
前節で作った XML 表示コントロールを使って、 ブログデータを表示する Web フォームを作ってみます。 とりあえず、まず最初に、 最新の日付のブログを表示するだけの物を作って見ます。
まず、 ブログデータや XSL ファイルですが、 App_Data フォルダに格納する事にします。
自作した Web コントロールの使い方ですが、 以下のようになります。
-
<%@ Register %> でコントロールを登録。
-
登録したコントロールをページ中に配置。
自作した XML 表示コントロール(ファイル名 ShowXml.ascx)を使うなら、 aspx ファイル中に以下のように書きます。
<%@ Page Language="C#"
MasterPageFile="~/Site.Master" AutoEventWireup="true"
CodeBehind="BlogLatest.aspx.cs" Inherits="WebsiteSample.BlogLatest"
Title="日記" %>
<%@ Register TagPrefix="local" TagName="ShowXml" Src="~/ShowXml.ascx" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div class="blogHead">
<asp:Label runat="server" ID="head" />
</div>
<local:ShowXml runat="server" ID="xmlContent" />
</asp:Content>
で、最新の記事を表示したいなら、 コードビハインドファイルは以下のようにします。
using System;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;
namespace WebsiteSample
{
public partial class BlogLatest : System.Web.UI.Page
{
internal static Regex yyyyMMdd =
new Regex(@"(\d{4})(\d{2})(\d{2})\.xml");
protected void Page_Load(object sender, EventArgs e)
{
string basePath = Context.Server.MapPath("~/App_Data");
string[] files = Directory.GetFiles(basePath, "*.xml");
Array.Sort(files);
string xmlFile = files[files.Length - 1];
string xslFile = basePath + @"\main.xsl";
this.xmlContent.XmlFileName = xmlFile;
this.xmlContent.XslFileName = xslFile;
Match match = yyyyMMdd.Match(xmlFile);
if (match.Success)
{
this.head.Text = string.Format("{0}年{1}月{2}日",
match.Groups[1],
match.Groups[2].ToString().TrimStart('0'),
match.Groups[3].ToString().TrimStart('0'));
}
}
}
}
やっていることは、 App_Data フォルダ中から最新の日付の XML ファイルを探してきて、 それを ShowXml コントロールの XmlFileName プロパティに渡しているだけです。 (20070701.xml とかいう形式でデータを保存しているので、 ファイル名でソートすればそれがそのまま日付順でのソートになる。)
ついでに、日付を <asp:Label ID="head"> 中に表示。