Cocoon2 チュートリアル (後編)
概要
前編では Cocoon の概要および Cocoon プログラミングについて説明しました。後半では Cocoon によるプログラミングの応用例として Sapid の SPIE (Source Program Information Explorer) の Cocoon 版である SPIECE (Source Program Information Explorer - Cocoon Edition) について説明します。
SPIE
SPIE は、クロスリファレンス情報をWebページとして表示するソフトウェアです。まず SPIE の構成について簡単に説明 します。
SPIEの例はこちらで参照できます。

SPIEでは上図のような画面分割のためにフレームを用いています。各フレームの中は XML + XSLT で表示されています。 XML と XSLT はクライアントサイドに送られているため、XSLT の適用はクライアントサイドで行われます。

SPIECEの構成
ここではSPIECEの構成についての外観について説明します。
SPIE のようにフレームで表示するのではなく、サーバサイドで一枚のHTMLとして生成し、クライアントに返すようにします。
フレームの代わりにテンプレートを作成し、部品を作成し埋め込んでいきます。テンプレートをXSPで作成し、埋め込み作業をXSLT で行います。各部品は別のpipelineでXMLとして生成します。このため、SPIECEのpipelineは2段になっています。
以下のような pipeline で実現します。

以降はSPIECEのソースコードを見て行きます。
SPIECEの詳細
まずsitemap.xmapにおけるpipelineの断片を示します。
<map:match pattern="**/index.html">
<map:generate type="serverpages" src="index.xsp"/>
<map:transform src="xslt/spie.xsl">
<map:parameter name="use-request-parameters" value="true"/>
</map:transform>
<map:serialize type="html"/>
</map:match>
<map:match pattern="**/spie-index.xml">
<map:generate src="{1}/spie-index.xml"/>
<map:transform src="xslt/spie-index.xsl">
<map:parameter name="use-request-parameters" value="true"/>
</map:transform>
<map:serialize type="xml"/>
</map:match>
<map:match pattern="**/spec-*.xml">
<map:generate src="{1}/spec-{2}.xml"/>
<map:transform src="xslt/spec.xsl">
<map:parameter name="use-request-parameters" value="true"/>
<map:serialize type="xml"/>
</map:match>
<map:match pattern="**/list-*.xml">
<map:generate src="{1}/list-{2}.xml"/>
<map:transform src="xslt/list.xsl">
<map:parameter name="use-request-parameters" value="true"/>
</map:transform>
<map:serialize type="xml"/>
</map:match>
上図で説明したように4つのpipeline定義で構成されています。
まず"**/index.html"は各ディレクトリのindex.htmlが要求された場合の定義です。"**"はディレクトリを またがってマッチする0文字以上の文字列を表します。
index.xspはテンプレート代わりに利用し、spie.xslで他のpipelineに対してXMLを要求して埋め込みます。
テンプレート代わりに使っているindex.xspを見てみましょう。
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR
/xhtml1/DTD/xhtml1-frameset.dtd">
<xsp:page language="java"
xmlns:xsp="http://apache.org/xsp"
xmlns:xsp-request="http://apache.org/xsp/request/2.0">
<body>
<xsp:logic>
String url = <xsp-request:get-requested-url/>;
url = url.substring(0, url.lastIndexOf("/"));
</xsp:logic>
<url><xsp:expr>url</xsp:expr></url>
<div style="position:fixed; height: 400px">
<include name="category"/>
<div style="overflow: auto; height: 100%; max-width:14em" >
<include name="list"/>
</div>
</div>
<div style="margin-left: 14em">
<include name="spec"/>
</div>
</body>
</xsp:page>
include要素が埋め込む場所です。XSLTでinclude要素の位置にXMLを埋め込んでいきます。
埋め込み役のspie.xslを見てみましょう。
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsp-request="http://apache.org/xsp/request/2.0"
xmlns:xsp="http://apache.org/xsp"
xmlns:html="http://www.w3.org/1999/xhtml"
version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="no"
doctype-public="-//W3C//DTD XHTML 1.0 Traditional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:param name="category"/>
<xsl:param name="list"/>
<xsl:param name="spec"/>
<xsl:template match="/">
<html>
<head>
<meta name="robots" content="noindex,nofollow" />
<title>SPIE: Program: test </title>
<link rel="stylesheet" href="SPIE.css" type="text/css" />
<!--link rel="stylesheet" href="new.css" type="text/css" /-->
</head>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="url">
</xsl:template>
<xsl:template match="include">
<xsl:variable name="context" select="//url/text()"/>
<xsl:variable name="category_path"
select="concat($context,
'/',
$category,
'?category=',
$category,
'&list=',
$list,
'&spec=',
$spec)"/>
<xsl:variable name="list_path"
select="concat($context,
'/',
$list,
'?category=',
$category,
'&list=',
$list,
'&spec=',
$spec)"/>
<xsl:variable name="spec_path"
select="concat(
$context,
'/',
$spec,
'?category=',
$category,
'&list=',
$list,
'&spec=',
$spec)"/>
<xsl:choose>
<xsl:when test="@name='category'">
<xsl:copy-of select="document($category_path)/html:html/html:body/*"/>
<br/><br/>
</xsl:when>
<xsl:when test="@name='spec'">
<xsl:copy-of select="document($spec_path)/html:html/html:body/*"/>
</xsl:when>
<xsl:when test="@name='list'">
<xsl:copy-of select="document($list_path)/html:html/html:body/*"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
変換するのはinclude要素だけなので最後の規則では、include要素以外はそのままコピーします。
include要素に対する変換ではinclude要素のname属性に対応してXMLの生成要求をもう一度投げそれを埋め込みます。
このときパラメータで生成するXMLを指定しています。
まとめ
前編・後編を通してCocoonの概要から応用までを説明しました。XMLを使ってWebアプリケーションを作成する場合、 Cocoonは非常に有力なフレームワークです。ぜひ一度Cocoonを自分でさわってみて、その強力さを実感してみてください。
by Ryo SUETSUGU


