XSLT 2.0で便利になった機能(40) instance of演算子

今回はinstance of演算子を紹介します.instance of演算子は、例えば組み込み型で使ってみると以下のようになります.
 
5 instance of xs:integer は true を返します.
5 instance of xs:positiveInteger は false を返します(!).
"5" instance of xs:integer は false を返します.
"5" instance of xs:string は true を返します.
 
ちなみに
 
"5" castable as  xs:integer は true を返します.
xs:positiveInteger(5) instance of xs:positiveInteger  は true を返します.
 
いかがでしょうか?instance of演算子は、castable asなどというある意味ではいい加減(?)な演算子と違い、左辺に「くくりつけられた型」が右辺の型に等しいかtrue/falseで返します.つまり厳密です.
 
ですから組み込み型で試してみても全然おもしろくありません.5 は xs:integer だし、"5" は xs:string に決まっているからです.
 
本当のinstance ofの使い方はschema-awareなXSLTプロセッサを使って、XML Schemaでvalidationしたデータを処理する用途ではないかと思います.schema-awareなXSLTプロセッサということで今回はAltova XMLをつかってみました.
 
[入力データ: input.xml]
<?xml version="1.0" encoding="UTF-8" ?>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="input_schema.xsd">
    <product type="pencil" maker="三菱"     price="100"/>
    <product type="pencil" maker="コーリン" price="90"/>
    <product type="pencil" maker="トンボ"   price="110"/>
    <product type="pencil" maker="北星"     price="105"/>
    <product type="note"   maker="コクヨ"   price="NA"/>
    <product type="note"   maker="ツバメ"   price="NA"/>
    <product type="note"   maker="マルマン" price="NA"/>
</data>
 
[XML Schema: input_schema.xsd]
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="data" type="dataType"/>
    <xs:complexType name="dataType">
        <xs:sequence>
            <xs:element ref="product" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:element name="product" type="productType"/>
    <xs:complexType name="productType">
        <xs:attribute name="type" type="xs:string"/>
        <xs:attribute name="maker" type="xs:string"/>
        <xs:attribute name="price" type="priceType"/>
    </xs:complexType>
    <xs:simpleType name="priceType">
        <xs:union memberTypes="NotAvailableType xs:positiveInteger" />
    </xs:simpleType>
    <xs:simpleType name="NotAvailableType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="NA"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>
 
ポイントは、product/@price属性です.値段が入っているものと、"NA"(Not Availableの意味)のものがあります.入力データを読み込んで値段の合計と、"NA"と入っているものの個数を表示します.スタイルシートは次のようになります.(抜粋)
 
[スタイルシート: test.xsl]
<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs" >
<xsl:import-schema schema-location="input_schema.xsd"/>
...
<xsl:template match="data">
    <xsl:variable name="prices" select="data(product/@price)" as="item()*"/>
    <xsl:message select="'Total price:', sum($prices[. instance of xs:positiveInteger])"/>
    <xsl:message select="'Not avalable count:', count($prices[. instance of  NotAvailableType])"/>
</xsl:template>
...
コマンドライン AltovaXML.exe /xslt2 test.xsl /in input.xml /out result.xml で試してみると、結果は次のようでした.
 
XSL message: Total price: 405
XSL message: Not avalable count: 3
 
ちゃんと合っています.もちろんXMLスキーマなど使わなくとも同じ機能のスタイルシートは書けるでしょう.
 
    <xsl:variable name="prices" select="product/@price" as="attribute()*"/>
    <xsl:message select="'Total price:', sum($prices[string(.) ne 'NA'])"/>
    <xsl:message select="'Not avalable count:', count($prices[string(.) eq 'NA'])"/>
 
でも最初のスタイルシートのように厳粛にinstance ofを使うのがschema-awareなXSLTプロセッサを使った場合のスタイルシートの流儀(?)ではないかと一人ひそかに考えております.