パッケージ org.apache.struts.digester

Digester パッケージは、独自の XML 文書をルールに基づいて処理する機能を提供します。

参照:
          説明

クラスの概要
CallMethodRule 後続の CallParamRule または、当該要素のボディから収集した引数を渡して、 最上位(親)オブジェクトのメソッドを呼び出すルールを実装しています。
CallParamRule CallMethodRule ルールに関連して呼び出され利用される、 要素の属性またはそのボディのどちらか一方からパラメータを取り出し保存するルールを実装しています。
Digester Digester は、 一連のネストした要素のパターンを検出することによって実行されるルールを、 パースの開始前に追加し、 それによって XML 入力ストリームの処理を行います。
ObjectCreateRule 新しいオブジェクトを生成しオブジェクトスタックへプッシュするルールを実装しています。
Rule このクラスの具象的な実装を行うと、XML 要素の中から相応のネストしたパターンが検出された際の動作を組み込むことができます。
SetNextRule 最上位(子)オブジェクトを引数として渡し、 (top-1)(親)オブジェクトのメソッドを呼び出すルールを実装しています。
SetPropertiesRule 対応する名前を持つ属性を元に、 スタックの最上位オブジェクトが持つ複数のプロパティの設定を行うルールを実装しています。
SetPropertyRule 対応する名前の属性を元に、 スタックの最上位オブジェクトが持つ個々のプロパティの設定を行うルールを実装しています。
SetTopRule (top-1)(子)オブジェクトを引数として渡し、 最上位(親)オブジェクトのメソッドを呼び出すルールを実装しています。
 

パッケージ org.apache.struts.digester の説明

Digester パッケージは、独自の XML 文書をルールに基づいて処理する機能を提供します。

[はじめに] [プロパティの設定] [オブジェクトスタック] [要素のパターン照合] [プロセッシングルール] [使用例]

はじめに

XML 形式のデータに対応したアプリケーション環境では "イベント駆動" 方式によって XML 文書の処理が行えると便利です。 "イベント駆動" 方式では、ネストした XML 要素の中から特定のパターンを検出したときに、特定の Java オブジェクトが生成されます(または既存のオブジェクトのメソッドが呼び出されます)。 Simple API for XML Parsing (SAX) による XML 文書のパース[訳注:解析]に精通したデベロッパは、 Digester がより高いレベルの、もっとデベロッパにとって使いやすい SAX イベントのインターフェースを提供していることに気が付くでしょう。 そのため、XML 階層構造の細部をほとんど意識する必要がありません -- デベロッパは、パースした結果の処理に専念することができます。

Digester を使用する手順として、次の基本的なステップが必要になります:

Digester のプロパティの設定

org.apache.struts.digester.Digester インスタンスには、いくつかのプロパティがあり、それを操作しカスタマイズすることができます。 それらのプロパティはパースに影響を及ぼします。 parse() メソッドのひとつを呼び出す前に必ず設定して下さい。

プロパティ 説明
debug この整数値は、デバッグ時にパースの経過を System.out() に出力し、その出力量を定義します。 これはパース時に発生した問題を追跡する際に役立ちます。 デフォルトの値は 0 で、デバッグ出力を行いません -- 0 以上の値を設定するとより多くの、 そして詳細なデバッグ情報を生成します。
validating このブール値は true を設定することで DOCTYPE 宣言で定義されたドキュメントタイプ定義 (DTD) に対する XML 文書の妥当性を検査します。 デフォルトの値は false で、 "妥当な" ではなく "整形式" の XML 文書を単に検出します。

上のプロパティの定義に加えて、ローカルにコピーしたドキュメントタイプ定義 (DTD) を DOCTYPE 宣言の参照に、追加して記述することができます。 システム外を参照するパブリックな識別子を伴う DOCTYPE 宣言を検出したときに、 XML パーサはそのような記述を識別して、実際には DOCTYPE 宣言のものではなく、 常にその記述したシステム識別子 (URL) の指す DTD の内容を利用するでしょう。

例えば、 Struts フレームワークを動かしているサーブレットは、 Struts 設定ファイルを参照する際に、ローカルにコピーされた DTD を使うよう、 Struts に指示します。 これは Struts がインターネットへ接続せずに環境設定を行えるようにし、 (それがネットワークへの接続を回避するため) インターネットサイトへの接続を伴う処理と比べてスピードアップを図れます。

    digester.register
      ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
       "/org/apache/struts/resources/struts-config_1_0.dtd");

ちなみに、この例のなかで使用されているシステム識別子は、 java.lang.ClassLoader.getResource() または java.lang.ClassLoader.getResourceAsStream() へ渡されるパスです。実際の DTD リソースは、全ての Struts クラスを(大抵は struts.jar ファイルから) ロードする、それらと同一のクラスローダによってロードされます。

オブジェクトスタック

org.apache.struts.digester.Digester テクノロジの最も一般的な使用法は、 動的に Java オブジェクトのツリーを構築するというものです。ツリーの内部構造は、 (ツリー内のオブジェクトの細かいプロパティ設定を行ったかのように) XML ドキュメントの内容に基づいた設定がなされます。 実際、 Digester パッケージを作成した主な理由は、 Struts のコントローラサーブレットが自身の設定を簡単に、 アプリケーション配下にある struts-config.xml ファイルの内容に基づいて行えるようにすることでした。

使い方を簡単にするために、 Digester はスタックを開示していて、それを、 要素の照合パターンを満たした場合に発生するプロセッシングルールから操作できるようにしています。 利用できる一般的なスタック関連の操作を、次に示します:

典型的な設計手法では、特定の XML 要素を見つけたときに、特定のルールを発生させ、 そこで新しいオブジェクトを生成しスタックへプッシュします。 そのネストが処理されている間オブジェクトはそこに置かれ、そして要素の最後に到達したときにポップされます。 この標準 "オブジェクト生成" プロセッシングルールは、 とても便利な方法として、この機能の実現に一役買っています。

Digester のこの機能とは別の特性が投げかける、設計手法に関して危惧されるいくつかの問題点:

要素のパターン照合

org.apache.struts.digester.Digester パーサの主な特徴は、 Digester が XML ドキュメント要素の階層構造を自動的に検索してくれるため、 デベロッパがプロセスを意識する必要がないことです。 その代わり、 XML ドキュメントのパースに際して、 検出したい要素のネスト構造と、 そのとき、どのような機能を実行すればよいのかを決めることに専念します。 このような仕組みのことを要素のパターン照合と呼びます。

最もシンプルな要素の照合パターンは "a" のような単純な文字列でしょう。 このパターンは、XMLドキュメントの中で <a> が最上位要素として現れるすべての箇所と(何回でも)一致します。 ですが、ネストの中に <a> という要素がある場合には、このパターンと一致しません -- この種のパターン照合に関してこの後、述べていきます。

次に "a/b" の組み合わせにステップアップします。 このパターンは <a> を最上位の要素としたネストの中に <b> が見られる場合に一致します。 先程も言った通り、 XML ドキュメントの内容に従った回数だけ一致します。 複数のスラッシュを使って検索したい階層構造の深さをはっきりさせることで、 適切な照合を行うことができます。

例として、 "a"、 "a/b"、 そして "a/b/c" というパターンを検出するプロセッシングルールが登録してあるものと仮定します。 次の内容のような XML ドキュメントが入力された場合、パースによって、 それぞれのパターンは対応する要素と一致します:

  <a>         -- "a" と一致
    <b>       -- "a/b" と一致
      <c/>    -- "a/b/c" と一致
      <c/>    -- "a/b/c" と一致
    </b>
    <b>       -- "a/b" と一致
      <c/>    -- "a/b/c" と一致
      <c/>    -- "a/b/c" と一致
      <c/>    -- "a/b/c" と一致
    </b>
  </a>

さらに、パターン文字列の中で "*" ワイルドカード文字を使用することによって、 特定の XML 要素がどれだけネストしていても(またはネストしていなくても) 検索することができます。 例えば、<a> がドキュメント中のネストのどの位置にあっても、 "*/a" という要素の照合パターンで検出することができます。

そのため、ひとつ要素がパースされたとき、 複数の登録されたプロセッシングルールに対応するパターンを検出する可能性も十分にあります (複数のプロセッシングルールを同じ照合パターンに登録したか、 厳密な照合パターンとワイルドカードによる照合パターンの両方が同じ要素によって満たされたため)。 その場合、Digester に登録した順番の最初から、対応する全てのプロセッシングルールが発生します。

プロセッシングルール

前節の記述では、 どうすれば思い通りのタイミングで処理を行えるか、その方法を説明しました。 プロセッシングルールの目的は、あるパターンを検出したときに何をすればいいのかを定義することです。

形式的なことを言えば、プロセッシングルールとは org.apache.struts.digester.Rule を実装した Java クラスのことです。 各々のルールには下記のイベントメソッドがひとつ以上組み込まれ、 検出したパターンに対応するルールが発生したときに定義されている限り何度でも呼び出されます:

Digester を設定した後、addRule() メソッドを呼び出すことで、 要素の照合パターンを、上記のタイミングで呼び出される、イベントを捕捉するメソッドを持つ Rule クラスのインスタンスと一緒に登録することができます。 この仕組みによって、 アプリケーションに様々な機能を組み込むために、 動的に Rule を実装したクラスを生成することができます。

加えて、プロセッシングルールを実装したクラスのセットが提供されており、 多くのプログラミングに共通するシナリオに対処できます。次にそのクラスを記述します:

上述したように、 digester.addRule() を呼び出すことによって、 標準の Rule クラスのインスタンスを生成し、登録することができます。 しかしながら、そのような方法は汎用的なものなので、短縮して記述できるよう、各標準ルールを Digester クラスに直接、登録するためのメソッドが定義されています。 次にコード例を示します:

    Rule rule = new SetNextRule(digester, "addChild",
                                "com.mycompany.mypackage.MyChildClass");
    digester.addRule("a/b/c", rule);

このように置き換えられます:

    digester.addSetNext("a/b/c", "addChild",
                        "com.mycompany.mypackage.MyChildClass");

使用例

Struts 設定ファイルの操作

前述したように、 org.apache.struts.digester.Digester パッケージは、Struts コントローラサーブレット自身が Struts ベースアプリケーションのあらゆる局面についての設定を struts-config.xml に記述し、その内容を処理する、頑丈で、柔軟な、簡単に拡張できるメカニズムを実現するために在ります。 このことで、コントローラサーブレットが包括的な、また実装面での Digester を使用する事例になるといえます。 Digester を使用するために、その生成と設定をする方法については org.apache.struts.action.ActionServlet クラスの initDigester() メソッドを、 また実際にどこでパースを行っているのかについては initMapping() メソッドを参照してください。

ここからは、Digester のいくつかの特徴を活かした使用法を解説するために、 いくつかの照合パターンとプロセッシングルールの構成に焦点を当てて述べます。 まず、 どのようにして Digester インスタンスが生成され、初期化されるのかを見てみましょう:

    Digester digester = new Digester();
    digester.push(this);
    digester.setDebug(detail);
    digester.setValidating(true);

ここでは Digester インスタンスが生成され、パーサの妥当性検査を有効にしているのがわかります。 (前述したように)妥当性検査は、Struts に含まれる struts-config_1_0.dtd DTD に対して行われます。 設定されたオブジェクトを追跡できるようにする意味で、コントローラサーブレットのインスタンスは、 自身を Digester 内にあるスタックに追加しています。

    digester.addObjectCreate("struts-config/global-forwards/forward",
                             forwardClass, "className");
    digester.addSetProperties("struts-config/global-forwards/forward");
    digester.addSetNext("struts-config/global-forwards/forward",
                        "addForward",
                        "org.apache.struts.action.ActionForward");
    digester.addSetProperty
      ("struts-config/global-forwards/forward/set-property",
       "property", "value");

これらの記述で、グローバルフォワード宣言を処理するためルールが生成されます。 こうすることで <forward> 要素を見つけた場合に、次のような動作をします:

その後、Digester は以下のように実行されます:

    InputStream input =
      getServletContext().getResourceAsStream(config);
    ...
    try {
        digester.parse(input);
        input.close();
    } catch (SAXException e) {
        ... deal with the problem ...
    }

parse() の呼び出しの結果、 struts-config.xml ファイルで定義された全ての設定情報は、Struts のコントローラサーブレット内にキャッシュされたオブジェクトの集合として表され、 サーブレットコンテキスト属性として利用することができます。

XML ファイルのボディテキスト解析

Digester モジュールは XML ファイルの単純な要素や属性ばかりでなく、 ネストされたボディテキストも処理することがでます。 以下の例は、カレント web アプリケーションのための、 web アプリケーションのための配備記述子( /WEB-INF/web.xml )をパースし、 特定のサーブレットのために設定情報を記録する必要がある、 という仮定を基づいたものです。 この情報を記録する上で、以下のようなメソッド(など)を持つ Bean クラスがあるものと仮定します:

  package com.mycompany;
  public class ServletBean {
    public void setServletName(String servletName);
    public void setServletClass(String servletClass);
    public void addInitParam(String name, String value);
  }

典型的な Struts ベースアプリケーションのコントローラサーブレットを宣言する web.xml ファイルの処理に関して見ていきます (この例では簡潔にするために要約しています):

  <web-app>
    ...
    <servlet>
      <servlet-name>action</servlet-name>
      <servlet-class>org.apache.struts.action.ActionServlet<servlet-class>
      <init-param>
        <param-name>application</param-name>
        <param-value>org.apache.struts.example.ApplicationResources<param-value>
      </init-param>
      <init-param>
        <param-name>config</param-name>
        <param-value>/WEB-INF/struts-config.xml<param-value>
      </init-param>
    </servlet>
    ...
  </web-app>

次に、この入力ファイルのための Digester プロセッシングルールを定義しましょう:

  digester.addObjectCreate("web-app/servlet",
                           "com.mycompany.ServletBean");
  digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
  digester.addCallMethod("web-app/servlet/servlet-class",
                         "setServletClass", 0);
  digester.addCallMethod("web-app/servlet/init-param",
                         "addInitParam", 2);
  digester.addCallParam("web-app/servlet/init-param/param-name", 0);
  digester.addCallParam("web-app/servlet/init-param/param-value", 1);

すると、次の処理が行われ、要素がパースされます:


[訳注: これは樋田 佳之が翻訳しました。日本語訳に対するコメントがあれば、report@jajakarta.orgに送って下さい。]



このドキュメントは、Ja-Jakartaにより訳されました。コメントがある場合は、report@jajakarta.orgまでお願いします。
Copyright (C) 2000-2002 - Apache Software Foundation