agenda 2003-05(下旬) S curse

パン屑ナビはパラグラフかも

公開
2003年5月28日

「サイト名 > archive > 2002年 > 五月の日記」。このようなパン屑ナビゲーションは、一説によるとdiv要素であり、あるいはul、li要素であると言われており、「p要素派」は宗教家扱いされています。しかしながら、整形結果やメディアを意識することなく、制作された文書ありのままをハイパーテキストとしてマークアップするという立場からすれば、そもそも「パン屑ナビゲーション」なる物自体、登場する余地の無いものです。

パン屑ナビは何を伝えるものか

製作者は、パン屑ナビゲーションで一体何を伝えようとしているのでしょうか。多くの場合、サイト内におけるその文書の位置付けを示そうとしていると考えられます。つまりこうです。

  • 「Home」より、「archive」、「2002年」、とリンクを辿ると、この文書、「五月の日記」に行き着きます。

あるいは:

  • この文書「五月の日記」の目次は「2002年」、その目次は「archive」、ホームページは「サイト名」です。

このような文(センテンス)を「media="screen"」向けに表現したものが「パン屑ナビゲーション」であると考えるわけです。だとすれば、その表現とやらにはCSSが推奨されるべきであり、当然この文自体はp要素としてマークアップされるべきということになります。

パン屑ナビゲーションは、例えば「media="aural"」向けには意味不明で、ほとんど使い物になりません。

CSSを用いた解

HTMLソースは例えばこのようになります。

  • <p><a href="/">Home</a>より、<a href="../../archive/">archive</a>、<a href="../2002/">2002年</a>、とリンクを辿ると、この文書、五月の日記、に行き着きます。</p>

これをそのまま「パン屑ナビゲーション」として整形するには、CSS2は非力です。非表示になる部分等をspan要素として明示しなければなりません。

  • <p><a href="/">Home</a><span>より、</span><a href="../../archive/">archive</a><span>、</span><a href="../2002/">2002年</a><span>、とリンクを辿ると、この文書、</span>五月の日記<span>、に行き着きます。</span></p>

CSS2の欠点は、セレクタを、ノードではなく要素としてしか指定できない事でしょうか。拡張の難しい独特の構文を用いているのも欠点かもしれません。仮にセレクタをXPathのロケーションパスで指定できたなら、この文をパン屑ナビゲーションに整形する事は容易でした。

CSSを用いぬ解

さて、CSS2の欠点といえばもう一つ挙げられます。画像オブジェクトとテキストを置換する方法が無いことです。このような目的を達成するために、製作者はimg要素を用いなければなりません。

前述の例におけるspan要素を、img要素に置き換えてみます。

  • <p><a href="/">Home</a><img>より、</img><a href="../../archive/">archive</a><img>、</img><a href="../2002/">2002年</a><img>、とリンクを辿ると、この文書、</img>五月の日記<img>、に行き着きます。</img></p>

某N社がでっち上げたこのimg要素の醜悪な性質により、このマークアップは残念ながら妥当ではありません。次のように修正しなければなりません。

  • <p><a href="/">Home</a><img alt="より、" /><a href="../../archive/">archive</a><img alt="、" /><a href="../2002/">2002年</a><img alt="、とリンクを辿ると、この文書、" />五月の日記<img alt="、に行き着きます。" /></p>

テキストはalt属性に移し、img要素自体は空要素になりました。お粗末。

それぞれのimg要素のsrc属性に、矢印アイコンのURIを示せば完成です。最後のimg要素は、「現在地」というアイコンにします。但し、透過処理をしてしまうとCSSの変更などに制約を加える事になります。このような用途にimg要素を用いるのはあまり良い方法では無いのかもしれません。

まとめ

パン屑ナビゲーション等の「オブジェクト」は、可能ならばまずその目的をストレートに文章で表現し、その整形をCSS等に任せるならば、「はじめにテキストありき」のハイパーテキスト文書に融和させることが可能です。そしてそのようなアプローチが結果としてアクセシビリティの向上につながる事もあり得ます。

追記

このような一見まわりくどいことをする目的は、アクセシビリティを向上させる事ではなく、「文書そのものを如何に自然に(あるいは必然性を持ったハイパーテキストとしてマークアップするか」を追求する事です。そのアプローチが多くを改善する事を私は知っています。

結果ツリーフラグメントの拡張(XSLT1.0)

公開
2003年5月25日

あるウェブページ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

テンプレートの拡張には、xsl:apply-imports要素があるではないかと思われるかもしれません。しかしこれは名前付きテンプレートの拡張、言い換えると、静的な結果ツリーフラグメントの拡張には使えないのです。

拡張したいテンプレートがmatch属性を持っているなら、xsl:apply-imports要素が使えます。パラメータを渡す事が出来ないので、どちらにしろあまり魅力的ではないですけれども。

フラットな文書を構造化 その2

公開
2003年5月16日

note::memo XSLTに関する記事内、XSLTでフラットな文書を構造化で公開されている構造化スタイルシートを見ていて、私も人様に使ってもらえそうな形にしておこうと思い立ちました。茨の道なので実際あまり薦められる物でもないのですが。

気をつけた点は以下の通りです。

  • モジュールとして使える形にしました。
  • 競合が起こらないように、mode名に名前空間をつけました。
  • XHTML2.0に変換できるよう、見出しレベルは無制限にしました。
  • 任意のレベルのセクションから構造化を開始できるようにしました。
  • ソース文書が名前空間を持っていても変換可能にしました。
  • フラットでさえあれば、階層レベルを問わないようにしました。
  • 変換結果の構造が「見える」よう、工夫しました。

structuring.xslの使い方

  1. このXSLTファイルをインクルードします。例:
    <xsl:include href="このXSLTファイルのURIまたはパス"     />
  2. インクルードしたXSLTファイルのルート要素で、名前空間 http://purl.org/jintrick/2003/XSLT を宣言します。例:
    <xsl:stylesheet xmlns:jtr="http://purl.org/jintrick/2003/XSLT"     />
  3. 構造化を展開したい任意のテンプレート内の任意の位置で、ルート要素直下のh1要素達をカレントノードリストにしつつ、mode属性を jtr:Structuring にしてapply-templatesします。例:
    <xsl:apply-templates select="/child::*/child::h1" mode="jtr:Structuring"     />

注意点など

h2レベルから構造化を開始させることも出来ます。

例:○
<xsl:apply-templates select="/child::*/child::h2" mode="jtr:Structuring"     />

特定のセクションのみを構造化することも出来ます。

例:○ id属性値が「foo」のh3のセクションのみ構造化
<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)でなければなりません。

例:○ (全てbody要素の子供になっている)
<html xmlns="http://www.w3.org/1999/xhtml">
	<head><title>EX</title></head>
	<body>
		<h1     />
		<h2     />
		<h3     />
	</body>
</html>
例:× (h1の親とh2の親、h3の親がそれぞれ違う)

<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>