XPathの式処理は、勧告によれば「static analysis phase」と「dynamic evaluation phase」の二つのフェーズから構成されているとされます.「static analysis phase」は文字通り"静的"に式を評価します.この際スキーマでvalidationされた入力データがどうであろうが関係ありません.式自体が解釈/評価されます.「dynamic evaluation phase」は、データが入力され式の値が実際に計算される際に行われます.
例えば次のようなデータを考えてみます.
[入力データ]
<?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="三菱" unitPrice="100"/>
<product type="pencil" maker="コーリン" unitPrice="90"/>
<product type="pencil" maker="トンボ" unitPrice="110"/>
<product type="pencil" maker="北星" unitPrice="105"/>
<product type="note" maker="コクヨ" unitPrice="NA"/>
<product type="note" maker="ツバメ" unitPrice="NA"/>
<product type="note" maker="マルマン" unitPrice="NA"/>
</data>
<?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="三菱" unitPrice="100"/>
<product type="pencil" maker="コーリン" unitPrice="90"/>
<product type="pencil" maker="トンボ" unitPrice="110"/>
<product type="pencil" maker="北星" unitPrice="105"/>
<product type="note" maker="コクヨ" unitPrice="NA"/>
<product type="note" maker="ツバメ" unitPrice="NA"/>
<product type="note" maker="マルマン" unitPrice="NA"/>
</data>
[スキーマ]
<?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="unitPrice" type="unitPriceType"/>
</xs:complexType>
<xs:simpleType name="unitPriceType">
<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>
<?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="unitPrice" type="unitPriceType"/>
</xs:complexType>
<xs:simpleType name="unitPriceType">
<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>
このときdata(@unitPrice)は、どうなるでしょうか?「static analysis phase」では、スキーマに従えば、unitPriceTypeになります.ですから、第一パラメータに明示的にxs:positiveIntegerを要求するような次のような関数に渡すとすればエラーを報告すると考えられます.
tmf:calcPrice(data(@unitPrice),2)
<xsl:function name="tmf:calcPrice" as="xs:string">
<xsl:param name="prmUnitPrice" as="xs:positiveInteger"/>
<xsl:param name="prmNumber" as="xs:integer"/>
<xsl:sequence select="string($prmUnitPrice * $prmNumber)"/>
</xsl:function>
<xsl:param name="prmUnitPrice" as="xs:positiveInteger"/>
<xsl:param name="prmNumber" as="xs:integer"/>
<xsl:sequence select="string($prmUnitPrice * $prmNumber)"/>
</xsl:function>
treat as演算子はこのような場合、
tmf:calcPrice(data(@unitPrice) treat as xs:positiveInteger, 2)
とするとstatic typeとしてオペランドのxs:positiveIntegerを返します.ですのでこの関数呼び出しの記述は「static analysis phase」をパスします.
「dynamic evaluation phase」ではどうでしょうか?上記の例では、data(@unitPrice)がxs:positiveIntegerにマッチすれば、その値を返します.もし万が一マッチしない場合、dynamic errorが報告されます.つまりここでは、treat asは、C++言語のassert()のような役割を果たしてくれます.
試しに
<xsl:template match="product">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="price"
select="if (data(@price) instance of NotAvailableType)
then
string('0')
else
tmf:calcPrice(data(@unitPrice) treat as xs:positiveInteger,2)"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="price"
select="if (data(@price) instance of NotAvailableType)
then
string('0')
else
tmf:calcPrice(data(@unitPrice) treat as xs:positiveInteger,2)"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
としてみます.上記の例のデータでは動作します.ではスキーマとデータの一部を次のように変えてみます.
[スキーマ]
<xs:simpleType name="unitPriceType">
<xs:union memberTypes="OutOfStockType NotAvailableType xs:positiveInteger" />
</xs:simpleType>
<xs:simpleType name="NotAvailableType">
<xs:restriction base="xs:string">
<xs:enumeration value="NA"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="OutOfStockType">
<xs:restriction base="xs:string">
<xs:enumeration value="OS"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="unitPriceType">
<xs:union memberTypes="OutOfStockType NotAvailableType xs:positiveInteger" />
</xs:simpleType>
<xs:simpleType name="NotAvailableType">
<xs:restriction base="xs:string">
<xs:enumeration value="NA"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="OutOfStockType">
<xs:restriction base="xs:string">
<xs:enumeration value="OS"/>
</xs:restriction>
</xs:simpleType>
[入力データ]
<product type="note" maker="コクヨ" unitPrice="OS"/>
<product type="note" maker="コクヨ" unitPrice="OS"/>
実行してみると、
Couldn't cast to destination type - found 'OS' of type User defined, expected ty
pe xs:positiveInteger - xs:positiveInteger
pe xs:positiveInteger - xs:positiveInteger
とちゃんとエラーになります.(XPathで定義されているXPDY0050とは違うところが心配ですが...)
いずれにしてもtreat asはschema-awareでstatic type chekingを行うXSLTプロセッサを使ってXMLスキーマでvalidationした入力データを扱う局面で威力を発揮するようですね.