ブログっぽいものを作成。
一般に“ブログ”と呼ばれてるようなものほどちゃんとしたツールを作るつもりはなくて、 以下のような仕様のものを。
今どき、ブログのデータは(記事、コメント、トラックバック含め全部)データベースに持つのがいいと思うんですが、 自分のサイトにそこまでの機能が必要ないのと、 過去に自分の書きためてるものが XML 形式だったのでこういう仕様に。
技術的な面でいうと、ここで説明する内容は以下の通り。
長く成りそうなので、3つに分割。 このページではまず、最新の日付のブログを表示するところまで。 技術面で言うと、1 と 2 を説明。
ブログもどきの仕様ですが、以下のような感じ。
以下のような 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 フォームを作ります。
また、これらの3つのページの共通部品として、 XML に XSLT を掛けた物を表示するだけの 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 やデータベース中から取り出してきたデータを任意の形式で表示するための機構が用意されてたりするんで、 (使い方次第ではあるけど)そちらを使ってみることも推奨。
前節で作った XML 表示コントロールを使って、 ブログデータを表示する Web フォームを作ってみます。 とりあえず、まず最初に、 最新の日付のブログを表示するだけの物を作って見ます。
まず、 ブログデータや XSL ファイルですが、 App_Data フォルダに格納する事にします。
自作した Web コントロールの使い方ですが、 以下のようになります。
自作した 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"> 中に表示。