前回に続き、今回は独自の関数を登録する方法を見ていきます(記事一覧)。
XPath インターフェースに定義されている FunctionContext アクセッサ
XPath インターフェースには、VariableContext 同様、FunctionContext オブジェクトに対するアクセッサメソッドが定義されています:
package org.jaxen; public interface XPath { ... FunctionContext getFunctionContext(); void setFunctionContext(FunctionContext context); }
org.jaxen.FuncticonContext インターフェースについては後ほど。
関連する型
独自関数は FunctionContext インターフェースを介して扱います。 自分で FunctionContext インターフェースを実装したクラスを作成することもできなくはありませんが、Jaxen ライブラリに定義されてある XPathFunctionContext クラスを用いるほうが良いでしょう。 理由は後ほど。
- FunctionContext インターフェース
- SimpleFunctionContext クラス (implements FunctionContext)
- XPathFunctionContext クラス (extends SimpleFunctionContext)
FunctionContext インターフェース
FunctionContext インターフェースには、VariableContext インターフェース同様、関数名(名前空間 URI 、接頭辞、ローカル名)を指定して関数オブジェクト (org.jaxen.Function オブジェクト) を取得するメソッドが定義されています:
package org.jaxen; public interface VariableContext { Function getFunction(String uri, String prefix, String localName) throws UnresolvableException; }
FunctionContext#getFunction() に関しても、VariableContext#getVariableValue() と同様の注意事項があります:
Function オブジェクトの詳細は次回。
SimpleFunctionContext クラス
SimpleFunctionContext クラスには FunctionContext インターフェースに定義されているメソッドに加えて、関数名と関数オブジェクトの組を登録するメソッドが定義されています:
package org.jaxen; public class SimpleFunctionContext implements FunctionContext{ public SimpleFunctionContext(){...} @Override public Function getFunction(String uri, String prefix, String localName) throws UnresolvableException{...} public void registerFunction(String uri, String localName, Function function) {...} }
注意をいくつか:
- 登録する関数は Function オブジェクトなので、関数の評価 (evaluate) がこの関数オブジェクトの状態に依存してしまうと意図しない結果を返す可能性があります。 基本的には状態を持たない (stateless) ようにすべきでしょう。
- 既に登録されている関数と同名の関数を登録すると、その関数は上書きされます。
- この SimpleFunctionContext クラスは XPath 1.0 のコア関数ライブラリ (core function library) を返しません。 したがって、独自のコア関数ライブラリを実装するのでなければ、次に見る XPathFunctionContext クラスを使用しましょう。
XPathFunctionContext クラス
XPathFunctionContext クラスは SimpleFunctionContext クラスを継承し、デフォルトで XPath のコア関数ライブラリが登録されているクラスです。 新に定義されているインスタンスメソッドはありません:
package org.jaxen; public class XPathFunctionContext extends SimpleFunctionContext{ public XPathFunctionContext(){...} public XPathFunctionContext(boolean includeExtensionFunctions){...} @Override public Function getFunction(String uri, String prefix, String localName) throws UnresolvableException{...} @Override public void registerFunction(String uri, String localName, Function function){...} public static FunctionContext getInstance(){...} }
既に登録されている関数と同名の関数を登録すると、(たとえコア関数ライブラリでも)関数が上書きされます。
boolean を引数にとるコンストラクタは、Jaxen 独自の関数を使用するかどうかを指定します。 引数がないコンストラクタはこのコンストラクタで true を指定したものと同じです。
Jaxen 独自の関数には次の4つが定義されています:
関数 | シグネチャ*1 | 返り値の型 | 説明 |
---|---|---|---|
evaluate() | evaluate(string) | node-set | (おそらく)引数の文字列を XPath 式として評価し、結果をノードセットとして返します。 |
upper-case() | upper-case(string) | string | 引数の文字列を大文字に変換します。 |
lower-case() | lower-case(string) | string | 引数の文字列を小文字に変換します。 |
ends-with() | ends-with(string, string) | boolean | 第1引数の文字列が第2引数の文字列で終わるかどうかを返します。 |
独自関数を登録する
以下では具体的に同時変数を登録するサンプルコードを見ていきます。 (通常そうであろう)名前空間を扱わない場合のみ載せてます。 検索対象となる XML 文書は適当に想像して読んで下さい。
独自関数を登録して使用する手順は以下の通り:
- 独自の関数(Function インターフェースの実装クラス)を作成する
- XPathFunctionContext オブジェクトを生成する
- XPathFunctionContext オブジェクトに関数を登録する
- XPath に XPathFunctionContext オブジェクトをセットする
まず独自関数を。 この関数は、単に文字列 "dependency" を返すだけです。
class TargetFunction implements Function{ @Override public String call(Context context, @SuppressWarnings("unchecked") List args){ return "dependency"; } }
で、この関数を登録して使うサンプルコード。 XML 文書の中から "dependency" というローカル名の要素を捜して返します:
org.dom4j.Document doc = ... // 検索対象の Document オブジェクト XPath xpath = new Dom4jXPath("//*[local-name() = target()]"); // 1. XPathFunctionContext オブジェクトを生成する XPathFunctionContext context = new XPathFunctionContext(); // 2. XPathFunctionContext オブジェクトに関数を登録する context.registerFunction(null, "target", new TargetFunction()); // 3. XPath に XPathFunctionContext オブジェクトをセットする xpath.setFunctionContext(context); @SuppressWarnings("unchecked") List<Element> result = xpath.selectNodes(doc); // 検索結果に対して処理を行う