倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Jaxen 苦闘 (7) :独自の変数を登録する

前回までで、Jaxen の基本的な使い方は終わり。

今回は独自の変数を登録して使用する方法を見ていきます(記事一覧)。

XPath インターフェースに定義されている VariableContext アクセッサ


XPath インターフェースには VariableContext オブジェクトに対するアクセッサメソッドとして、getter と setter メソッドが定義されています:

package org.jaxen;

public interface XPath {
    ...
    VariableContext getVariableContext();
    void setVariableContext(VariableContext context);
}

org.jaxen.VariableContext インターフェースについては後で。 具体的な扱い方は、さらにその後で。

関連する型


独自変数は VariableContext インターフェースを介して扱います。 自分で VariableContext インターフェースを実装したクラスを作成しても構いませんが、基本的にはその単純実装 (?) である SimpleVariableContext クラスを用いる方が簡単です。

  • VariableContext インターフェース
  • SimpleVariableContext クラス (implements VariableContext)

VariableContext インターフェース

VariableContext インターフェースには、変数名(名前空間 URI 、接頭辞、ローカル名)を指定して変数に格納されている値を取得するメソッドのみが定義されています:

package org.jaxen;

public interface VariableContext {
    Object getVariableValue(String uri, String prefix, String localName) 
            throws UnresolvableException;
}

独自の VariableContext の実装クラスを作成する場合、

  • 変数に格納されている値を取得する際に、接頭辞は結果に影響を与えてはいけません。 これはデバッグやエラーハンドリングのために使用します。
  • 接頭辞がない場合は、名前空間 URI に null が指定されます。

ということに注意する必要があります。 また、変数値の型は基本的には何でも構いませんが、「XPath 1.0 に定義されているデータ型」で定義されている4つの型にしておく方が良いかと。

ちなみに、UnresolvableException (org.jaxen.UnresolvableException) は変数の解決に失敗した際に投げられる例外です*1

SimpleVariableContext クラス

SimpleVariableContext クラスは VariableContext インターフェースに定義されているメソッドに加えて、変数名と変数値の組を登録するメソッドが定義されています。 名前空間 URI がある場合とない場合の2つがあります:

package org.jaxen;

public class SimpleVariableContext implements VariableContext{

    public SimpleVariableContext(){...}

    @Override 
    public Object getVariableValue(String uri, String prefix, String localName)
            throws UnresolvableException{...}

    public void setVariableValue(String localName, Object value){...}
    public void setVariableValue(String uri, String localName, Object value){...}
}

独自変数を登録する


以下では具体的に同時変数を登録するサンプルコードを見ていきます。 (通常そうであろう)名前空間を扱わない場合と、扱う場合を載せてます。 どちらも SimpleVariableContext クラスを用いています。 検索対象となる XML 文書は適当に想像して読んで下さい。

名前空間を使用しない場合

独自変数を登録して検索をする手順は以下の通り:

  1. SimpleVariableContext オブジェクトを生成する
  2. SimpleVariableContext オブジェクトに変数を登録する
  3. XPath オブジェクトに VariableContext オブジェクトをセットする

以下のサンプルコードは、コメントでちょっとゴチャゴチャしてますが、

  • XPath 式に "$target" として target という変数を参照している
  • target 変数の値として "dependency" という文字列をセットしている

などに注意して見て下さい:

        org.dom4j.Document doc = ...  // 検索対象の Document オブジェクト

        XPath xpath = new Dom4jXPath("//*[local-name() = $target]");
        
        // 1. SimpleVariableContext オブジェクトを生成する
        SimpleVariableContext context = new SimpleVariableContext();
        // 2. SimpleVariableContext オブジェクトに変数を登録する
        context.setVariableValue("target", "dependency");
        // 3. XPath オブジェクトに VariableContext オブジェクトをセットする
        xpath.setVariableContext(context);
        
        @SuppressWarnings("unchecked")
            List<Element> result = xpath.selectNodes(doc);
        
        // 検索結果に対して処理を行う

@SuppressWarnings("unchecked") はあまり気にしないで下さいな。

名前空間を使用する場合

概ね上記の「名前空間を使用しない場合」と同じですが、XPath オブジェクトへの名前空間の設定で1行増えてます:

        org.dom4j.Document doc = ...  // 検索対象の Document オブジェクト

        XPath xpath = new Dom4jXPath("//*[@angle > ($m:pi / 2.0)]");
        xpath.addNamespace("m", "mathematics");  // 接頭辞と名前空間 URI の登録
        
        SimpleVariableContext context = new SimpleVariableContext();
        context.setVariableValue("mathematics", "pi", Math.PI);
        xpath.setVariableContext(context);
        
        @SuppressWarnings("unchecked")
            List<Element> result = xpath.selectNodes(doc);
        
        // 検索結果に対して処理を行う

*1:関数の解決に失敗した際にも投げられます。