SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

CGI不可のサーバでもできるAjaxによるHTMLの動的な整形

Ajaxを利用したデータとプレゼンテーションの分離

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (12.9 KB)

表示コンテンツの切り替え

 多くのWebサイトの基本的なレイアウトは、上下左右にメニューやリンクなど、サイトの情報などを表示するスペースを設け、中央に記事などのコンテンツを表示する形になっています。特に、Blogやニュースなど、多くの記事を短い間隔で更新し続ける場合に有効なデザインだと思います。

 こうしたボックス型のレイアウトを実現する方法にHTMLのframeset要素がありますが、framesetを用いる場合はフレーム用のHTMLと、フレーム表示するそれぞれのHTMLを個別に用意しなければなりません。さらにHTMLファイルが分離されるため、依存関係などの管理にも注意が必要です。次のサンプルを見てください。

sample02 test.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp">
 <frameset cols="20%,80%">
  <frame src="left.html" name="left" />
  <frame src="001.html" name="center" />
 </frameset>
</html>

 これは、古い時代のWebから使われてきたフレームを用いたレイアウトの例です。表示するHTMLは「test.html」とは別に用意しなければなりません。左側のフレームには「left.html」ファイルを表示し、右側のフレームには「001.html」を表示します。左側のフレームはリンク項目などのツール的な機能を提供し、右側のフレームに主となるコンテンツを表示します。

 しかし、この方法にはいくつかの問題があります。

 例えば、記事の量が増え続け、HTMLファイルが数千にも達した後で、すべての記事の基本的な雛型を変更したくなった場合です。すべての記事の末尾に、著作権を表すCopyrightの一文を追加する必要があるとします。すべての記事のHTMLヘッダやソースのレイアウトが共通していたとしても、ファイル数が多ければ大変な作業になります。記事の数が数千であれば、置き換えツールを使ったとしても気楽な仕事ではありません。

 困ったことに、雛形の変更は珍しいことではありません。HTMLからXHTMLの時代に移行したときはxml宣言を付け加える必要がありました。記事がリンクするCSSやJavaScriptの名前を変更したいといったこともあるかもしれませんし、すべての記事の上部に宣伝用のバナーを付け加えたいということもあるかもしれません。

 また、フレーム分割はブラウザによって行われるため、ブラウザがフレーム分割に対応していない場合なども問題となるでしょう。技術的な制約でフレーム分割を使いたくない場合もあります。

 BlogシステムやWikiなど、サーバー側スクリプトやデータベースを使うことができるWebアプリケーションであれば、スクリプトが実行時に必要な情報を集め、雛型にコンテンツを埋め込んでHTMLを返すことができます。ですが、趣味でサイトを運用したいと考えている方にとっては敷居が高いものでしょう。

 Ajaxを用いれば、サーバー側スクリプトを使うことができないレンタルサーバーでも、雛型にコンテンツを埋め込むことができます。最初に、記事などのコンテンツを抜いたHTMLページの雛型を作成し、ここにJavaScriptを書きます。JavaScriptから、Ajaxの技術を用いて主となるコンテンツをダウンロードし、DOMを使ってHTMLページにダウンロードしたコンテンツを表示するという仕掛けになります。

sample03 test.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp">
 <head>
  <title>test</title>
  <script type="text/javascript">
function createRequest() {
 var req = null;
 if ("XMLHttpRequest" in window) {
  req = new XMLHttpRequest();
 }
 else if ("ActiveXObject" in window) {
  try {
   req = new ActiveXObject("Msxml2.XMLHTTP");
  }
  catch (e) {
   try {
    req = new ActiveXObject("Microsoft.XMLHTTP");
   }
   catch (e) {}
  }
 }

 return req;
}

var req;
function requestText(url) {
 req = createRequest();

 req.open("GET", url, true);
 req.onreadystatechange = req_readystatechange;
 req.send(null);
}

function req_readystatechange() {
 var divRightPanel = document.getElementById("rightPanel");
 if (req.readyState == 4) {
  if (req.status == 200) {
   divRightPanel.innerHTML = req.responseText;
  }
  else {
   divRightPanel.innerHTML = "システムエラー:読み込めませんでした";
  }
 }
}
  </script>
 </head>

 <body>
  <table border="0">
   <tr><td style="width:20%" valign="top">
    <p><a href="javascript:requestText('001.txt')">はじめに</a></p>
    <p><a href="javascript:requestText('002.txt')">Ajaxとは</a></p>
   </td>
   <td style="width:80%" valign="top">
    <div id="rightPanel"></div>
   </td></tr>
  </table>
 </body>
</html>

 sample03の「test.html」は、sample02のようなレイアウトをAjaxを応用して実現したHTMLページです。このHTMLファイル自体がサイトの重要な雛型として機能し、記事などのコンテンツはリンクをクリックするとrightPanelというIDを与えているdiv要素上に表示されます。sample02と比較して、ハイパーリンクをクリックしてもページ移動が発生しないことに注目してください。JavaScriptが内部でサーバーにファイルを要求し、ダウンロードしています。

 createRequest()関数は、Ajaxの中枢であるXMLHttpRequestオブジェクトを生成して返します。requestText()関数は、url引数に指定したアドレスに要求を行います。URLは相対アドレスでもかまいません。通常、ブラウザのセキュリティによって異なるホストへのアクセスは禁止されているため、通常は相対アドレスで十分でしょう。

 req_readystatechange()は、XMLHttpRequestオブジェクトのonreadystatechangeプロパティに設定するための関数です。この関数は、サーバーから応答があった時に呼び出されます。req_readystatechange()関数内で、データが完全にダウンロードされたかどうかを調べ、完全にデータがダウンロードされた時点でresponseTextプロパティから単純な文字列としてダウンロードしたデータを取得しています。

 HTMLページに埋め込まれる記事は、HTMLファイルとは別の「001.txt」と「002.txt」ファイルに用意しています。例えば、「001.txt」ファイルの内容は次のようになっています。

sample03 「001.txt」抜粋
<h1>はじめに</h1>
<p>
ここ最近、Web 2.0という言葉と共にクライアント側の...(略)
</p>
<p>
では、Ajaxはそれほど敷居の高いものなのでしょうか。
質の高い開発集団や、高額な開発環境、またはサーバーなどの...(略)
</p>

 本文は長くなるため省略していますが、HTMLの部品となるテキストであることが確認できます。HTML要素やヘッダなどの情報が含まれていないため、これ自体は不完全なHTMLです。「test.html」ファイルのスクリプトに読み込まれ、div要素のrightPanelに埋め込まれることが前提となっています。

 この構造であれば、記事の本文をHTMLの全体の構造と切り離すことができ、柔軟にページのレイアウトを変更することができます。

設定ファイル

 sample03は、XMLHttpRequestオブジェクトを使ったスクリプト内部によるダウンロードと、DOMによるHTMLの構造の動的な変更という、Ajaxの基礎的な技術を応用したサンプルです。しかし、数千の記事を扱うサイトの場合はリンクの部分が大きな問題となります。

 sample03は、HTMLのbody要素内に直接a要素を書いています。これは、参照する記事が2つだけだったので手書きで十分でしたが、数千という記事を参照するリンクを何の構造化を行うこともなく、手書きで用意するのは非効率的です。

 こうした問題を解決するには、参照するファイルの情報などを記した設定ファイルを用意するといった方法があるでしょう。設定ファイルは、HTMLソースとは分離して用意し、XMLHttpRequestでダウンロードして使います。例えば、設定ファイルにサイトマップなどの情報を書き込み、スクリプトが設定情報を分析してリンクを含むHTMLに変換するという方法があります。

 設定ファイルのフォーマットはXMLが最適です。XMLHttpRequestオブジェクトには、ダウンロードしたデータをDOMで定められているDocumentオブジェクトとして返すresponseXMLプロパティがあります。Documentオブジェクトの詳細はDocument Object Model Specificationsを参照してください。

 設定ファイルをXML形式で記述し、JavaScript+DOMでデータを読み込む方法であれば、設定情報を解析する専用のパーサーを開発する必要はありません。

sample04 test.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp">
 <head>
  <title>test</title>
  <script type="text/javascript">
function createRequest() {
 var req = null;
 if ("XMLHttpRequest" in window) {
  req = new XMLHttpRequest();
 }
 else if ("ActiveXObject" in window) {
  try {
   req = new ActiveXObject("Msxml2.XMLHTTP");
  }
  catch (e) {
   try {
    req = new ActiveXObject("Microsoft.XMLHTTP");
   }
   catch (e) {}
  }
 }

 return req;
}

var req;

function init() {
 var divLeftPanel = document.getElementById("leftPanel");

 req = createRequest();
 req.open("GET", "setup.xml", false);
 req.send(null);

 var doc = req.responseXML;
 var setup = doc.getElementsByTagName("setup")[0];
 var docsList = setup.childNodes;

 for(var i = 0 ; i < docsList.length ; i++) {
  var docs = docsList.item(i);
  if (docs.nodeType == 1 && docs.nodeName == "documents") {
   var from = docs.getAttribute("from");
   var to = docs.getAttribute("to");
   var prefix = docs.getAttribute("prefix");
   var suffix = docs.getAttribute("suffix");
   var title = docs.getAttribute("title");

   divLeftPanel.innerHTML += "<p>【" + title + "】<br/>";
   for(var j = from ; j <= to ; j++) {
    divLeftPanel.innerHTML +=
     "<a href=\"javascript:requestText('" + prefix + j + suffix + "')\">"
      + j + "</a> ";
   }
   divLeftPanel.innerHTML += "</p>";
  }
 }
}

function requestText(url) {
 req = createRequest();

 req.open("GET", url, true);
 req.onreadystatechange = req_readystatechange;
 req.send(null);
}

function req_readystatechange() {
 var divRightPanel = document.getElementById("rightPanel");
 if (req.readyState == 4) {
  if (req.status == 200) {
   divRightPanel.innerHTML = req.responseText;
  }
  else {
   divRightPanel.innerHTML = "システムエラー:読み込めませんでした";
  }
 }
}
  </script>
 </head>

 <body onload="init()">
  <table border="0">
   <tr><td style="width:20%" valign="top">
    <div id="leftPanel"></div>
   </td>
   <td style="width:80%" valign="top">
    <div id="rightPanel"></div>
   </td></tr>
  </table>
 </body>
</html>
sample04 setup.xml
<?xml version="1.0" encoding="UTF-8"?>
<setup>
 <documents from="0" to="1" prefix="ajax" suffix=".txt" title="Ajax入門" />
 <documents from="0" to="4 prefix="c" suffix=".txt" title="C入門" />
</setup>

 sample04は、sample03をさらに発展させ、左側の領域に表示されるリンクの生成を自動化させたものです。sample03で左側に表示されているハイパーリンクはHTMLソースに直接書き込まれていたものですが、sample04は「setup.xml」に書かれている情報からスクリプトに自動生成させています。

 「setup.xml」は、設定情報を格納するXMLファイルです。この設定情報のルート要素にはsetupを指定するものとし、setupの子要素には記事などの連続的なファイル情報をまとめるdocuments要素を指定するものとします。documents要素には、開始番号をfrom属性に、終了番号をto属性に指定します。連続的な記事の主題をtitle属性に指定するものとします。

 prefixにはファイル接頭辞、suffixには接尾辞を指定します。例えば、「article0.txt」~「article20.txt」までの連続的な記事がある場合は、fromに0、toに20、prefixにarticle、suffixに.txtを指定することになります。

<documents from="0" to="20"
 prefix="article" suffix=".txt" title="記事の名前" />

 スクリプトでは、これらの属性情報を受け取ってprefix+ファイル番号+suffixという形で参照するURLを作っています。

 コンテンツの管理を行い、リンクなども自動生成してくれるサーバー側スクリプトに比べると、設定ファイルを書くという作業が余分に発生していますが、リンクのすべてをHTMLファイルで管理することに比べれば、こうしたAjaxを応用した手法で簡略化する方法も選択の1つかと思います。

次のページ
HTMLからの脱却

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

赤坂 玲音(アカサカ レオン)

平成13年度「全国高校生・専門学校生プログラミングコンテスト 高校生プログラミングの部」にて最優秀賞を受賞。2005 年度~ Microsoft Most Variable Professional Visual Developer - Visual C++。プログラミング入門サイト WisdomSoft の管理人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1015 2007/03/02 00:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング