Home of: [工房 "藤車"] > [SourceForge.net における SASAX]

要素の反復

本節では、 SASAX を用いて、 反復される要素を解析する方法を説明します。

文書構造の定義

XML Schema によるスキーマおよび文書例を "文書構造" に示します。

XML Schema によるスキーマ:

<xs:schema 
  targetNamespace="http://www.lares.dti.ne.jp/~foozy/"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:local="http://www.lares.dti.ne.jp/~foozy/">

  <xs:simpleType name="int">
    <xs:restriction base="xs:integer"/>
  </xs:simpleType>

  <xs:element name="list">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="int" type="local:int" 
          minOccurs="0" maxOccurs="unbounded"
          form="qualified"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

例:

<foozy:list
 xmlns:foozy="http://www.lares.dti.ne.jp/~foozy/">
  <foozy:int>
      12345678
  </foozy:int>
  <foozy:int>
      23456789
  </foozy:int>
  <foozy:int>
      34567890
  </foozy:int>
  <foozy:int>
      45678901
  </foozy:int>
</foozy:list>

文書構造

対象文書が以下の特徴を持つことがわかります。

要素オブジェクト(群)の生成

前述の文書を解析するためのオブジェクト群は、 "要素オブジェクト(群)の生成" に示すようにして生成されます。


String uri = "http://www.lares.dti.ne.jp/~foozy/"

CompositeElement listElement =
    new CompositeElement(null, uri, "list");

ElementRepetition repetition =
    new ElementRepetition(listElement);

// "repetition" を
// "listElement" 配下に登録する
listElement.addMustItem(repetition);

IntElement intElement =
    new IntElement(repetition, uri, "int");

// "intElement" を
// "repetition" による反復対象に設定
repetition.setElement(intElement);

要素オブジェクト(群)の生成

コンストラクタ引数を見れば、 "intElement" が "listElement" ではなく "repetition" の子要素であることに気が付くでしょう。 "ElementRepetition" は、 オブジェクト構造上は中間要素であるかのように振舞いますが、 XML 文書構造上は透過的な要素となります。

反復される要素の解析であるにも関わらず、 IntElement インスタンスが唯一つしか生成されていないことにも気が付くでしょう。 ElementRepetition は、 "setElement()" されたインスタンスを各反復ごとに再利用するのです。 このことが中間オブジェクトの生成コストを低減させます。

備考: ElementRepetition の利用で問題が発生する場合は、 (1)ElementRepetition#setElement(Element) 起動の有無と、 (2)反復対象要素の親要素指定を確認してください。

反復された値の取得

解析の際には、反復された整数値を格納したいと思うでしょう。

反復における確定毎に値を取得する方法の一つは、 "notifyDetermined(ParseContext)" メソッドをオーバライドすることです。


final LinkedList list = new LinkedList();

String uri = "http://www.lares.dti.ne.jp/~foozy/"

CompositeElement listElement =
    new CompositeElement(null, uri, "list");

ElementRepetition repetition =
    new ElementRepetition(listElement);

IntElement intElement =
    new IntElement(repetition, uri, "int"){
        protected void notifyDetermined(ParseContext context){
            list.add(getInteger(false));
        }
    };

// "intElement" を
// "repetition" による反復対象に設定
repetition.setElement(intElement);

値確定の通知 (1)

getInteger() の引数に関する詳細は、 "固有要素" ないし API ドキュメントを参照してください。

値の確定通知を受け取るもう一つの方法は、 "Notification" を使用するものです。 オーバライドによるアプローチの利用は十分単純で容易な選択肢ですが、 Notification の利用をお勧めします。


final LinkedList list = new LinkedList();

String uri = "http://www.lares.dti.ne.jp/~foozy/"

CompositeElement listElement =
    new CompositeElement(null, uri, "list");

ElementRepetition repetition =
    new ElementRepetition(listElement);

IntElement intElement =
    new IntElement(repetition, uri, "int");

Notification notification = new Notification(){
    public void elementStarted(Element element,
                               ParseContext context,
                               Attributes attributes)
        throws SAXException
    {
        // NOP
    }

    public void elementEnded(Element element,
                             ParseContext context)
        throws SAXException
    {
        list.add(((IntElement)element).getInteger(false));
    }
};

intElement.addNotification(notification);

// "intElement" を
// "repetition" による反復対象に設定
repetition.setElement(intElement);

値確定の通知 (2)

ちなみに、ElementRepetition は、 NotificationelementEnded() メソッドを 反復の終了時に起動します。ですので、 Notification の登録は、繰り返したい要素に対して行ってくだ さい。

文書の解析

"文書の解析" に示すコードにより、 XML 文書を解析することが出来ます。


ElementDrivenHandler handler =
    new ElementDrivenHandler(listElement);

handler.parse(reader);

文書の解析

ElementDrivenHandler#parse 起動後、 反復された "intElement" が格納した整数値を list から得ることが出来ます。

チュートリアル本節におけるコードの完全なものは、 配布物の src/demo/sasax/src 配下にある jp.ne.dti.lares.foozy.sasax.RepetitionDemo です。 このクラスはバイナリ配布版中の demo.jar に含まれています。


次節「固有要素」へ

詳細情報

クラス図

本節におけるクラス図を以下に示します。

クラス図
クラス図 (クリックで拡大表示)

オブジェクト図

本節におけるオブジェクト図を以下に示します。

オブジェクト図
オブジェクト図 (クリックで拡大表示)

シーケンス図

ElementDrivenHandler、CompositeElement および Element 実装クラスにおける処理フローは以下のようになります。

  1. ElementDrivenHandler が ElementRepetition の "startElement" を起動
  2. ElementRepetition は Element(現状は IntElement) に "startElement" を委譲
  3. IntElement は次のイベント受領者として自身を返却
  4. ElementDrivenHandler は "intElement" を次のイベント受領者として保持
  5. ElementDrivenHandler は "intElement" のメソッドを起動
  6. .....
  7. ElementDrivenHandler は IntElement の "endElement" を起動
  8. IntElement は自身の "notifyDetermined" を起動
  9. IntElement は次のイベント受領者として "repetition" を返却
  10. ElementDrivenHandler は "repetition" を次のイベント受領者として保持
  11. ElementDrivenHandler は "repetition" のメソッドを起動

加えてシーケンス図を以下に示します。

シーケンス図
シーケンス図 (クリックで拡大表示)

クラス名

本チュートリアルでは、 クラスは全てクラス名のみで表記されています。 完全な名称は以下の通りです。

表記完全名
AbstractElement jp.ne.dti.lares.foozy.sasax.AbstractElement
CompositeElement jp.ne.dti.lares.foozy.sasax.CompositeElement
ElementDrivenHandler jp.ne.dti.lares.foozy.sasax.ElementDrivenHandler
ElementRepetition jp.ne.dti.lares.foozy.sasax.ElementRepetition
IntElement jp.ne.dti.lares.foozy.sasax.IntElement
Notification jp.ne.dti.lares.foozy.sasax.Notification
ParseContext jp.ne.dti.lares.foozy.sasax.ParseContext