japan.internet.com
デベロッパー2008年5月27日 10:00
文字サイズ文字サイズ小文字サイズ中文字サイズ大

汎用XSLTプリプロセッサ「XmlTransform」

この記事のURLhttp://japan.internet.com/developer/20080527/26.html
著者:Michael Sorens
海外internet.com発の記事

はじめに

 この記事では、汎用のXMLトランスフォーマ/バリデータであるXmlTransformについて解説します。XmlTransformは、変換対象のファイルがどのような深さのディレクトリツリーに格納されていても問題なく機能します。出力時には複数レベルの索引を生成でき、必要に応じてナビゲーションリンクを追加することも可能です。

 XmlTransformの検証機能はかなりシンプルにできていて、変換に使用したXMLファイル一式が妥当かどうかを指定のXMLスキーマに従って検証します。入力ファイルと(変換後の)出力ファイルの両方、あるいはどちらか一方を検証するよう選択できます。

 より興味深いのは変換機能の方です。変換エンジンはよくプリプロセッサとして使用され、Webページを制作するときに大いに役立ちます。

プリプロセッサとHTML

 最新の技法を取り入れた整形式のHTMLは、XMLの名前を真似てXHTMLと呼ばれます。XHTMLには普通のHTMLと比べて、わずかですが重要な違いがあります。XmlTransformを使用すると、XMLファイルをきわめて効率よくWebページに変換できます。XmlTransformでは、実際には任意のXML出力を生成できるのですが、HTMLなど、読者の皆さんが既に知っているであろう具体的なファイル形式を扱った方がプロセスを想像しやすいと思うので、今回の説明ではHTMLの生成に焦点を絞ることにします。

 ところでプリプロセッサとは何でしょうか。また、なぜこれが便利なのでしょうか。どのソフトウェアプロジェクトにおいても言えることですが、メンテナンスには大量のリソースが必要とされ、プロジェクト初期の設計やその後の実装よりも多くのリソースが費やされることもよくあります。プリプロセッサは、このメンテナンスコストの削減に役立ちます。

 たとえば、ある会社のWebサイトを保守しているとします。このサイトは509もの単純なHTMLページから構成されていて、そのそれぞれに一定のサイズのロゴが表示されています。この会社が突然、サイトの見栄え、つまりページヘッダや書体、さらにはロゴのサイズを変更しようと決めた場合、新しいロゴの画像を表示するために500以上のページを1つひとつ編集しなくてはなりません。こういった変更に必要な作業量はページの設計方法に左右されるのですが、ここで重要なのは、この変更作業では、頻繁に登場するWebページ要素に対して同じ変更を繰り返しているということです。

 そこでプリプロセッサの出番です。この考え方はスタイルシートに似ています。スタイルシートでは、あらかじめ定義しておいたスタイルを何度でも利用できます。それと同様に、プリプロセッサでは、スタイルに限らずWebページのあらゆるものに対して同じ処理を実行できます。たとえば、XML内で独自の<footer>要素を作成しておき、そのXMLソースからページを生成するときに、<footer>要素のマーカーを以下のXHTMLコード(コメントを含む)に自動的に置き換えることができます。

<!-- BEGIN footer -->
<div>
  <div style="float:left">
    <img src="image/logo.gif"
      alt="XYZ logo" width="143" height="25"/>
  </div>
  <div style="float:right">
   XYZ Corporation -- (c) 2008 All rights reserved
  </div>
</div>
<!-- END footer -->
 この置換処理は重要です。ソースファイル内の<footer>要素のインスタンスを、ターゲットXHTMLファイル内で上記のコードに展開するためには、展開方法を正確に指定するXSLTを用いて、ソースの「変換」を行う必要があります。上記のHTMLを出力するXSLTコードは以下のようになります。

<xsl:template name="footer">
  <xsl:comment>BEGIN footer</xsl:comment>
  <div>
    <div style="float:left">
      <img src="image/logo.gif" alt="XYZ logo" 
        width="143" height="25" />
    </div>
    <div style="float:right">XYZ Corporation -- &copy; 
       2008 All rights reserved</div>
    </div>
  <xsl:comment>END footer</xsl:comment>
</xsl:template>
 今回はこの記事のダウンロードサンプルに収録されているXSLTファイルを利用しますが、XmlTransformをうまく利用するにはXSLTの理解が不可欠です。作業の大半は、変換をコントロールするXSLTコードの作成に費やされます。簡潔で便利なXSLTを作成するにはかなりの努力が必要ですが、うまくできれば長い間利用できます。

 XmlTransformの設定では、ソースファイルの共通の要素をすべてカプセル化するXMLダイアレクトを独自に定義します。また、その後にXSLTマッピングファイルを作成し、特定のダイアレクトをXHTML(あるいは変換後の任意のXMLダイアレクト)にどのように対応付けるかを指定する必要があります。この初期設定にはある程度時間が必要ですが、一度設定してしまえば、ロゴの変更(あるいは著作権表記などサイト全体を通じて使用される要素の変更)が、XSLTファイル内の1ヶ所を書き換えて出力ファイルを生成し直すだけで簡単に行えるようになります。

 XmlTransformの動作を図1に示します。この図に説明をたくさん詰め込みましたが、1つひとつ分けて考えれば理解しやすいはずです。

図1 実行時のXmlTransformエンジン: 中央に示されているのがXmlTransformの主要な動作ですが、変換元または変換先のツリーに対してスキーマ検証を起動することもできます。変換エンジンのさまざまなオプションを使用した、ツリー操作の細かい制御が可能です。
図1 実行時のXmlTransformエンジン: 中央に示されているのがXmlTransformの主要な動作ですが、変換元または変換先のツリーに対してスキーマ検証を起動することもできます。変換エンジンのさまざまなオプションを使用した、ツリー操作の細かい制御が可能です。
 ここでの目的は変換元のツリー(左上)を変換後のツリー(右下)に対応付けることです。「Schema validator」と「XSLT engine」という3つの黄色い長方形に注目してください。これらはアクティブなコンポーネントで、パスごとのオンとオフを、ブール型のコマンドラインスイッチオプション(図中では丸いスイッチで表現)で切り替えることによって制御します。この切り替えには、xslTransformvalidateInputToSchema、およびvalidateOutputToSchemaのオプションを使用します。図1にはすべてのオプションが点線で囲んで表示されています。inExtensionoutExtensionを使えば、変換元と変換先のファイルに異なる拡張子を指定できます。

 たとえば、XMLをHTMLに変換する場合は、inExtensionに.xmlを指定し、outExtensionに.htmlを指定します。最後に、変換元のツリーの場所(sourcePath)と変換を実行するディレクトリのリスト(dirList)、そしてファイルの出力場所(targetPath)を指定する必要があります。図1では、dirListに指定された変換元ツリー内のディレクトリが赤い長方形で囲まれています。それ以外のディレクトリは変換が行われないので、変換先ツリー内で×印が付いています。他にも考慮すべきパラメータが多数ありますが、そのほとんどはデフォルト値をそのまま使用できます。

 上記以外にも、XmlTransformにはメンテナンスを簡単にする強力な機能が2つあります。それは、サマリ(目次)ページの作成と、ナビゲーションリンクの追加です。以降ではこの2つについて解説します。

目次ページの自動作成

 図2は、XmlTransformの機能を使用して、Webセクションの目次ページに兄弟ページまたは子ページの要素から自動的にデータを読み込む仕組みを示しています。<title>要素の一部と、特定の<meta>要素の一部を指定されたページセットの各ページから抜き出し、それらを組み合わせて1つの目次ページにしています。この方法であれば、セクションにページを追加または削除した場合でも、XmlTransformを再度実行するだけで更新された目次ページを生成できます。

図2 目次の自動生成: 選択された情報をソースファイルから抽出し、目次ページ(画面下)を自動生成できます。
図2 目次の自動生成: 選択された情報をソースファイルから抽出し、目次ページ(画面下)を自動生成できます。
 図1をもう一度見てください。変換先のツリーにファイルが生成されているだけでなく、変換元のツリーにも中間の「目次」ファイル(ピンク色のファイル名)がいくつか生成されています。目次ファイル用のテンプレートを「_index.xml」という名前で作成し、このテンプレートを対象ファイルが含まれるディレクトリに格納すると、XmlTransformによってサマリ情報がテンプレートに挿入されます。たとえば、図2の出力の生成に使用された「_index.xml」ファイルを以下に示します。

<?xml version="1.0"?>
<cc:cleanCodeDoc>
  <cc:head>
    <cc:title>CleanCode::Web Guidelines</cc:title>
    <cc:id>$Id: _index.xml 20 2006-12-29 00:03:27Z dellxp $</cc:id>
    <cc:version>$Revision: 20 $</cc:version>
    <cc:generator/>
  </cc:head>
  <cc:body>
    <h1>Web Guidelines</h1>
    <h2>Design Considerations for Web Sites</h2>
    <cc:files group=""/>
    <br />
  </cc:body>
</cc:cleanCodeDoc>
 この「_index.xml」テンプレートファイルは、ソースツリー内の残りのファイルと一緒に変換される前に、特別な処理が施されます。ここで、同じディレクトリ内のファイルの情報が差し込まれます。この処理は、上記のテンプレートコードの<cc:files>要素を使って制御します。テンプレートにデータが挿入された後、それが変換元ツリー内の「web info.xml」という中間ファイル(図1を参照)に書き出され、続いて、残りの変換処理が実行されます。この中間ファイル(web info.xml)の該当する部分を以下に示します。上記のテンプレートと比較して見ると、同じディレクトリ内の他のファイルの情報が<cc:files>要素に入力されていることがわかります。

<?xml version="1.0"?>
<cc:cleanCodeDoc>
  <cc:head>
    <cc:title>CleanCode::Web Guidelines</cc:title>
    <cc:id>$Id: _index.xml 20 2006-12-29 00:03:27Z dellxp $</cc:id>
    <cc:version>$Revision: 20 $</cc:version>
    <cc:generator/>
  </cc:head>
  <cc:body>
     <h1>Web Guidelines</h1>
     <h2>Design Considerations for Web Sites</h2>
     <cc:files group="">
       <cc:file>
         <cc:relfile>webRules/accessibility.html</cc:relfile>
         <cc:absfile>/usr/doc/webRules/accessibility.xml</cc:absfile>
       </cc:file>
       <cc:file>
         <cc:relfile>webRules/antispam.html</cc:relfile>
         <cc:absfile>/usr/doc/webRules/antispam.xml</cc:absfile>
       </cc:file>
       <cc:file>
         <cc:relfile>webRules/browser.html</cc:relfile>
         <cc:absfile>/usr/doc/webRules/browser.xml</cc:absfile>
       </cc:file>
       <cc:file>
         <cc:relfile>webRules/cssConformance.html</cc:relfile>
         <cc:absfile>/usr/doc/webRules/cssConformance.xml</cc:absfile>
       </cc:file>
         . . .
     </cc:files>
     <br />
  </cc:body>
</cc:cleanCodeDoc>
 目次ページのテンプレートには、その他のHTMLを何でも含めることができます。XmlTransformにとって重要なのは、生成した目次の挿入先を示すマーカー要素(<cc:files>)だけです。上記の例は、<h1><h2>のヘッダ要素のみを追加する非常に基本的なページを表示します。この時点で、中間ファイルを他のすべての参照ページと一緒にXSLT変換で処理できる状態になります。以下に、前述の中間ファイルXMLをXHTMLに変換する「translate.xsl」ファイルから抜粋した、他のページを参照している部分のコードを示します。

<xsl:template match="cc:files">
  <xsl:apply-templates/>
</xsl:template>
   
<xsl:template match="cc:file">
  <xsl:variable name="extNode" 
    select="document(cc:absfile)/cc:cleanCodeDoc"/>
  <div class="guidelink"><a href="{cc:relfile}">
    <xsl:call-template name="trim">
      <xsl:with-param name="s">
        <xsl:value-of select="$extNode/cc:head/cc:title"/>
      </xsl:with-param>
    </xsl:call-template>
    </a>:<xsl:text> </xsl:text>
    <xsl:value-of select=
      "$extNode/cc:head/xhtml:meta[
      @name='description']/@content"/>
  </div>
</xsl:template>
 この短いXSLTコードの各要素をよく見て図2の表示画面と比較すると、該当する情報だけが抽出されていることがわかります(具体的なコードは掲載しませんでしたが、上記のXSLTコードで呼び出しているtrim関数は、コロンで区切られた文字列の最後の項を返します。これは著者のコーディングスタイルであり、いつもそうすると決めているだけで特に深い意味はありません)。最後に、このXSLT変換によってレンダリングされた最終的なXHTMLページの中から、関係のある部分を以下に紹介します。

<body>
. . .
<h1>Web Guidelines</h1>
<h2>Design Considerations for Web Sites</h2>
<div class="guidelink">
  <a href="webRules/accessibility.html">
    Accessibility</a>: Don't discriminate
    on physical ability when you design web pages.
</div>
<div class="guidelink">
  <a href="webRules/antispam.html">
    Anti-Spam</a>: Design defensively so you
    do not make it easy for spammers to enlist you to help them.
</div>
<div class="guidelink">
  <a href="webRules/browser.html">
    Browser Compliance</a>: Design economically
    by considering the technology of your audience.
</div>
<div class="guidelink">
  <a href="webRules/cssConformance.html">
     CSS Conformance</a>: Use CSS
     to improve your design, reduce duplication, 
     and simplify maintenance, but getting it 
     right can be a challenge.
</div>
. . .
 この例では、グループ分けされていない目次ファイルが生成されます。つまり、すべての項目が目次ページ上の1つのリストに配置されます。必要であれば、項目をグループ分けし、各グループに名前を付けて読みやすくすることもできます。たとえば、個々の目次項目グループの前に説明の段落を挿入することも可能です。さらに、ディレクトリごとの目次テンプレートを指定し、ディレクトリの内容に合わせてレイアウトを変えることも可能です。

著者メモ
 具体的な例として、こちらのWebページを紹介します。これは、19個のファイルを6つのセクションに編成して表示する目次ページです。
 ここで解説した目次(サマリ)ページから、階層レベルを1つ下にドリルダウンするための仕組みが理解できたと思います。以降では、残りの方向、つまり上方向へのナビゲーションと、同レベルでのナビゲーションについて解説します。その場合、生成された目次ファイルがどこに置かれるのか気になるところですが、これについても取り上げていきます。

ページの結合

 たとえば、複数のWebページで構成されたチュートリアルのように、自然な順番で表示される一連のWebページがあるとします。各ページには、前後のページや目次ページに移動するためのナビゲーションボタンがあります。ここに新しいページを追加したり、ページを削除したり、あるいはページの順序を変えたりする場合、静的なページを使用していると、おそらく、すべてのリンクを自分で編集しなくてはなりません。これは、時間がかかるうえに間違いを起こしやすい作業です。

 このような連結されたページを図3に示します。各ページに、先頭ページと最終ページ、前のページと次のページ、そして親ページに移動するためのボタンがあります。XSLT変換のマッピングを適切に使用すれば、これらのナビゲーションの連結部分を、XmlTransformで自動的に生成することができます。

図3 周りのページとの連結: XmlTransformによって、親にあたる「web info.html」目次ページが生成されます。このページには、各ページの中央のナビゲーションボタン(「上へ」ボタン)から到達できます。その他のボタンは、子ページ間での前後の移動や先頭および末尾への移動を制御します。
図3 周りのページとの連結: XmlTransformによって、親にあたる「web info.html」目次ページが生成されます。このページには、各ページの中央のナビゲーションボタン(「上へ」ボタン)から到達できます。その他のボタンは、子ページ間での前後の移動や先頭および末尾への移動を制御します。
 図3をよく見ると、すべてのページに「先頭ページ」および「最終ページ」に進むボタンが表示されることがわかります。それに対して、その間にある「戻る」「上へ」「進む」の3つのボタンは条件付きで表示されます。たとえば、先頭ページに「戻る」を表示したり、最終ページに「進む」を表示したくはありません。また場合によっては、2つのボタンが同じページを指すこともあります。たとえば2ページ目に表示される「先頭ページ」ボタンと「戻る」ボタンは、どちらも1ページ目に移動します。

 「上へ」ボタンは、特にディレクトリ構造が深い場合に便利です。先に解説した目次の自動生成処理を思い出してください。一般的な慣例では、あるディレクトリについての「index.html」ファイルは、対象ディレクトリ内に置きます。しかしこの慣例に従うと、生成されるナビゲーションボタンは「index.html」を「戻る」ボタンや「進む」ボタンで移動できるページと同様のものとして扱うため、「上へ」ボタンで移動することができません。これを「親」にするためには、「index.html」を子よりも1つ上のディレクトリに置く必要があります。

 しかし、複数のディレクトリについての目次を生成する場合はどうでしょうか。言うまでもなく、複数のファイルに「index.html」という同じ名前を付けることはできません。これを解決するために、XmlTransformでは、目次ファイルにディレクトリと同じ名前を付けるという方法を採用しています。つまり、「stuff」というディレクトリであれば「stuff.html」という目次ファイルが生成されるのです。

 この2通りの要件を考慮し、XmlTransformでは目次ページの生成方法を選択できるようになっています。つまり、いつもの慣例に従いたい場合は同一ディレクトリに「index.html」という名前で生成し、より自然な階層モデルを使用したい場合(「上へ」ナビゲーションボタンを利用したい場合)は1つ上のディレクトリに「<ディレクトリ名>.html」という名前で生成することができます。

 各Webページのナビゲーションボタンを生成するXSLTコードの一部をリスト1に示します。通常の<body>要素ではなく<cc:body>要素を使用すると、このXSLTが(検索ボックス、ロゴ、メニューなどを表示する他の多くのコードと一緒に)各Webページへ自動的に組み込まれます。あるページのナビゲーション部分として出力されたXHTMLコードの抜粋を以下に示します。よく見ると、このコードは図3の先頭ページ(access.html)からの抜粋であることがわかります。「戻る」ボタンの部分に矢印ではなく空白の画像が配置され、アクティブなリンクも作成されていないからです。

<span style="margin-left:10px" class="headerFont"
    title="Shortcut keys in Internet Explorer:
    1=First, 2=Previous, 3=Next, 4=Last, 5=Up">NAVIGATION:</span>
<span>
     <a href="accessibility.html">
       <img src="/image/firstButton.gif" alt="first page in section"
         width="14" height="14" />
     </a>   
     <img src="/image/dot_clear.gif" alt="" width="14" height="14" />
   
     <a href="../webRules.html">
        <img src="/image/upButton.gif" alt="up one level"
            width="14" height="14" />
     </a>
   
     <a href="antispam.html">
        <img src="/image/nextButton.gif" alt="next page"
            width="14" height="14" />
     </a>
   
     <a href="style.html">
        <img src="/image/finalButton.gif" alt="final page in section"
            width="14" height="14" />
     </a>
</span>
 ここまでの解説で、XmlTransformの基本的な動作と、目次ページを生成する機能、さらにファイル間のナビゲーションを自動化する機能について見てきました。この2つの機能は、XMLをHTMLに変換する場合に非常に便利ですが、その他のXMLダイアレクトに変換する場合には必要ないかもしれません。

XmlTransformの実行

 XmlTransformを実行するには、以下のコンポーネントを読み込む必要があります。

  • Java(バージョン1.5以上)。必要なのはJavaのランタイムエンジンだけです。持っていない場合はSunからダウンロードしてください。
  • XML解析用Xercesライブラリ。
  • XSLT変換用Xalanライブラリ。
  • cleancode-javaオープンソースライブラリ。
  • CleanCodeライブラリ(cleancode.jar)、Xercesライブラリ(xml-apis.jarとxercesImpl.jar)、およびXalanライブラリ(serializer.jarとxalan.jar)のJARファイルをJavaのクラスパスに追加する必要があります。
 動作を確認するために、使用方法を表示するオプションを呼び出します。

> java com.cleancode.xml.XmlTransform --help
 このコマンドを実行すると、利用可能なすべてのコマンドラインオプションが一覧で表示され、それぞれが1行で説明されます。

 オプションの数が多いため、すべてのオプションをパラメータファイルに記述し、コマンドラインからパラメータファイルを参照するという方法も用意されています。その場合は、次の例のようにファイル名の先頭に@マークを指定します。

> java com.cleancode.xml.XmlTransform @myParams.dat
 XmlTransformはパラメータファイル内のオプションを、コマンドラインから入力されたオプションと同じように扱います。ただし、シェル画面には表示されません。コマンドラインから特殊文字(引用符やリダイレクトなど)を直接入力すると、シェルが特殊文字を先に処理するために衝突が起こる場合もありますが、パラメータファイルを使用すれば回避できます。パラメータファイルのもう1つのメリットは、デフォルトのオプションセットを含むパラメータファイルを作成し、その設定を、コマンドラインで直接入力したオプションや別のパラメータファイルで指定したオプションによって上書きしたり、補足したりできるという点です。

 たとえば、「inline.conf」というパラメータファイルに以下の3つのパラメータを記述したとします(わかりやすくするために架空のオプション名を使っています)。

--x1=2
--x2=4.3
--x3=true
 そして、コマンドラインで以下のように指定します。

> java class_name --x1=4 @inline.conf --x4=0.5
 すると、パラメータが挿入され、以下のコマンドラインを指定したのと同じことになります。

> java class_name --x1=4 --x1=2 --x2=4.3 --x3=true --x4=0.5
 x1オプションは2回指定されることになりますが、最後に指定された値が採用されるため、x1の値は4ではなく2になります。したがって、デフォルトのオプションセットを含むパラメータファイルを使用し、そのオプションを必要に応じてコマンドラインから上書きしたい場合は、上記の例のようにパラメータファイルをオプション間に指定するのではなく、先にパラメータファイルを指定し、後からそれを上書きするためのオプションを直接入力します。

 この手法のバリエーションとして、デフォルトのオプションセットを含むパラメータファイルを指定した後に、そのオプションの一部を書き換える別のパラメータファイルを指定することもできます。以下に例を示します。

> java class_name @default.dat @variation-one.dat

オプションの要約

 以下はXmlTransformで使用可能なすべてのオプションの一覧です。後述の各ステップでは、これらのオプションを論理的に分類して詳しく説明します。さらに詳しく知りたい場合は、XmlTransform APIを参照してください。

contentsBaseName       -- 目次ファイルのベース名(indexなど)
contentsToParent       -- 目次を親ディレクトリと同じディレクトリの
                          どちらに置くかをブール値で指定
debug                  -- Trueの場合にすべて(ライブラリを含む)の
                          診断を有効にする
diagList               -- アクティブにする診断を1文字の文字列で指定
dirList                -- 処理対象のディレクトリをコンマで区切って指定
enable                 -- 処理を行う場合はTrue、
                          レポートのみの場合はFalse
generateContents       -- 目次を生成するかどうかをブール値で指定
generatorNode          -- ジェネレータ情報で置き換えるノードのタグ名
groupIdXpath           -- 各ファイル内のグループIDノードを指す
                          簡単なXpath
groupPlaceHolder       -- 目次ファイル内でファイルリストを挿入する
                          タグの名前
help                   -- この一覧を表示する
inExtension            -- 処理対象のファイルの拡張子
inputSchemaSource      -- 入力の検証用グローバルスキーマファイル
outExtension           -- 変換後のファイルの拡張子
outputSchemaSource     -- 出力の検証用グローバルスキーマファイル
processAll             -- Trueの場合、日付スタンプをチェックせずに
                          処理する
sourcePath             -- 変換元のXMLツリーのルート
startDepth             -- ツリーの最上位から各自の相対ルートまでの
                          ディレクトリ数
targetPath             -- 変換先のXMLツリーのルート
validateInputToSchema  -- 入力の検証をブール値で指定
validateOutputToSchema -- 出力の検証をブール値で指定
validateXslBySchema    -- 必要なXSLファイルの検証をブール値で指定
xslName                -- 各ディレクトリのプライマリXSLファイル
xslParmList            -- XSLパラメータをコンマで区切って指定
xslSchema              -- XSLファイルのスキーマファイルの名前
xslTransform           -- XSL変換をブール値で指定
 XmlTransformで利用可能なオプションのうち、このアプリケーション固有でないものを以下に示します。CleanCode診断システムを使用するアプリケーションであれば、必ずこれらのオプションを使用できます。Diagnostic APIのすべてが説明されたドキュメントをこちらで参照できます。

.*_DIAG                -- すべてのクラスの診断レベル
CREATE_DIAG            -- オブジェクト作成の診断レベル
DIAG_LEVEL             -- 診断マスク
ENV_DIAG               -- システム環境の診断レベル
FORMATTER              -- Webチャネルの書式設定のクラス名
LOG_DIAG_NAME          -- 通常のメッセージのベースファイル名
LOG_DIR                -- ログファイルの作成先ディレクトリ
LOG_ERR_NAME           -- 警告/エラーメッセージのベースファイル名
OUTPUT_DIAG            -- 通常のメッセージの出力チャネル
OUTPUT_ERR             -- 警告/エラーメッセージの出力チャネル
SHOW_THREAD            -- スレッド情報の表示/非表示の切り替え
TRACE_DIAG             -- メソッド入/出の診断レベル
TRACE_INDENT           -- ネストされた出力のインデント文字列
VERSION_DIAG           -- モジュールのバージョン管理の診断レベル
WARNINGS_ON            -- 警告メッセージの表示/非表示の切り替え
 サンプルプロジェクトの完全なパラメータファイルをリスト2に示します。以降では、各オプションに値を正しく設定する方法についてさらに詳しく説明します。

ステップ1:何を?

 XmlTransformでは多数のブール型オプションを使用して、各機能の有効と無効を切り替えます。

  • xslTransformでは、指定されたXSLTを使用してファイルを検証するだけでなく、入力から出力へ変換を行うことを指定します。
  • generateContentsでは、入力ツリー内に目次ファイルを生成することを指定します(前述の目次テンプレートファイルを使用)。
  • validateInputToSchemaでは、XMLスキーマ定義を使用して入力を検証することを指定します。
  • validateOutputToSchemaでは、XMLスキーマ定義を使用して出力を検証することを指定します。
  • validateXslBySchemaは高度な目的に使用されるオプションで、XSLファイルそのものを検証することを指定します(xslTransformが有効になっていればどのエラーもすぐに見つかるのであまり使用されません)。

ステップ2:どこへ?

 入力ファイルのツリーの場所(sourcePath)と出力ファイルのツリーの生成場所(targetPath)を指定します。指定しなければ、デフォルトでどちらも現在のディレクトリにセットされます。次に、入力ファイルの拡張子(inExtension)と出力ファイルの拡張子(outExtension)を指定します。デフォルトではinExtensionがxml、outExtensionがhtmlです。

ステップ3:何を使って?

 各ファイルを変換するには、変換情報を定義したXSLファイルをxslNameに指定する必要があります。絶対パスで指定した場合、XmlTransformはすべてのサブディレクトリに対してそのファイルを使用しますが、ファイル名のみ(stuff.xslなど)を指定した場合は、処理対象のサブディレクトリ内でその名前のファイルを探します。ファイルが見つからなければルートディレクトリ(sourcePath)を探します。これを利用して、XSLファイルを柔軟に指定することができます。つまり、グローバルなXSL定義を1つ指定し、一方で特別な処理が必要なサブディレクトリでは定義を上書きすればよいのです。あるいは、ルートにXSLファイルを置かず、処理を行いたいサブディレクトリにだけXSLファイルを格納するという方法も便利です。

 特定のサブディレクトリで目次を生成する場合は、XMLテンプレートファイルを指定する必要があります。これは他のファイルと同じく普通のXMLファイルですが、前にも説明したように、他のファイルを参照してリストを作成するためのプレースホルダが1つ以上記述されます。テンプレートファイルの名前は、「_myDir.xml」などのように、アンダースコア(_)、contentsBaseNameの値、ドット(.)、inExtensionの値を並べるというルールに従って作成しなければなりません。

 XmlTransformはテンプレートにデータを挿入し、データが挿入されたファイルを中間ファイルとして入力ファイルツリーに格納します。この中間ファイルの名前は、目次ファイルを参照先ファイル群と同じディレクトリに格納するか、その親ディレクトリに格納するか(contentsToParent)によって変わります。同じディレクトリに格納する場合は、テンプレートと同じベース名(contentsBaseName)、ドット(.)、inExtensionの値を並べた名前になります(アンダースコアは付けません)。さらに、目次項目を目次テンプレートのどこに挿入するかを、グループプレースホルダ(groupPlaceHolder)で指定する必要があります。

 中間ファイルは変換元のツリーに作成されるので、目次ファイルをうっかり上書きしないように注意する必要があります。しかし、それをXmlTransformでチェックすることはできません。なぜなら、前回の実行時に作成されたファイルと区別が付かないからです。そのため、生成される中間ファイルの指定のノードにジェネレータIDの文字列を書き込み、そのノードの存在を調べてファイルを上書きしてよいかを判断するようになっています。このジェネレータIDの文字列をXMLのどの要素で受け取るかはgeneratorNodeオプションに指定します。最後に、目次ファイルの生成ではgroupIdXpathオプションが必要です。ここには各ファイルのグループ識別子の検索に使用するXPath式を指定します。

ステップ4:どのように?

 最後に、プログラムの動作方法についてもいくつかオプションを指定する必要があります。

  • 処理対象のサブディレクトリ――sourcePath内のどのサブディレクトリをXmlTransformで処理するかを、dirListオプションを使用して明示的に指定します。この文字列はsub1, sub1/subsub1, sub2, sub3のように、サブディレクトリ名(sourcePathより下の部分)をコンマまたはセミコロンで区切って指定します。省略するとsourcePath自体が処理されます(サブディレクトリは処理されません)。
  • プレビューモード――XmlTransformの使い方に慣れるまで、あるいは新しく設定したオプションを確認したい場合などは、プログラムの処理内容を実際に動作させずにチェックできます。この制御はenableフラグで行います(デフォルト値はTrue)。enableをFalseにセットすると、XmlTransformは実際には動作せずに、実行する処理の内容をレポートします。
  • 節約モード――XmlTransformは節約家なので必要なことしかしません。つまり、前回実行した際の処理を追跡して、それ以降に変更されたファイルだけを検証または変換します。これを変更し、すべてのファイルを強制的に処理する場合はprocessAllフラグを使用します。デフォルト値はFalseです。
  • サブディレクトリの深さの追跡――高度な目的に使用するオプションです。XmlTransformで処理するサブディレクトリの深さを追跡します。これを利用すると、位置情報を必要とするアクションやパスを定義できます。たとえば、HTMLを出力ファイルとして生成するとき、インクルードされるファイルへの相対パスを指定したい場合に、追跡した深さを使用して"../../.."などの文字列を正しく生成し、ファイル名の先頭に付加することができます。以下に、このようなパスを正確に生成する簡単なXSLを示します。
  • <xsl:template name="buildpath">
       <xsl:param name="level"></xsl:param>
       <xsl:if test="$level &gt; 0">../<xsl:call-template name="buildpath">
           <xsl:with-param name="level">
               <xsl:value-of select="$level - 1"/>
           </xsl:with-param>
           </xsl:call-template>
       </xsl:if>
    </xsl:template>
    
    startDepthオプション(デフォルト値は0)を使用して、ルート(sourcePath)と参照先のインクルードファイルの場所の間のオフセットを指定できます。たとえば、インクルードファイルがHTMLファイルの1つ上のディレクトリに含まれる場合は、startDepthに1を指定して、上記のXSL関数でパスに".."を1つ追加するよう指示します。ここで注意したいのは、XmlTransformが処理対象のサブディレクトリの深さをXSL変換に渡すときには、levelパラメータを使用して、この開始位置までのオフセットとして渡すという点です。
    XSL内でcall-template要素を使用するとき、先の例のパス文字列を作成するために$levelを引数として渡しているのはこのためです。これは一例に過ぎません。$levelパラメータには他の使い方もあります。たとえば、XSL内で現在のレベルに応じて異なるテンプレートを呼び出すことなども可能です。
  • カスタムなXSLパラメータの定義――高度な目的に使用するオプションです。現在のサブディレクトリレベルをパラメータとしてXSLに渡せるのと同様に、xslParmListオプションを使用すれば、XSLにユーザー定義の値を渡すこともできます。これには、パラメータをコンマまたはセミコロンで区切って設定します。各パラメータは「名前:値」の形式で設定する必要があり、値にコンマやセミコロンを含めることはできません。これは著作権の日付やリリースのバージョン番号などの値(例:xslParmList=copyright:2006,relVersion:v1.2)を渡す場合に便利です。
  • また、前述のように、XmlTransformはジェネレータIDの文字列を作成します。この文字列は前述の目次ファイルの上書きを防ぐ仕組みの中で自動的に利用できます。このパラメータにアクセスするには、最初に以下の行をXSLに含めます。
    <xsl:param name="generator"/>
    
    続いて、HTMLやXHTMLを作成する場合であれば以下のように定義します。
    <meta content="{$generator}" name="myGenerator"/>
    
 XmlTransformのオプションは数が多く、また、出力結果からオプションの効果を見て取ることが難しいため、習得までの道のりは非常に険しいと言えます。しかし、何か苦労している問題があるなら、XmlTransformで解決できないか調べてみてください。時間を大幅に節約できるかもしれません。筆者はもともとXmlTransformを自身のオープンソースのWebサイトで静的なページを生成するために使用していました。ページをHTMLではなくカスタムなXMLダイアレクトで手早く作成でき、ヘッダ、フッタ、ページのリンク、著作権日付などを見栄え良く自動作成してくれるからです。

 しかし、XmlTransformが便利なのはそれだけではありません。たとえば、C#のNdocや、JavaのJavaDocと同種のSQLドキュメントジェネレータとしても利用できます。「Add Custom XML Documentation Capability To Your SQL Code」の記事には、XmlTransformを使用したSQLドキュメントの作成方法が詳しく説明されています。この記事では、今回紹介したのと同じサンプルソースファイルが使用されているので、XmlTransformを別の方法で試してみるとよいでしょう。

リスト1 XSLTナビゲーション
<xsl:template name="navArrows">
    <xsl:if test="$nextLink or $prevLink">
    <span class="headerFont" style="margin-left:10px">
        <xsl:attribute name="title">
           Shortcut keys in Internet Explorer:<xsl:text>
           </xsl:text>1=First, 2=Previous, 3=Next, 4=Last, 5=Up
        </xsl:attribute>
        NAVIGATION:
    </span>
    <span>
        <xsl:if test="$firstLink">
            <a href="{$firstLink}">
                <img height="14" width="14" alt="first page in section"
                    src="/image/firstButton.gif" />
            </a>
        </xsl:if>
        <xsl:choose>
            <xsl:when test="$prevLink">
                <a href="{$prevLink}">
                    <img height="14" width="14" alt="previous page"
                        src="/image/prevButton.gif" />
                </a>
            </xsl:when>
            <xsl:otherwise>
                <img alt="" width="14" height="14"
                    src="/image/dot_clear.gif" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:choose>
            <xsl:when test="$upLink">
                <a href="{$upLink}">
                    <img height="14" width="14" alt="up one level"

                        src="/image/upButton.gif" />
                </a>
            </xsl:when>
            <xsl:otherwise>
                <img alt="" width="14" height="14"
                    src="/image/dot_clear.gif" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:choose>
            <xsl:when test="$nextLink">
                <a href="{$nextLink}">
                    <img height="14" width="14" alt="next page"
                        src="/image/nextButton.gif" />
                </a>
            </xsl:when>
            <xsl:otherwise>
                <img alt="" width="14" height="14"
                    src="/image/dot_clear.gif" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="$finalLink">
            <a href="{$finalLink}">
                <img height="14" width="14" alt="final page in section"
                    src="/image/finalButton.gif" />
            </a>
        </xsl:if>
    </span>
    </xsl:if>
</xsl:template>
リスト2 XmlTransformのパラメータ
// switches indicate what to process
--generateContents=true
--xslTransform=true
--validateInputToSchema=false
--validateOutputToSchema=false

// root of source xml tree
--sourcePath=/devx/sqlDoc/sqlDocProject/XMLsrc

// root of target html tree
--targetPath=/devx/sqlDoc/sqlDocProject/api/sql

--inExtension=xml
--outExtension=html

// Comma-separated list of directories in source tree to process.
// Omit if processing everything (e.g. ".")
// --dirList=.

// name of XSLT file within each directory of dirList
--xslName=translate.xsl

// ignore datestamps if true
--processAll=false

// can opt to report on what will happen with a false value
--enable=true

// directories from the tree top back to relative root
--startDepth=0

// xsl parms passed via comma-separated list of "name:val" entries
--xslParmList=revdate:2007.11.01,copyright:2007,relVersion:0.95

// flag to indicate to put contents in parent or in same directory
--contentsToParent=false

// where to add a list of group files in a contents file
--groupPlaceHolder=cc:files

// where to put generator information in contents file
--generatorNode=cc:generator

// where to find the group identifier in each file
--groupIdXpath=cc:cleanCodeDoc/cc:head/cc:group

// bit combination of xxxx_DIAG values to enable
DIAG_LEVEL=0x81a

// to show all module versions
VERSION_DIAG=0x800

// to show all configuration options
INPUTOPTIONS_DIAG=0x400

XMLTRANSFORM_A_DIAG=0x2
XMLTRANSFORM_B_DIAG=0x4
XMLTRANSFORM_C_DIAG=0x8
XMLTRANSFORM_D_DIAG=0x10
XMLTRANSFORM_E_DIAG=0x20
XMLTRANSFORM_F_DIAG=0x40

// log and stdout
OUTPUT_DIAG=9
// log and stderr
OUTPUT_ERR=0xA

著者紹介

Michael Sorens(Michael Sorens)
フリーランスのソフトウェアエンジニア。フェニックス大学やコミュニティカレッジでの指導、2冊の本とさまざまな記事の執筆、さらにオープンソースのWebサイトを通して、優れたデザインの種をまき続けている。Fortune 500企業やベンチャー企業でJava、C#、Perl、C、Lisp、PostScriptなどのプログラミングに従事。お気に入りのプロジェクトは、シリコン製でプリンタヘッドにレーザーを使用した、独立宣言を文字どおりピンの頭に印字できる世界最小のワープロの設計と実装。
japan.internet.comのウエブサイトの内容は全て、国際法、日本国内法の定める著作権法並びに商標法の規定によって保護されており、その知的財産権、著作権、商標の所有者はインターネットコム株式会社、インターネットコム株式会社の関連会社または第三者にあたる権利者となっています。
本サイトの全てのコンテンツ、テキスト、グラフィック、写真、表、グラフ、音声、動画などに関して、その一部または全部を、japan.internet.comの許諾なしに、変更、複製、再出版、アップロード、掲示、転送、配布、さらには、社内LAN、メーリングリストなどにおいて共有することはできません。
ただし、コンテンツの著作権又は所有権情報を変更あるいは削除せず、利用者自身の個人的かつ非商業的な利用目的に限ってのみ、本サイトのコンテンツをプリント、ダウンロードすることは認められています。

Copyright 2012 internet.com K.K. (Japan) All Rights Reserved.