「サイト名 > archive > 2002年 > 五月の日記」。このようなパン屑ナビゲーションは、一説によるとdiv要素であり、あるいはul、li要素であると言われており、「p要素派」は宗教家扱いされています。しかしながら、整形結果やメディアを意識することなく、制作された文書ありのままをハイパーテキストとしてマークアップするという立場からすれば、そもそも「パン屑ナビゲーション」なる物自体、登場する余地の無いものです。
製作者は、パン屑ナビゲーションで一体何を伝えようとしているのでしょうか。多くの場合、サイト内におけるその文書の位置付けを示そうとしていると考えられます。つまりこうです。
あるいは:
このような文(センテンス)を「media="screen"」向けに表現したものが「パン屑ナビゲーション」であると考えるわけです。だとすれば、その表現とやらにはCSSが推奨されるべきであり、当然この文自体はp要素としてマークアップされるべきということになります。
パン屑ナビゲーションは、例えば「media="aural"」向けには意味不明で、ほとんど使い物になりません。
HTMLソースは例えばこのようになります。
これをそのまま「パン屑ナビゲーション」として整形するには、CSS2は非力です。非表示になる部分等をspan要素として明示しなければなりません。
CSS2の欠点は、セレクタを、ノードではなく要素としてしか指定できない事でしょうか。拡張の難しい独特の構文を用いているのも欠点かもしれません。仮にセレクタをXPathのロケーションパスで指定できたなら、この文をパン屑ナビゲーションに整形する事は容易でした。
さて、CSS2の欠点といえばもう一つ挙げられます。画像オブジェクトとテキストを置換する方法が無いことです。このような目的を達成するために、製作者はimg要素を用いなければなりません。
前述の例におけるspan要素を、img要素に置き換えてみます。
某N社がでっち上げたこのimg要素の醜悪な性質により、このマークアップは残念ながら妥当ではありません。次のように修正しなければなりません。
テキストはalt属性に移し、img要素自体は空要素になりました。お粗末。
それぞれのimg要素のsrc属性に、矢印アイコンのURIを示せば完成です。最後のimg要素は、「現在地」というアイコンにします。但し、透過処理をしてしまうとCSSの変更などに制約を加える事になります。このような用途にimg要素を用いるのはあまり良い方法では無いのかもしれません。
パン屑ナビゲーション等の「オブジェクト」は、可能ならばまずその目的をストレートに文章で表現し、その整形をCSS等に任せるならば、「はじめにテキストありき」のハイパーテキスト文書に融和させることが可能です。そしてそのようなアプローチが結果としてアクセシビリティの向上につながる事もあり得ます。
このような一見まわりくどいことをする目的は、アクセシビリティを向上させる事ではなく、「文書そのものを如何に自然に(あるいは必然性を持ったハイパーテキストとしてマークアップするか」を追求する事です。そのアプローチが多くを改善する事を私は知っています。
あるウェブページfoo.htmlでは、foo.cssという外部CSSスタイルシートを利用し、そのウェブページの補足ページbar.htmlにおいては、foo.css、及び、bar.cssの二つのCSSスタイルシートを利用するというケースがあるとします。
foo.htmlは、foo.xsl内の次のようなXSLTテンプレートによってlink要素が出力されています。
<!-- foo.xsl内 -->
<xsl:template name="CSS">
<link rel="stylesheet" href="foo.css" />
</xsl:template>
bar.htmlには、foo.cssの他にbar.cssも埋め込みたいので、このテンプレートを次のように「上書き」しました。
<!-- bar.xsl内 -->
<xsl:import href="foo.xsl" />
<xsl:template name="CSS">
<link rel="stylesheet" href="foo.css" />
<link rel="stylesheet" href="bar.css" />
</xsl:template>
しかしこれはテンプレートを一から再定義しているに過ぎません。
しかし結果ツリーフラグメントをグローバル変数にバインドする方法なら、インポートした側で結果ツリーフラグメントを拡張する事が出来ます。
<!-- foo.xsl内 -->
<xsl:variable name="CSS">
<link rel="stylesheet" href="foo.css" />
</xsl:variable>
<!-- bar.xsl内 -->
<xsl:import href="foo.xsl" />
<xsl:variable name="CSS">
<xsl:copy-of select="$CSS" />
<link rel="stylesheet" href="bar.css" />
</xsl:variable>
グローバル変数の場合、内容が最初に一度だけ評価され、内部ではまだ自分自身を参照する事が出来ませんが、それらを利用しています。
インポート優先順位の低いグローバル変数を参照する場合、エラーになるともならないとも書かれていないというだけで、何と言うかグレーゾーンなんですけどね。
テンプレートの拡張には、xsl:apply-imports要素があるではないかと思われるかもしれません。しかしこれは名前付きテンプレートの拡張、言い換えると、静的な結果ツリーフラグメントの拡張には使えないのです。
拡張したいテンプレートがmatch属性を持っているなら、xsl:apply-imports要素が使えます。パラメータを渡す事が出来ないので、どちらにしろあまり魅力的ではないですけれども。
note::memo XSLTに関する記事内、XSLTでフラットな文書を構造化で公開されている構造化スタイルシートを見ていて、私も人様に使ってもらえそうな形にしておこうと思い立ちました。茨の道なので実際あまり薦められる物でもないのですが。
気をつけた点は以下の通りです。
<xsl:include href="このXSLTファイルのURIまたはパス" />
<xsl:stylesheet xmlns:jtr="http://purl.org/jintrick/2003/XSLT" />
<xsl:apply-templates select="/child::*/child::h1" mode="jtr:Structuring" />
h2レベルから構造化を開始させることも出来ます。
<xsl:apply-templates select="/child::*/child::h2" mode="jtr:Structuring" />
特定のセクションのみを構造化することも出来ます。
<xsl:apply-templates select="/child::*/child::h3[string(@id) = 'foo']" mode="jtr:Structuring" />
h7要素とかh8要素、h100要素(理論上)にも対応しています。XHTML2.0に変換できるようにするためです。
<xsl:apply-templates select="/child::*/child::h7" mode="jtr:Structuring" />
*見出しのindexは正の整数である必要があります。0や-1、1.5等は不可。
見出し以外を含むノード集合をカレントノードリストにして、mode="jtr:Structuring"でapply-templatesしないで下さい。とんでもないエラーになります。
<xsl:apply-templates select="child::p" mode="jtr:Structuring" />
*これは絶対にやらないで下さい。mode="jtr:Structuring"にしなければ問題ありません。見出しがXML名前空間を持っていても可。例えばソース文書がXHTMLでもOK。
<xsl:apply-templates select="/child::xht:html/child::xht:body/child::xht:h1" mode="jtr:Structuring" />
全ての見出しはある共通の要素の子供(child)でなければなりません。
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>EX</title></head>
<body>
<h1 />
<h2 />
<h3 />
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>EX</title></head>
<body>
<h1 />
<div>
<h2 />
<div>
<h3 />
</div>
</div>
</body>
</html>
※後者の例は最初から構造化されているので、このスタイルシートを
使う意味はありません。前者の例のようなものを後者の例のように変
換するのがこのスタイルシートです。
各ノード(要素、属性等)についての変換ルールは別途用意する必要があります。
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:apply-templates select="child::node()|@*" />
</xsl:element>
</xsl:template>