/another/another0002.xml back up
コンテンツによって多少の構造の違いがありますが、サイト内のXSLファイルはだいたい同じ親子関係の要素で構造化されています(そうしないとソース書き間違えるため)。HTML要素が含まれますが、ソースの1行目を見ても分かるとおりこれはXML文書です。このページの解説はXMLファイルを作成したことがあるという程度のスキルをお持ちであることを前提としています。
このサイトでは、doc_div要素が所有する子要素を全て(たとえデータがnullであっても)常にソースに書き込んでいます。これはテンプレートをコピー&ペーストで貼り付け楽をするため、そして他のフォーマットへの変換を視野に入れ汎用性を持たせるためです。しかしnullなデータでファイル容量を冗長させる欠点があります。
例としてhpディレクトリのファイルを採りあげます。XSLTはXML文書を様々なフォーマットに変換するプログラムです。ここではブラウザで表示するために、HTMLへの変換をしていますが、PDFや(仕様さえあれば)独自規格などにも変換可能です。HTMLに変換する場合XSL命令文をHTML要素の間に埋め込みます。ディスプレイの横幅の制限上、ソースは推奨される位置とは違う美しくない位置で改行されています。
01 <?xml version="1.0" encoding="UTF-8"?> 02 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 03 <xsl:template match="/"> 04 <html> 05 <head> 06 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 07 <title> 08 <xsl:value-of select="file_root/head_group/head_title"/> 09 </title> 10 <link rel="stylesheet" media="screen" href="hoge.css" /> 11 </head> 12 <body> 13 <div class="dir"> 14 <xsl:value-of select="file_root/head_group/head_dir_add"/> 15 </div> 16 <h2> 17 <xsl:value-of select="file_root/doc_group/doc_header2" /> 18 </h2> 19 <p class="nippon"> 20 <xsl:value-of select="file_root/doc_group/doc_info" /> 21 </p> 22 <xsl:for-each select="file_root/doc_group/doc_src"> 23 <h3> 24 <xsl:value-of select="doc_header3" /> 25 </h3> 26 <xsl:for-each select="div_group/doc_div"> 27 <p class="nippon"> 28 <xsl:value-of select="division" /> 29 <xsl:if test="anchor_group/anchor_href[.!='']"> 30 <span class="small"> 31 <xsl:element name="a"> 32 <xsl:attribute name="href"> 33 <xsl:value-of select="anchor_group/anchor_href" /> 34 </xsl:attribute> 35 <xsl:attribute name="target"> 36 _<xsl:value-of select="anchor_group/anchor_window" /> 37 </xsl:attribute> 38 <xsl:value-of select="anchor_group/anchor_text" /> 39 </xsl:element> 40 </span> 41 </xsl:if> 42 <xsl:if test="img_group/img_src[.!='']"> 43 <xsl:element name="img"> 44 <xsl:attribute name="src"> 45 <xsl:value-of select="img_group/img_src" /> 46 </xsl:attribute> 47 <xsl:attribute name="alt"> 48 <xsl:value-of select="img_group/img_alt_text" /> 49 </xsl:attribute> 50 <xsl:attribute name="width"> 51 <xsl:value-of select="img_group/img_width" /> 52 </xsl:attribute> 53 <xsl:attribute name="height"> 54 <xsl:value-of select="img_group/img_hight" /> 55 </xsl:attribute> 56 </xsl:element> 57 </xsl:if> 58 </p> 59 <xsl:if test="pre_group/pre_text[.!='']"> 60 <pre> 61 <xsl:value-of select="pre_group/pre_text" /> 62 </pre> 63 </xsl:if> 64 </xsl:for-each> 65 </xsl:for-each> 66 </body> 67 </html> 68 </xsl:template> 69 </xsl:stylesheet>
プログラム上意味のないテキスト及びXSL変換と関係のないHTML要素は省略しています。hpディレクトリのXSLファイルとは同一ではありません。XSL命令はHTMLと混同しないようにTABキーでインデントをつけて区別してあります。逆にHTML部分はインデント0です。
このXSLソースでXML+XSLTの理解度が判明します。私は入門書をかじった程度ですので、上のソースは素人同然です。本物のXSLソースを見るとプログラムの出来の違いに恥ずかしくなります。(じゃあ晒すな と)
厳密に言うとXSLとXSLTは別物です(=「XSLでトランスフォームするものがXSLT」ではないということ)。XSLもXSLTもともにXMLを人に理解しやすい形に変換するものという意味で同義ですが、XSLがXMLのスタイルシート役に限定されているのに対して、後から別プロジェクトで定義されたXSLTは広範囲なXMLの変換プロセッサです。XSLはXMLの見栄えを変えるもの、XSLTはXMLデータを抽出し別のフォーマットに変えるもの、といえます。ですからせっかくのXSLTをXSLに埋め込むということは、XSLTの機能を限定させてしまっているのではないでしょうか。本当はもっと便利な使い道”も”あるのでは?でもその”も”の部分が勉強不足で分かりません。(重ねて言うことになりますが)そこら辺からも私のスキルの限界がにじみ出ています。
本題に戻って以下からは各行のソースコードの解説をします。
このXSL(XSLもXMLファイル)のXML宣言文です。
<?xml version="1.0" encoding="UTF-8"?>
XSLTのルート要素です。XSLTのバージョンとXSLTの名前空間の使用を宣言します。名前空間を宣言しているので、XSLTでは自分で任意の要素名をつけても機能しません。(付けていけない訳ではありませんが解釈されません。)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
xsl:template要素です。xsl:template要素は、xsl:stylesheet要素がただ2つ持つだけことができる直下の子要素の内の1つです。matchが属性で「/(とそれ以下の要素)にマッチするもの」という意味で、参照元のXMLデータ用ファイルの「階層判断の基点をルート要素にします」と解釈します。
<xsl:template match="/">
xsl:value-of要素です。xsl:value-of要素は、参照元XMLデータファイルの「file_root/head_group/head_title」で選択(select)された階層の要素のデータを代入します。ここではHTMLのtitle要素の「要素の内容」になります。「file_root/head_group/head_title」はHTMLのハイパーリンクで使用される相対パスに似ている指定方法です。前項で指定されたルート要素からの階層をスラッシュで区切り指定します。これだけ見ると絶対パスのような気もしますが、実際はXSLT命令文が階層構造を持った場合、子要素の命令文では親要素で指定された階層以下のみ書かないとエラーになるので「相対パスに似ている」としました。(詳しくは後述)
<xsl:value-of select="file_root/head_group/head_title"/>
ふたたびxsl:value-of要素です。参照元XMLデータファイルの「file_root/head_group/head_dir_add」で選択(select)された階層の要素のデータを代入します。ここではその前後行にあるdiv要素の「要素の内容」になります。
<xsl:value-of select="file_root/head_group/head_dir_add"/>
またxsl:value-of要素です。参照元XMLデータファイルの「file_root/doc_group/doc_header2」で選択(select)された階層の要素のデータを代入します。ここではその前後行にあるh2要素の「要素の内容」になります。xsl:value-ofは空要素なので(XHTMLの経験があれば分かると思いますが)要素の最後をスラッシュで閉めます。
<xsl:value-of select="file_root/doc_group/doc_header2" />
くどいぐらいにxsl:value-of要素です。参照元XMLデータファイルの「file_root/doc_group/doc_info」で選択(select)された階層の要素のデータを代入します。ここではその前後行にあるp要素の「要素の内容」になります。xsl:value-of要素はテキストなどのデータを代入するので、XMLファイルがデータ用である限りもっとも使用頻度が高くなります。
<xsl:value-of select="file_root/doc_group/doc_info" />
xsl:for-each要素です。参照元XMLデータファイルの「file_root/doc_group/doc_src」で選択(select)された階層の要素が続く限り、xsl:for-each要素が所有する子要素のXSLT命令文を繰り返します。
<xsl:for-each select="file_root/doc_group/doc_src"> ・・・ </xsl:for-each>
xsl:value-of要素です。これはxsl:for-each要素の子要素です。参照元XMLデータファイルの「doc_header3」で選択(select)された階層の要素のデータを代入します。ここでselectされた階層の表現方法を見ると、相対パスに似ているという前述の表現の意味が分かります。xsl:for-each要素の子要素なのでxsl:for-each要素で指定された階層「file_root/doc_group/doc_src」までは解釈されていて後はdoc_srcの子要素以下を書けばよいとなるわけです。よって「doc_header3」で良いことになります。
<xsl:value-of select="doc_header3" />
xsl:for-each要素です。先ほどのxsl:for-each要素は段落(セクション)を繰り返すためのもの、これは文章部分(doc_div)を繰り返すための繰り返し命令です。前項と同様に前にある別のxsl:for-each要素の子要素となっているので相対的な階層指定方法になります。別のxsl:for-each要素の子要素となることで、ここでは文章を繰り返しつつ段落も繰り返す仕組みを生んでいます。
<xsl:for-each select="div_group/doc_div"> ・・・ </xsl:for-each>
要素自体の親子関係とselect属性の階層を共に正しくしなければ正常に繰り返されません。
xsl:value-of要素です。これは26行目のxsl:for-each要素の子要素です。参照元XMLデータファイルの「division」で選択(select)された階層の要素のデータを代入します。階層を初めから辿ると「file_root/doc_group/doc_src(22行目)」+「div_group/doc_div(26行目)」+「division(28行目)」になります。
<xsl:value-of select="division" />
xsl:if要素です。「test="anchor_group/anchor_href[.!='']"」部分でif条件をテストしています。この場合「anchor_group/anchor_href」の階層の要素がnullでないなら、以下を実行せよという命令になります。「[.!='']」がnot nullを意味しています。XSLTの関数は奥が深く、現在様々なサイトで解説されているので参照してみてください。
<xsl:if test="anchor_group/anchor_href[.!='']"> ・・・ </xsl:if>
xsl:element要素です。elementという言葉からも分かるとおり、要素を生成するための命令文です。(要素とはtagではないと、気の利いたHTML入門書なら必ず書いてある、アレです。)name属性で生成したい要素を指定します。ここでは「name="a"」なのでHTMLのancher要素を生成します。
<xsl:element name="a"> ・・・ </xsl:element>
xsl:attribute要素です。xsl:attribute要素は、xsl:element要素の子要素で、xsl:element要素で指定したHTML要素の属性を生成します。指定はname属性「name="href"」で行います。ここではHTMLのancher要素の属性hrefを生成しています。33行目のxsl:value-of要素でhref属性値を代入します。
<xsl:attribute name="href"> <xsl:value-of select="anchor_group/anchor_href" /> </xsl:attribute>
xsl:attribute要素です。ここではHTMLのancher要素の属性targetを生成しています。36行目のxsl:value-of要素でtarget属性値を代入します。36行目の初めに「_(アンダーバー)」が付いているのは、このWEBサイトではframeを使わないので、target属性はデフォルトで存在する属性値しか使用しないためです。frameを使う場合は、任意のtarget属性値を入力するのでアンダーバーはXSLTソースではなく参照元XMLデータファイルのanchor_window要素に書くことになります。
<xsl:attribute name="target"> _<xsl:value-of select="anchor_group/anchor_window" /> </xsl:attribute>
xsl:value-of要素です。参照元XMLデータファイルのanchor_text要素の値を代入します。ここではリンクスイッチ用のテキストになります。
<xsl:value-of select="anchor_group/anchor_text" />
xsl:if要素です。先ほどはHTMLのancher要素を生成するかどうかの条件式でしたが今回のテスト先は参照元のXMLデータファイルのimg_src要素です。前述と同様にnullでないなら子要素を実行します。XSLTにif文ではelseはありません。2分岐させたい場合には別の命令文があります(xsl:choose等)。
<xsl:if test="img_group/img_src[.!='']"> ・・・ </xsl:if>
xsl:element要素です。先ほどはHTMLのa(ancher)要素を生成しましたが今回はHTMLのimg要素を生成します。先ほどと同様にxsl:attribute要素で属性を生成していきます。なおHTMLのimg要素が空要素であるため38行目のようなただのテキストデータは必要ありません。
<xsl:element name="img"> <xsl:attribute name="src"> <xsl:value-of select="img_group/img_src" /> </xsl:attribute> <xsl:attribute name="alt"> <xsl:value-of select="img_group/img_alt_text" /> </xsl:attribute> <xsl:attribute name="width"> <xsl:value-of select="img_group/img_width" /> </xsl:attribute> <xsl:attribute name="height"> <xsl:value-of select="img_group/img_hight" /> </xsl:attribute> </xsl:element>
xsl:if要素です。テスト先は参照元のXMLデータファイルのpre_text要素です。前述と同様にnullでないなら子要素を実行します。今回の場合は、pre_text要素に値があれば60〜62行目を実行します。任意インデントが付けられるプログラムソース表示用としてよく使われるHTMLのpre要素です。nullではないという条件には、「改行」や「スペース」も含みますから参照元のXMLデータファイルでは「<pre_text></pre_text>」のように完全にnullな要素の内容にしなければ無意味な行が表示されます。
<xsl:if test="pre_group/pre_text[.!='']"> <pre> <xsl:value-of select="pre_group/pre_text" /> </pre> </xsl:if>