Jintrick.netagenda2003年01月アーカイブ → 2003年01月22日

XSLT 1.0で正規表現を使う(MSXML限定)/ XPathのstring-value

XSLT 1.0にはビルトイン関数があります。しかしそれらはXPathの文法やデータモデルに従ったものなのだから、XSLTの関数というより、XSLTで使用できるXPathの拡張だと思うのは私だけでしょうか。それはさておき、XPathの関数をMSXMLの独自要素を利用して定義する形で、XSLT内で正規表現を使ってみようという話です。

MSXML(4.0)を使う利点は、今のところ二つ程認識しています。一つは高速であるということ。もう一つは、スクリプト言語で簡単にXPath関数を拡張できるという点です。ところがこの二つの利点は同時に成り立ちません。独自に関数を定義するとスクリプトエンジンを起動するので処理が遅くなるのだそうです。ですから利用する際には気をつけたほうが良いと思います。

具体例

XPathのビルトイン関数にcontains関数というブール値を返す関数がありますが、これに似た、正規表現が使用可能な機能強化版を作ってみます。

まず、普通にJScriptの関数を書きます。

function contains(_str, _sReg)
{
  var re = new RegExp(_sReg);
  return re.test(_str);
}

これは、第一引数(文字列)の中に、第二引数(文字列として表現された正規表現)で表された正規表現にマッチする文字列が存在した場合にtrue, そうでなければfalseを返却するJScript関数です。

注意点
関数の戻り値はXPath 1.0で扱えるデータ型に従って「ノードリスト、文字列、ブール値、数値」の何れかにします。配列オブジェクトなどを戻り値にしてしまうと多分エラーが出るでしょう(もしくはtoString関数が適用されるかも知れません)。引数も同様、XPath 1.0で扱えるデータ型でなければなりません。例えば正規表現オブジェクトを引数にしたつもりで/reg/g等と記述すれば、g要素とやらを含んだノードリストとして評価されてしまいます。因みに、XPathの仕様書ではノードリストはnode set(ノード集合)となっていますが、MSXMLユーザ的にはDOM互換の「ノードリスト」という概念で考えた方が色々と便利です。

次に、作成したJScript関数を、msxsl:script要素の内容としてトップレベル(xsl:stylesheet要素の直下)に配置します。

<msxsl:script language="JScript" implements-prefix="jtr">
function contains(_str, _sReg) {
	var re = new RegExp(_sReg);
	return re.test(_str);
}
</msxsl:script>

language属性に、使用するスクリプト言語を指定します。JScript、JavaScriptで確認しました。implements-prefix属性の値は、関数名(Qname)にくっつけるXML名前空間の接頭辞です。urn:schemas-microsoft-com:xsltと一緒にスコープ内(ルート要素かその辺)で宣言しておく必要があります。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:jtr="http://purl.org/jintrick/schema/personnel"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="jtr msxsl"
>

<msxsl:script language="JScript" implements-prefix="jtr">
function contains(_str, _sReg) {
	var re = new RegExp(_sReg);
	return re.test(_str);
}
</msxsl:script>
</xsl:stylesheet>

これで、例えば次のようにしてこのユーザー定義関数を呼び出すことが出来ます:

<xsl:template match="foo">
 <xsl:choose>
  <xsl:when test="jtr:contains(string(self::node()), '\s')">
   <p>空白文字を検出しました。</p>
  </xsl:when>
  <xsl:otherwise>
   <p>空白文字はありません。</p>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

foo要素の子孫ノードの文字列値に空白文字(半角スペース、タブ文字、改行文字等)が含まれているかどうかで条件分岐しています。

XPathのstring-valueについて

前述の最後の例のどこに「子孫ノード」なんていう表現があるのかと思った方はXML Path Language (XPath) (英語) の5. Data Modelを参照してください。XPathでは、ノードはそれぞれstring-valueという特別なプロパティを持っていることになっています。要素ノードにおいては、子孫の(DOMでいう)nodeValueを文書順(document order)に継ぎ足した値になります。string関数はこのstring-valueを取り出すわけです。極めて重要な約束事だと思うのですが、仕様書以外ではお目にかかった試しがありません。手持ちの本(付録のリファレンスしか使っていない)でも、何だかはぐらかしてあります。 関係ないけどp.533の非XMLなXML Schemaインスタンスは何時になったら訂正されるのだろう 訂正されました(XML SQUARE 正誤表


webmaster@jintrick.net
公開: 2003年01月22日
カテゴリ: XPath ,XSLT