2010年3月21日日曜日

Oracle BPEL/string-join

入力メッセージ中の繰り返し要素を、区切り文字で連結して他のサービスに渡したりするようなコーディングは良くあると思う。例えば、検索用の Webサービスが外部にあるとして、これに渡す条件文を組み立てたりするのが典型的か。

この部分を 敢えてBPEL だけで書いたらこんな風になるけど...
...実際にはそんなフローを書く人は少ない。BPEL やワークフローを体系的に勉強していなくても、こんな粒度の細々したステップを書くのはまずかろうと、いくらなんでも普通は気づく(IDE は JDeveloper)。

で XSLT で書いたりするが、惜しいかな、いかにも手続き型っぽいこんな感じのコードが多い。
<xsl:template match="/">
<client:processResponse>
<client:result>
<xsl:for-each select="/client:process/client:input">
<xsl:choose>
<xsl:when test="position() > 1">
<xsl:text>,</xsl:text>
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</client:result>
</client:processResponse>
</xsl:template>
JDeveloper の XSLマップ デザイナ前提だと手続き型になるしかないけど、上記コードは実はこの時点でデザイナが使えなくなってる。<for-each> の使い方が違うとか、<choose> 内には<when> 要素が必要だとか意味不明なことを言ってくるが、見ての通りそんな問題は存在しない。

というわけで、これ以上糞ツールに気を使っても面白くないので、XSLT らしく関数型で書いてみる。
<xsl:template match="/">
<client:processResponse>
<client:result>
<xsl:apply-templates select="client:process/client:input[1]"/>
</client:result>
</client:processResponse>
</xsl:template>

<xsl:template match="client:input[following-sibling::client:input]">
<xsl:value-of select="."/>
<xsl:text>-</xsl:text>
<xsl:apply-templates select="following-sibling::client:input[1]"/>
</xsl:template>

<xsl:template match="client:input[not(following-sibling::client:input)]">
<xsl:value-of select="."/>
</xsl:template>
繰り返し文や条件文を全否定する気はサラサラないけど、関数型の書法の方が応用が利くので、こっちの方がお勧め。

もう一個の改善点は、XSLT 変換の範囲。

上記コードは、もともと Transform アクティビティ生成の結果作られたものを書き直したものなので、BPEL側の<assign>ではメッセージタイプからメッセージタイプへの変換になっている。従って、client:processResponse がもっと複雑な構造だと、<xsl:template match="/"> の中に 要素の複製や空要素の生成など無駄なコードが大量発生がちなので、次はこれを改善。
<xsl:template match="/">
<xsl:apply-templates select="client:process/client:input[1]"/>
</xsl:template>

<xsl:template match="client:input[following-sibling::client:input]">
以下同文

上記コードの出力は連結したテキストのみとなるので、このXSLTの出力を受ける BPEL 内の<to>要素に query 属性で processResponse/client:result を指定しておけば、最小限の要素をピンポイントで指定したコードになる。(XSLT内に<xsl:output method="text"/>も含めておく)

実は、更にもう一段階ある。

どうも JDeveloperでは、標準的な XSLT 関数なのに IDE的にサポートされていないものがあるらしい。例えば document()関数なども、ドロップダウンリストに表示されなかったりする。

ここまで例として取り上げてきた文字列の連結では、string-join 関数が使える。せっかく再帰で書いた上の XSLTコードがもったいないけど、実は 3行で書けちゃったりする。
<xsl:template match="/client:process">
<xsl:value-of select="string-join(client:input, ',')"/>
</xsl:template>

うーん、なんだか今日はずいぶん無駄なコードを書いたかも・・・

0 件のコメント:

コメントを投稿