本文へジャンプ

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


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

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

ヒント: SAXフィルターを使用してデータを操作する

SAXのストリームによりイベントの出力を変更する

Nicholas Chase (nicholas@nicholaschase.com), President, Chase and Chase, Inc.
Nicholas Chase は、Lucent Technologies や Sun Microsystems、Oracle、the Tampa Bay Buccaneers などの会社で Web 開発に携わってきました。彼は高校の物理の先生であり、低レベル放射性廃棄物施設の管理者であり、オンライン SF 雑誌の編集者であり、マルチメディアのエンジニアであり、Oracle インストラクターであり、あるインタラクティブ・コミュニケーション会社の最高技術責任者でもあります。『XML Primer Plus』(Sams 刊) を含めて、何冊かの著作があります。

概要: Simple API for XML (SAX) のストリーム・ベースの性格により、短時間で大量のデータを処理することだけでなく、基礎となるアプリケーションに影響を与えずに、ビジネス・ルールを実装する変更をストリームに挿入することが可能になります。このヒントでは、データの処理方法を制御するためにSAXフィルターを作成および使用する方法を説明します。

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


注: このヒントではJAXPを使用します。このクラスはJava 2 SDK 1.4の一部でもあるので、1.4をインストール済みでしたら他にソフトウェアを追加する必要はありません。SAXの基本的な点については簡単に説明しますが、JavaとXMLの基本的な点については事前に理解しておく必要があります。

このヒントでは、特定の緊急事態が生じたときの通知先となる従業員を決定し、それに応じて機能を果たすアプリケーションを考察します。(連絡そのものは、読者のために課題として残しておきます。)リスト1 に示すソース・ドキュメントは、単に従業員、部門、および状況をリストしたものに過ぎません。


リスト1. ソース・ドキュメント
                
<?xml version="1.0"?>
<personnel>
  <employeeempid="332" deptid="24" shift="night" status="contact">
    JennyBerman
  </employee>
  <employeeempid="994" deptid="24" shift="day" status="donotcontact">
    AndrewFule
  </employee>
  <employeeempid="948" deptid="3" shift="night" status="contact">
    AnnaBangle
  </employee>
  <employeeempid="1032" deptid="3" shift="day" status="contact">
    DavidBaines
  </employee>
</personnel>

基本的なアプリケーション

SAXアプリケーションは2つの部分から成り立っています。メイン・アプリケーションはXMLReader を作成します。これは、実際に文書を構文解析し、startElementendDocument などのイベントをコンテンツ・ハンドラーに送ります。エラーは、別個のエラー・ハンドラーに送ることができます。ハンドラー・オブジェクトは、これらのイベントを受け取って、処理します。

メイン・アプリケーションは、コンテンツ・ハンドラーまたはエラー・ハンドラー (あるいはその両方) として機能することもできますが、リスト2 では、これらを別個の3つのクラスとしています。



リスト2. メイン・アプリケーション
                
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.XMLReader;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import java.io.IOException;
       
public class MainSaxApp {
       public staticvoid main (String[] args){
    try {
       StringparserClass = "org.apache.crimson.parser.XMLReaderImpl";
         XMLReader reader = XMLReaderFactory.createXMLReader(parserClass);
       reader.setContentHandler(new DataProcessor());
         reader.setErrorHandler(new ErrorProcessor());
       InputSource file = new InputSource("employees.xml");
         reader.parse(file);
       } catch (IOException ioe) {
         System.out.println("IO Exception: "+ioe.getMessage());
       } catch(SAXException se) {
         System.out.println("SAX Exception: "+se.getMessage());
       } 
    }
       
}

リーダーのコンテンツ・ハンドラーをDataProcessor オブジェクトとするよう設定することにより、アプリケーションはリーダーに対して、イベントをこのオブジェクトに送るよう命じます。リスト3 に示すDataProcessor は単純なものであり、要素の名前と従業員の状況だけを調べて、従業員と連絡を取るかどうかを決めます。



リスト3. コンテンツ・ハンドラー
                
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
       
public class DataProcessor extends DefaultHandler
{
   public voidstartElement (String namespaceUri, String localName,
                           String qualifiedName, Attributesattributes) {
       if(localName.equals("employee")){
           if(attributes.getValue("status").equals("contact")){
              System.out.println("Contacting employee "+
                                 attributes.getValue("empid"));
              //Implement actual contact here
           }
       }
   }
}

ErrorProcessor クラスはそれほど重要ではありません。このクラスは、このヒント用のソース・コードに組み込まれています。(ソース・コードをダウンロードするには、参考文献を参照してください。)

アプリケーションを実行すると、どの部門に所属しているかに関係なく、状況の属性がcontact の従業員が全員出力に含まれることになります。

Contacting employee 332
Contacting employee 948
Contacting employee 1032
            


データのフィルター操作

現段階で、アプリケーションは、部門に関係なく、on duty (勤務中) としてリストされているすべての従業員と連絡を取ります。そして、これは正しく機能しています (あるいは、正しく機能するものと期待できます)。特定の部門の従業員だけと連絡を取るようにとの新しい要件を受け取った場合、選択肢は2つあります。

  • コンテンツ・ハンドラーを変更し、あらゆる種類の新しいバグが入り込む危険を冒す
  • コンテンツ・ハンドラーに送るデータを変更し、該当する従業員だけが勤務中と判断されるようにする

後で別の要件が追加されることも考えられますから、それぞれを別個に実装する方が理にかなっています。

SAXフィルターは、パーサーとコンテンツ・ハンドラーの間に位置します。パーサーからイベントを受け取ると、他の指示がない限り、変更を加えずにイベントをコンテンツ・ハンドラーに渡します。たとえば、リスト4 に示す、次のフィルターを考慮してみましょう。



リスト4. 単純なXMLフィルター
                
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
       
public class DataFilter extends XMLFilterImpl
{
       
}

XMLFilterImpl クラスには、変更を加えずに単にデータを渡すだけのメソッドが組み込まれています。必要なのは、メイン・アプリケーション内のストリームにフィルターを挿入することだけです (リスト5 を参照)。



リスト5. メイン・アプリケーションにフィルターを挿入
                
...
          XMLReader reader = XMLReaderFactory.createXMLReader(parserClass);
DataFilter filter = new DataFilter();
          filter.setParent(reader);
          filter.setContentHandler(new DataProcessor());
filter.setErrorHandler(new ErrorProcessor());
filter.parse("employees.xml");    } catch (IOException ioe) {
...

アプリケーションは従来どおりにXMLReader を作成します。しかし、実際にファイルの構文解析を開始するのはフィルターです。フィルターは、自分の親であるXMLReader からイベントを受け取ると、構文解析を開始します。(覚えておいていただきたい点ですが、フィルターはsuper(parent) を呼び出します。)フィルターは、イベントをコンテンツ・ハンドラーに渡します。これは、元のバージョンで使用したのと同じ、DataProcessor オブジェクトです。

現時点で、フィルターは、変更を加えることなくイベントを渡すだけなので、アプリケーションを実行しても、得られる出力は次のとおりで前と変わりがありません。

Contacting employee 332
Contacting employee 948
Contacting employee 1032

しかし、フィルターを適用すれば、メイン・アプリケーションを修正しないで、容易に変更を加えることができます。たとえば、リスト6 で、フィルターは、部門24に所属しない従業員を全員除外します。そのために行うことは、この部門に属さない従業員の状況をdonotcontact に設定することだけです。



リスト6. データのフィルター操作
                
...
import org.xml.sax.helpers.AttributesImpl;
public class DataFilter extends XMLFilterImpl
{s
  public void startElement (String namespaceUri, String localName,
                        String qualifiedName, Attributes attributes)
                         throws SAXException
  {
    AttributesImpl attributesImpl = new AttributesImpl(attributes);
    if (localName.equals("employee")){
      if (!attributes.getValue("deptid").equals("24")){
          attributesImpl.setValue(3, "donotcontact");
      }
    }
    super.startElement(namespaceUri, localName, qualifiedName, attributesImpl);
  }
}

この場合、XMLFilterImpl に定義されているstartElement() メソッドをオーバーライドすることになります。依然としてイベントの受け渡しを行うものの、従業員が部門24に所属していない場合、フィルターが、この従業員にリストされているAttributes オブジェクトをdo not contact に変更して、イベントを渡します。

DataProcessor オブジェクトは、データが操作されたことを知りません。このオブジェクトは、連絡を取るべき従業員と、連絡を取るべきでない従業員がいることしか知りません。処理の結果の出力は、次のように変わります。

Contacting employee 332


次なるステップは

このヒントでは、XMLフィルターを使ってSAXアプリケーションの処理を変更するための簡単な方法を示しました。この場合、フィルターは事前に定義されたものでした。しかし、フィルターの動作を実行時に選択することにより、さまざまな状況に対応するアプリケーションを構築することもできます。これは、DataFilter クラスを置換することで実現できるでしょう。そのためには、パラメーターを実行時に渡すことや、あるいは最初にフィルター・クラスを作成するファクトリーを使用することさえできるかもしれません。

SAXアプリケーションでは、複数のフィルターを連鎖させ、1つのフィルターの出力を別のフィルターの入力とすることができます。これにより、モジュラーのチャンクを使って複雑なプログラミングが可能になります。


参考文献

著者について

Nicholas Chase

Nicholas Chase は、Lucent Technologies や Sun Microsystems、Oracle、the Tampa Bay Buccaneers などの会社で Web 開発に携わってきました。彼は高校の物理の先生であり、低レベル放射性廃棄物施設の管理者であり、オンライン SF 雑誌の編集者であり、マルチメディアのエンジニアであり、Oracle インストラクターであり、あるインタラクティブ・コミュニケーション会社の最高技術責任者でもあります。『XML Primer Plus』(Sams 刊) を含めて、何冊かの著作があります。

不正使用の報告のヘルプ

不正使用の報告

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


不正使用の報告のヘルプ

不正使用の報告

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


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=242325
ArticleTitle=ヒント: SAXフィルターを使用してデータを操作する
publish-date=10012002
author1-email=nicholas@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com

タグ

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

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

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

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

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