第32章 XPath 言語

概要

XML メッセージを処理する際に、XPath 言語を使用すると、メッセージの Document Object Model (DOM) に作用する XPath 式を指定して、メッセージの一部を選択することができます。また、要素や属性の内容をテストするための XPath 述語を定義することもできます。

32.1. Java DSL

基本的な式

xpath("Expression") を使用して、現在のエクスチェンジで XPath 式を評価することができます (XPath 式は現在の In メッセージのボディーに適用されます)。xpath() 式の結果は、XML ノード (または複数のノードが一致する場合はノードセット) になります。

たとえば、現在の In メッセージボディーから /person/name 要素の内容を抽出し、それを使用して user という名前のヘッダーを設定するには、以下のようなルートを定義することができます。

from("queue:foo")
    .setHeader("user", xpath("/person/name/text()"))
    .to("direct:tie");

setHeader() の引数に xpath() を指定する代わりに、Fluent Builder xpath() コマンドを使用することができます。たとえば、

from("queue:foo")
    .setHeader("user").xpath("/person/name/text()")
    .to("direct:tie");

結果を特定の型に変換する場合は、xpath() の第 2 引数に結果の型を指定します。たとえば、結果の型が String であることを明示的に指定するには、次のようにします。

xpath("/person/name/text()", String.class)

Namespaces

通常、XML 要素はスキーマに属し、名前空間 URI によって識別されます。このようなドキュメントを処理する際には、名前空間 URI と接頭辞を関連付けておく必要があり、XPath 式の中で要素名を明確に識別できるようにします。Apache Camel はヘルパークラス org.apache.camel.builder.xml.Namespaces を提供しています。これにより、名前空間と接頭辞の関連付けを定義することができます。

たとえば、接頭辞 cust を名前空間 http://acme.com/customer/record と関連付けて、要素 /cust:person/cust:name コンテンツを抽出するには、以下のようなルートを定義します。

import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");

from("queue:foo")
    .setHeader("user", xpath("/cust:person/cust:name/text()", ns))
    .to("direct:tie");

Namespaces オブジェクト ns を追加の引数として渡すことで、xpath() 式ビルダーで名前空間の定義を利用できるようにします。複数の名前空間を定義する必要がある場合は、以下のように Namespace.add() メソッドを使用します。

import org.apache.camel.builder.xml.Namespaces;
...
Namespaces ns = new Namespaces("cust", "http://acme.com/customer/record");
ns.add("inv", "http://acme.com/invoice");
ns.add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

結果の型を指定し、さらに名前空間も定義する必要がある場合は、以下のように xpath() の 3 つの引数形式を使用できます。

xpath("/person/name/text()", String.class, ns)

名前空間の監査

XPath 式を使用する際に最も頻繁に発生する問題の 1 つは、受信メッセージに表示される名前空間と XPath 式で使用される名前空間の間に不一致があることです。この種の問題のトラブルシューティングを支援するために、XPath 言語では、すべての受信メッセージからすべての名前空間をシステムログにダンプするオプションがサポートされています。

INFO ログレベルでネームスペースロギングを有効にするには、以下のように Java DSL で logNamespaces オプションを有効にします。

xpath("/foo:person/@id", String.class).logNamespaces()

あるいは、org.apache.camel.builder.xml.XPathBuilder ロガーで TRACE レベルのロギングを有効にするようにロギングシステムを設定することもできます。

名前空間のロギングを有効にすると、処理されたメッセージごとに以下のようなログメッセージが表示されます。

2012-01-16 13:23:45,878 [stSaxonWithFlag] INFO  XPathBuilder  -
Namespaces discovered in message: {xmlns:a=[http://apache.org/camel],
DEFAULT=[http://apache.org/default],
xmlns:b=[http://apache.org/camelA, http://apache.org/camelB]}