本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

XSLT 2.0によるコード生成 第1回: XSLT 2.0でSQLを生成する

より良いコードを構築しつつ、困難な作業を排除する

Jack Herrington (jherr@pobox.com), Editor-in-Chief, Code Generation Network
Jack D. Herringtonは、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。著者には、「Code Generation in Action」、「Podcasting Hacks」、そして近々刊行予定の「PHP Hacks」の3冊があります。彼は30本以上の技術記事も執筆しています。

概要: XSLT 2.0の持つ最先端機能の使い方、そして抽象データ・モデルからPHPコードを生成する方法を学びます。2回構成の第1回である今回は、Jack Herringtonが堅牢な多階層の変換技法を使って、対象データベースの単純なモデルからデータベース・サーバ用にSQLを生成する方法を説明します。

日付:  2005年 2月 08日
レベル:  中級 この記事の原文:  英語
アクティビティー: 2528 ビュー
お気軽にご意見・ご感想をお寄せください: 


みなさんは、新しいPHPプロジェクトのエンジニアリング・チームのリーダーです。要求事項は満足され、初期段階でのデータ・モデルは約150テーブルです。今度は、スケジュールを考える番です・・・。それぞれのデータベースのアクセス・クラスを書いて単体テストをするのに約1日と見積もると、1日1テーブルとして150テーブルでは150日になります。1ヶ月の稼働日を20日として、データベースのアクセス層を書くだけのために、約8ヶ月も必要なのでしょうか?

恐らく、そんなことはないはずです。ですからみなさんには、必要な時間を減らす方法が必要です。みなさんはパーシスタンス・フレームワークを使うことを考えるかも知れませんが、それを使って時間を半分にしたとしても、まだ4ヶ月が必要です。一般的なライブラリを書く方法もありますが、そうしたライブラリは使用するのが複雑であり、エラーを起こしやすく、またデバッグも困難です。

あるいは、1つか2つのサンプル・コードを書き、残りをコード・ジェネレータで構築する方法もあります。最悪の場合には、ジェネレータ自体を書くのに1ヶ月はかかるでしょう。しかしその後は、残りのコードの生成が数分でできるようになります。さらに、ジェネレータがSQLスキーマとデータベースのアクセス・コードの両方を生成するので、SQLスキーマがアクセス・コードと一致しない場合に発生するバグが、ほとんど無くなります。

そんな方法が本当に可能なのでしょうか?・・・それが、可能なのです。この記事では、どのようにそれを行うのか、そして、そうすることによってアプリケーションがいかに管理しやすく、堅牢に、そして楽しく書けるものになるかを説明します。2回シリーズの第1回の今回は、コード生成の基礎を解説し、また、対象となるモデルに対するSQLを生成するコード・ジェネレータ部分を構築する方法について順を追って説明します。第2回では、XSLをさらに深く掘り下げ、PHPを生成するコードを示しながら、ジェネレータをどのように完成させるかを解説して行きます。

コード生成の基礎

本題に入る前に、データベースの抽象モデルを検討し、そしてSQLスキーマとPHPでデータベースにアクセスするクラスの両方を構築するジェネレータが必要でしょう。図1は、このモデルと、Java™コードなど他の技術向けにデータベースのアクセス・コードを生成する可能性を示しています。


図1. ジェネレータに関する基本的な情報の流れ
ジェネレータに関する基本的な情報の流れ

図1で、破線で示した矩形(SQLモデルとデータベース・アクセス・モデル)は、抽象モデルから作成された一時的なモデルを示します。点線で示された部分(Java)は、生成できる可能性のあるものを示します。

次の問題は、どの技術を使うべきかです。ジェネレータは、Javaコードを使って書くことも、PerlやPython、あるいはRubyを使って書くこともできます。課題が単純なことを考えると、VelocityやXSLTのようなテンプレート・エンジンで用が足りるかもしれません。XSLT 2.0のようなテンプレート・エンジンは、それ自体が多くの機能をもっており、Javaコードの中に埋め込んでその機能を拡張することもできることから、出発点としては好適です。

XSLT 2.0

XSLT 2.0は、コード生成のためにテンプレート・エンジンを探し求めている開発者に対して、拡張言語機能を提供してくれます。この記事では、そうした機能に関して、抽象テーブルの定義を元に機能し、SQLとPHPの両方に対応する堅牢なジェネレータを構築するという観点から解説します。XSLT 1.xでは、単一レベルでの変換しか可能ではありませんでしたが、XSLT 2.0では、生成すべきコードの中間モデルを構築することができるのです。この機能のおかげで、ジェネレータを理解したり維持管理したりすることが容易になり、また他の言語をターゲットとしたジェネレータに転用することもできるようなります。

XMLの変換技術としてXSLTは、XMLをXMLあるいはテキストに変換することができます(このコード・ジェネレータ・プロジェクトでは、この両方の機能を使います)。XSLT 2.0は、XSLT 1.xよりも大幅に改善されていますが、この記事では再訂されたXSLT 2.0の持つ、3つの新機能を使います。

  • 関数: 拡張関数を定義できるようになりました。これは、このために面倒なテンプレート構文を使っていた最初のバージョンのXSLTと比較すると、大きな改善です。
  • 一時的ツリー: 最初のバージョンのXSLTでは、入力されたXMLツリーに対して操作をする必要がありました。XSLT 2.0では、他のテンプレートを操作するために使用可能な一時的ツリーを、メモリ上に構築できるようになりました。
  • 結果文書: 一つのテンプレートから複数の出力ファイルを生成できるようになりました。SQLファイルや個々のPHPファイルの生成に、この機能を使っています。

では、ジェネレータをどのように構築するかを見てみましょう。


ジェネレータを構築する

まず、ジェネレータへの入力から始めます。リスト1は、単純な書籍のデータベースに関するテーブル定義の例です。


リスト1. 入力用の抽象的なテーブル定義
                
<?xml version="1.0" encoding="UTF-8"?>
<tables>
    <table name="Author">
        <field name="first" type="text"/>
        <field name="last" type="text"/>
    </table>
    <table name="Publisher">
        <field name="name" type="text"/>
        <field name="last" type="text"/>
    </table>
    <table name="Book">
        <field name="name" type="text"/>
        <field name="author" type="id"/>
        <field name="publisher" type="id"/>
    </table>
</tables>

この単純なXMLスクリプトは、Author(著者)、Publisher(出版社)、Book(書籍)という、3つのデータベース・テーブルと、そのフィールドを定義しています。本格的なPHPアプリケーションへの入力は、これよりもずっと大きく複雑でしょうが、このコードで、最初としては充分です。

このXMLを、単一パスでSQLまたはPHPに変換するジェネレータを構築することもできますが、私としてはお勧めしません。テンプレートが複雑になり、維持管理も困難となるからです。コード生成に関する今日のベスト・プラクティスは、複数レベルのモデルを持ち、レベルに応じて次第に厳密に対象を絞るようにすることです。そうすることによって、一つ一つの変換が複雑になりすぎるのを防ぐことができます。これはWebサーバで、複数の階層を使うことによって全体的な複雑さを減少させ、再利用を促進するのと似ています。

再度図1を見ると、抽象モデルがSQL向けに一つのモデルを生成し、さらに、データベース・アクセス・モデルを通してPHP向けに、もう一つのモデルを生成していることが分かります。こうしたモデルは、一時的ツリーに保存され、そしてコードを生成するために使われます。図2では、ジェネレータにおける変換を通じて、Authorテーブルを追跡しています。


図2. 一つのSQLテーブルの進展
一つのSQLテーブルの進展

図2の一番上にある矩形は、元の抽象的なテーブル・モデルを示しています。中央の矩形は、その抽象的なモデルから構築されたSQLモデルです。一番下の矩形は、結果として作成されるSQL出力を示しています。見て分かる通り、SQLモデルには、最後のSQLファイルの中に何があるべきか、全ての要点を明示しています。コード・テンプレートの役割は、単純にXMLをSQLへと変換することです。それによって、一つのモデルから様々なデータベース用のコードが生成できるようになるのです。では、XSLを見てみましょう。


SQLを生成する

リスト2は、このジェネレータ・プロジェクト用の主要なXMLスタイルシートの、先頭部分を示しています。


リスト2. ジェネレータ用の主要XMLスタイルシートの先頭部分
                
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gen="http://www.codegeneration.net/" version="2.0">
    <!-- Output specifications -->
    <xsl:output method="text"/>
    <xsl:output method="xml" name="debug-xml" indent="yes"/>
    <xsl:output method="text" name="sql" indent="yes"/>
    <!-- SQL Templates -->
    <xsl:include href="gen2-sql.xsl" />
    <xsl:include href="gen2-sql-model.xsl" />
    <xsl:include href="gen2-queries.xsl" />
    <!-- Database Access Templates -->
    <xsl:include href="gen2-dba.xsl" />
    <xsl:include href="gen2-php.xsl" />
    <!-- The generator main entry point -->
    <xsl:template match="/">
        <!-- Create the SQL model -->
<xsl:text>Building SQL model</xsl:text>
        <xsl:variable name="sql-model">
            <xsl:call-template name="gen-sql-model">
                <xsl:with-param name="model" select="."/>
            </xsl:call-template>
        </xsl:variable>
        <!-- Dump it out for debugging -->
<xsl:text>Dumping SQL model</xsl:text>
        <xsl:result-document href="db/gen-tables.xml" format="debug-xml">
            <xsl:copy-of select="$sql-model"/>
        </xsl:result-document>
        <!-- Generate the SQL from the SQL model -->
<xsl:text>Generating SQL</xsl:text>
        <xsl:result-document href="db/gen-tables.sql" format="sql" >
            <xsl:apply-templates mode="sql" select="$sql-model/sql" />
        </xsl:result-document>
        

このスクリプトで重要な部分は、SQLモデルを保持するsql-model変数を作成する部分と、sql-model変数の内容を使ってSQLファイルを生成するresult-documentタグを作成するところです。こうしたタグは、XSLT 2.0に貴重な2つの機能が追加されたことを示しています。つまり、xsl:variableタグを使って一時的ツリーを作成する機能と、xsl:result-documentタグを使って複数の出力ファイルを作成する機能です。

では、抽象テーブル・モデルからSQLモデルを生成するテンプレートをお見せしましょう。リスト3は、gen-sql-modelテンプレートを示しています。


リスト3. SQLモデル・ジェネレータ
                
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:gen="http://www.codegeneration.net/" version="2.0">
    <!-- Builds the SQL model from the original data model -->
    <xsl:template name="gen-sql-model">
        <xsl:param name="model"/>
        <sql>
            <xsl:for-each select="$model/tables/table">
                <create name="{lower-case(@name)}"
   primary-key="{concat(lower-case(@name),'_id')}">
                    <field name="{concat(lower-case(@name),'_id')}"
    type="{gen:model-type-to-sql('integer')}"/>
                    <xsl:for-each select="field">
                        <field name="{lower-case(@name)}"
   type="{gen:model-type-to-sql(@type)}"/>
                    </xsl:for-each>
                </create>
            </xsl:for-each>
        </sql>
    </xsl:template>
</xsl:stylesheet>

このテンプレートは、ごく単純です。元のモデルから、SQLモデル用の新しいタグを幾つか作ります。gen:model-type-to-sql関数への呼出しに注意してください。この呼出しは標準的なXSLT関数の一部ではなく、私がリスト4で定義している、拡張関数です。


リスト4. モデルからSQL型への変換関数
                
    <xsl:function name="gen:model-type-to-sql">
        <xsl:param name="type"/>
        <xsl:choose>
            <xsl:when test="$type eq 'text'">TEXT NOT NULL</xsl:when>
            <xsl:when test="$type eq 'id'">INTEGER NOT NULL</xsl:when>
            <xsl:when test="$type eq 'integer'">INTEGER NOT NULL</xsl:when>
        </xsl:choose>
    </xsl:function>

この、新しいXPath関数を作ることができる、という機能は、XSLT 2.0で新規に追加されたものです。以前は、xsl:call-template構文を使う必要がありましたが、これはパラメータが増えると扱いが面倒になりがちです。また、テンプレートが関数として機能するため、テンプレートの名前空間を混乱させることにもなります。

SQLを生成するための最後のステップは、SQLモデルをSQLとして書式化することです。これは、リスト5に示す2つのテンプレートを使って行います。


リスト5. SQL生成テンプレート
                
    <!-- Template for SQL create tags -->
    <xsl:template match="create" mode="sql">
DROP TABLE IF EXISTS <xsl:value-of select="@name" />;
CREATE <xsl:value-of select="@name" /> (
<xsl:apply-templates mode="sql" select="field" />
PRIMARY KEY ( <xsl:value-of select="@primary-key" /> )
        );
    </xsl:template>
    <!-- Template for SQL field tags -->
    <xsl:template match="field" mode="sql">
<xsl:value-of select="concat(@name,' ',@type,',')" /><xsl:text>
</xsl:text>
    </xsl:template>

本当にこれがすべてです。SQLモデルのcreateタグに応答する一つのテンプレートがあり、このテンプレートが今度はapply-templatesタグを使って、その子fieldタグを処理します。fieldタグは、2番目のテンプレートによって書式化されます。

もう一度図2を見てください。XMLの構造とSQLの構造が、いかに似ているかに注意してください。createタグは、幾つかのfieldタグを含んでいます。SQLの場合と同様、createコマンドは幾つかのフィールド・パラメータを含んでいます。コードの構成と同じようにモデルを構成することによって、コード・テンプレートを非常に単純化することができます。


次回は・・・

この記事では、XSLT 2.0で導入された新しい機能(特に拡張された言語機能と、生成するコードの中間モデルを構築できる機能)を紹介しました。そして、これらを使うことによって、抽象的なテーブル定義からSQLを生成する堅牢なジェネレータを構築できることを説明しました。

第2回では、Webサーバがデータベースにアクセスできるようにするための、PHP部分のコードの生成方法について説明します。また、さらに幾つかのXSLT 2.0の新機能も紹介します。


参考文献

  • このシリーズ2回目の記事、「 Code generation in XSLT 2.0, Part 2: Generate PHP with XSLT 2.0」(developerWorks, 2005年2月)も読んでください。

  • コード生成に関する情報源であるCode Generation Network をよく見てください。様々な記事やインタビュー、書評、コード生成に関する議論のための電子メールのリストなどがあります。

  • Jack D. Herrington著による、Code Generation in Action を読んでください。データベースのアクセスに限らず、多種多様な目的のコード生成について網羅されています。

  • Saxon をダウンロードしてください。SaxonはXSLT 2.0をサポートする素晴らしいXSLTプロセッサであり、この記事でも使われています。

  • この話題に関して将来有望なGenerative Programming について調べて見てください。この分野には、他の自動プログラミング技法に加えて、コード生成も含まれています。

  • XSLT 2.0やXPath 2.0についてさらに知りたい方は、Michael Kay著によるXSLT 2.0 Programmer's Reference がこの新しい標準(XSLT 2.0)のバイブルです。またXPath 2.0に関しては、Michael Kay著による姉妹編として、XPath 2.0 Programmer's Reference があります。

  • developerWorksのXMLゾーン には、XMLに関する資料が豊富に取り揃えられています。

  • XMLおよび関連技術においてIBM認証開発者になる方法についてはこちら を参照してください。

著者について

Jack D. Herringtonは、20年以上の経験を持つシニア・ソフトウェア・エンジニアです。著者には、「Code Generation in Action」、「Podcasting Hacks」、そして近々刊行予定の「PHP Hacks」の3冊があります。彼は30本以上の技術記事も執筆しています。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=243375
ArticleTitle=XSLT 2.0によるコード生成 第1回: XSLT 2.0でSQLを生成する
publish-date=02082005
author1-email=jherr@pobox.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。