5.目次の自動生成
指定されたディレクトリに存在するファイルのタイトルを読み出し、目次を自動的に生成します。タイトルを読み出されるファイルは、XML文章である必要があります。
<?xml-stylesheet type="text/xsl" href="sample.xsl"?> <html> <head> <title>5.目次自動生成</title> </head> <body> <h1>5.目次自動生成</h1> <p> 対象ファイルに<title>が存在すれば、その内容が目次に表示されます。 </p> <p style="background-color:#eeeeee; padding:5px;"> <cdoe> <![CDATA[ <index path="..." sub="..." filename="..."/> ]]> </cdoe> </p> <dl> <dt>path</dt><dl>目次に載せるファイルがあるフォルダの (変換元ファイルから見た)相対パス</dl> <dt>sub</dt><dl>サブフォルダも検索するか否か。yesかnoで指定</dl> <dt>filename</dt><dl>目次に載せるファイルのファイル名</dl> </dl> <p> <index path="../" sub="yes" filename="*.xml"/> </p> </body> </html>
<index>を一つ書くだけで、目次が自動的に生成されます。
| 属性名 | 説明 |
| path | 目次に載せるファイルがあるフォルダの(変換元ファイルから見た)相対パス。 |
| sub | サブフォルダも検索するか否か。yesかnoで指定。 |
| filename | 目次に載せるファイルのファイル名。 |
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0"> <!-- リンク先切り替え用 --> <xsl:import href="../3/app2.xsl"/> <!-- パス関係用 --> <xsl:import href="../4/app1.xsl"/> <!-- 出力モード --> <xsl:output method="html" encoding="Shift_JIS"/> <!-- 処理命令は無視 --> <xsl:template match="processing-instruction()"/> <xsl:template match="processing-instruction('xml-stylesheet')"> <xsl:apply-imports/> </xsl:template> <!-- ノードや属性はそのまま出力 --> <xsl:template match="@*|node()" priority="-1.0"> <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> </xsl:template> <!-- 目次自動生成 --> <msxsl:script language="JScript" implements-prefix="xmlns"> // ファイルのリストを文字列で返す function initIndex(nodeList) { var node = nodeList.item(0); // 検索するファイルネーム var fileName = node.getAttribute("filename"); if(!fileName) fileName = "*.*"; // ファイルネームにディレクトリ名がくっついているなら外す fileName = fileName.replace(/^.*\\/, ""); // サブフォルダを参照するか否か var sub = node.getAttribute("sub")=="yes"; // 検索するフォルダ var path = node.getAttribute("path"); path = path.replace(/(?:\/|\\)$/, ""); if(!path) path=""; // ファイルを検索してリストを作成する。 var list = findFile(path, fileName, sub, ""); // 「,」で繋いで返す。 return list.join(","); } // ファイルを検索して配列で返す function findFile(path, fileName, sub) { // ファイル操作オブジェクト var fso = new ActiveXObject("Scripting.FileSystemObject"); // ファイル名リスト var list = new Array(); // 検索対象のフォルダ var folder = fso.GetFolder(getLocalPath(path)); // フォルダのファイルを列挙する for(var e=new Enumerator(folder.Files); !e.atEnd(); e.moveNext()) { var file = e.item(); if(checkWildcard(fileName, file.Name)) { // 指定されたファイルネームである。 // リストに追加 list.push(path+"/"+file.Name); } } // サブフォルダの検索をするか? if(sub) { // サブフォルダを検索する。 for(var e=new Enumerator(folder.SubFolders); !e.atEnd(); e.moveNext()) { var folder = e.item(); // サブフォルダ内のファイルのリストを作成し、 // 現在のリストと結合する。 var list2 = findFile(path+"/"+folder.Name, fileName, sub); list = list.concat(list2); } } // リストを返す return list; } // 指定したワイルドカードがファイル名にマッチするかどうか返す function checkWildcard(wildCard, fileName) { // ワイルドカードを正規表現に変換する // メタ文字のエスケープ wildCard = wildCard.replace(/[$+{}|.()\[\]\^\/\\]/g, "\\$&"); // *と?が使える wildCard = wildCard.replace(/\*/g, ".*"); wildCard = wildCard.replace(/\?/g, "."); // 全体にマッチしなければならない。 wildCard = "^"+wildCard+"$"; // 正規表現生成 var regexp = RegExp(wildCard); // ファイルネームが正規表現にマッチするかどうか返す return regexp.test(fileName); } </msxsl:script> <xsl:template match="index"> <ul> <xsl:call-template name="printItem"> <xsl:with-param name="list" select="xmlns:initIndex(.)"/> </xsl:call-template> </ul> </xsl:template> <!-- リストを分解しながらリストとして出力 --> <xsl:template name="printItem"> <xsl:param name="list" select="''"/> <xsl:choose> <xsl:when test="contains($list, ',')"> <xsl:call-template name="printItem"> <xsl:with-param name="list" select="substring-before($list, ',')"/> </xsl:call-template> <xsl:call-template name="printItem"> <xsl:with-param name="list" select="substring-after($list, ',')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <li> <a> <xsl:call-template name="switchHref"> <xsl:with-param name="href" select="$list"/> </xsl:call-template> <xsl:choose> <xsl:whentest="string(document(xmlns:getLocalPath($list))//title)!=''"> <xsl:value-of
select="string(document(xmlns:getLocalPath($list))//title)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$list"/> </xsl:otherwise> </xsl:choose> </a> </li> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
<index>に対するテンプレート<xsl:template match="index">はprintItemテンプレートを呼び出します。その際、initIndex()の戻り値をパラメータとして渡しています。initIndex()は指定された条件でファイルを検索し、ファイル名をカンマで区切って返します。
ファイル名1,ファイル名2,...,ファイル名n
パラメータ付きで呼び出されたprintItemテンプレートは、パラメータで渡された文字列にカンマが含まれているならばそこで分割し、それぞれの文字列をもう一度自分自身に渡します。つまり、再帰処理を行っています。
分割を繰り返していくうちに、printItemテンプレートには単一のファイル名が渡されるようになります。その時、printItemテンプレートはそのファイル名を元にリストの項目を出力します。
今回のスクリプトでは、「3.ローカルテスト時とアップロード時でのリンク先の切り替え」の「app2.xsl」や、「4.ヘッダとフッタの自動追加」の「app1.xsl」を読み込んで使用しています。

