2006 年 9 月 28 日 23 時 22 分

XSL #4: テンプレートを書く


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


いよいよ、テンプレートを書いてみよう。
RSS 2.0 からの変換を行うので、
<channel> と <item> に着目してルールを書くことにする。

元の XML は以下の通り。
http://loafer.jp/mixi/diary/rss.xsp

========== simple.xsl ==========
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

    <xsl:output
        method="html"
        doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
        doctype-system="http://www.w3.org/TR/html4/loose.dtd"
    />

    <xsl:template match="channel">

        <html>
            <head>
                <title>
                    <xsl:value-of select="title" />
                </title>
            </head>
            <body>
                <h1>
                    <a href="{link}">
                        <xsl:value-of select="title" />
                    </a>
                </h1>
                <p>
                    更新日: <xsl:value-of select="pubDate" />
                </p>

                <xsl:apply-templates select="item" />

                <hr />
                <address>
                    <xsl:value-of select="copyright" />
                </address>
            </body>
        </html>

    </xsl:template>

    <xsl:template match="item">

        <hr />
        <h2>
            <a href="{link}">
                <xsl:value-of select="title" />
            </a>
        </h2>
        <p>
            <xsl:value-of select="description" />...<br />
            (<small><xsl:value-of select="pubDate" /></small>)
        </p>

    </xsl:template>

</xsl:stylesheet>
========== end of simple.xsl ==========

定義するのは 2 つのテンプレートだけだ。
さて、XSLT の処理を順に考えていこう。

最初にルートノードがカレントノードに選択されて開始する。
ルートノードに対するテンプレートは定義していないため、
既定のテンプレートによって処理されることになる。

ルートノードや要素の既定テンプレートは
<xsl:apply-templates /> のみなので、
子ノードが順にカレントノードとなって処理される。
ここでは、rss 要素がそれに該当する。

rss 要素もテンプレートが定義されていないので、
上と同様、channel 要素に処理が移る。

channel 要素にはテンプレートが定義されているため、
<xsl:template match="channel"> で処理される。
このテンプレートには HTML の要素が含まれるので、
channel 要素はこれらに変換されて出力される。

<title>~</title> の内容としては、
<xsl:value-of select="title" /> と指定している。
XSLT の value-of 要素は、指定した値を文字列化する。

select 属性は XPath 式であり、"title" は
カレントノード(channel 要素)の直接の子供である
title 要素全てを選択したことになる。

これを value-of で文字列化すると、
該当ノードが複数ある場合でも、最初のノードだけが選ばれ、
その要素の子孫のテキストノードを全て連結した内容となる。

言い換えれば、最初に見つかった title 要素の内容から、
タグやコメント等を全て取り除いたものということだ。

次に出てくるのは、<a href="{link}"> だ。
これは、カレントノードの子の link 要素が文字列化され、
a 要素の href 属性の値として出力される。

XSLT では、属性に対して特別な処理を行う。
中括弧 {} で囲んだ内容は XPath 式として評価され、
その結果を文字列化したものに展開されるのだ。
このお陰で、属性値の出力も簡単に行うことができる。

その後には、<xsl:value-of select="title" /> が
再度出現するが、ここでも titie 要素が文字列化される。
基本的に value-of はそれぞれ独立して処理されるため、
必要であれば、何度でも同じ要素を選択することができる。

更新日: <xsl:value-of select="pubDate" /> や、
後ろにある <xsl:value-of select="copyright" /> も、
基本的には同じような方法で展開される。

そして、<xsl:apply-templates select="item" /> だ。
apply-templates は、子ノード全てに対して、
処理を継続(伝播)する命令だが、
select 属性で XPath 式を指定した場合、
それらで示されたノードだけ処理することが可能だ。

select="item" とあるため、
直接の子の全ての item 要素だけが処理されることになる。
ここでもし select 属性を省略した場合、
item 以外の要素などにもテンプレート処理が及んでしまう。

現在のカレントノードは、channel 要素である。
channel 要素は、item だけでなく、
pubDate、link、copyright などの要素も持つ。

link や pubDate は別の部分で使っており、
それら子要素を、この場所に展開する必要はないので、
select 属性を明示して処理させないのである。

つまり、このテンプレートの場合、
channel 属性の子供である language 属性は、
value-of 等で利用もされず、
apply-templates で選択されることもないため、
完全に無視されることになる。

さて、apply-templates は、item 要素を順に選択し、
それぞれをカレントノードとしてノード処理を行い、
その結果をこの部分に展開して出力する。

item 要素にはテンプレートが定義されているため、
各 item 要素は、<xsl:template match="item">
に従って処理されることになる。

item 要素用のテンプレートには目新しいところはない。
<a href="{link}"> や、
<xsl:value-of select="title" /> は上と同じだ。
カレントノードは item 要素なので、
これらは、item 要素の直接の子要素である、
link や title のことを指す。

item 要素のテンプレートには、
apply-templates 要素が含まれないため、
value-of などで利用している物を除き、
item 要素の子孫要素はノード変換されないことになる。

item 要素のノード処理内容は、それを呼び出した
channel 要素の apply-templates の場所に出力され、
channel 要素のテンプレート処理に戻ることになる。


上記の XSLT を反映するとこういう風になる。

http://loafer.jp/mixi/diary/rss.xsp?simple.xsl

単純なレイアウトではあるが、
XML の状態よりははるかに見やすくなった。
ソースを表示しても、元の XML のままだが、
レイアウト上は、HTML っぽいのは明らかだ。
つまり、XSLT によって HTML に変換されているのである。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.