XSLT 2.0で便利になった機能(21) Nodeのプロパティ関係の関数

ノードのプロパティ関係の新しい関数を紹介します.今回はあまりおもしろくありません.
 
■ data()
data()は、item()*をパラメータとしこれをatom化されたsequenceを返します.この関数はどうみても、schema-awareなXSLTプロセッサで意味があるものでしょう.例えば
 
 
としたとしても、attr属性がスキーマでどのような型で定義されているかわからなければ、その型にatom化できないからです.このような場合はstringになります.ただし、戻り型はxs:untypedAtomic*になります.これはxs:string*にキャストできますが、
 
    <xsl:variable name="data1" select="data(//element/@attr)" as="xs:string*"/>
 
とやっても、以下と
 
    <xsl:variable name="data1" select="//element/@attr" as="xs:string*"/>
 
変わらないと考えられます.
 
■ in-scope-prefixes()
in-scope-prefixes()はelement()をパラメータにとり、xs:string*でその要素に有効なnamespace prefixを返します.例えば、「閑話休題: Sequenceをパラメータに使う」で紹介したWordMLで、
 
<xsl:template match="w:wordDocument">
    <xsl:for-each select="in-scope-prefixes(.)">
        <xsl:message>No=<xsl:value-of select="position()"/> prefix="<xsl:value-of select="."/>"</xsl:message>
    </xsl:for-each>
</xsl:template>
 
とすると、
 
No=1 prefix="xml"
No=2 prefix="w"
No=3 prefix="wx"
 
と出力されます.この関数はXSL1.0では有効だったnamespace axis(XSLT2.0ではなくなった)の代用とされています.namespace prefixもあまり使用されなかったので、この関数もあまり使用される機会は少ないと思います.
 
■ namespace-uri-for-prefix()
namespace-uri-for-prefix()は、xs:stringのprefixと、element()をパラメータとして、対応するnamespace URIを返します.先ほどのテンプレートを以下のように書き換えてみます.
 
<xsl:template match="w:wordDocument">
    <xsl:variable name="currentElem" select="." as="element()"/>
    <xsl:for-each select="in-scope-prefixes(.)">
        <xsl:variable name="uri" select="namespace-uri-for-prefix(.,$currentElem)"/>
        <xsl:message>No=<xsl:value-of select="position()"/> prefix="<xsl:value-of select="."/>" URI="<xsl:value-of select="$uri"/>"</xsl:message>
    </xsl:for-each>
</xsl:template>
 
結果は以下のように出力されます.
 
 
この関数もあまり使われることはないと思います.
 
■ lang()
lang()は、言語コード(RFC3066)とオプションのnode()をパラメータに取って、その言語が対象のノードで有効であるか(継承されているか)を返します.例えば次のような入力に対して(ちょっと変なXMLですが)
 
<?xml version="1.0" encoding="UTF-8" ?>
<doc>
    <p xml:lang="ja">これは<ph>日本語の文章です</ph>が、英語の節
        <ph xml:lang="en">(phrase)</ph>
        も含まれています.
    </p>
</doc>
 
次のようなテンプレートを適用すると
 
<xsl:template match="*">
    <xsl:message>element=<xsl:value-of select="name()"/> lang("ja")=<xsl:value-of select="lang('ja')"/></xsl:message>
    <xsl:apply-templates/>
</xsl:template>
 
結果は
 
element=doc lang("ja")=false
element=p lang("ja")=true
element=ph lang("ja")=true
element=ph lang("ja")=false
 
と表示されます.xml:langが下位に継承されて判断されるのがわかります.
この関数、確かにある時点の要素で特定の言語が有効か判断するのには有用ですが、どちらかと言えば、(ancestor-or-self::*/@xml:lang)[last()]の方が有用に思えます.
ちなみにテンプレートを書き換えて
 
<xsl:template match="*">
    <xsl:variable name="lang" select="(ancestor-or-self::*/@xml:lang)[last()]"/>
    <xsl:message>element=<xsl:value-of select="name()"/> lang="<xsl:value-of select="$lang"/>"</xsl:message>
    <xsl:apply-templates/>
</xsl:template>
 
とすると、
 
element=doc lang=""
element=p lang="ja"
element=ph lang="ja"
element=ph lang="en"
 
のようにそのとき有効なxml:langを取得できます.
lang()は特定の言語の時にだけ行いたい処理を記述するために用いられるものなのでしょう.
 
■ root()
root()はnode()?をパラメータにとって、そのルートノードをnode()?として返します.戻り値がnode()?とあるのは入力が()のとき()を返すためです.ルートノードと言っても通常はDOMでいうところのdocument nodeです.document nodeは要素ではありません.
 
しかしXPath2.0ではdoument nodeでない場合もあります.例えば
 
<xsl:variable name="tempElem" as="element()">
    <doc>
        <p>Test of <ph xml:lang="en">root</ph> element</p>
    </doc>
</xsl:variable>
 
として、
 
<xsl:template match="/">
    <xsl:variable name="root" select="root($tempElem/p/ph)"/>
    <xsl:message>root element=<xsl:value-of select="name($root)"/></xsl:message>
</xsl:template>
 
とすると、
 
root element=doc
 
と表示されます.つまり、root()は親のないノードまでたどって、そのノードを返します.
この関数は、(ancestor-or-selef::node())[1]と等価とされています.この関数は"/"と似ていますが、"/"はコンテキストノードのルートノードを返し、それがドキュメントノードであることが必要という点が違います.root()の場合は任意のノードをパラメータとして指定でき、上位にドキュメントノードを必要としません.
 
■ unparsed-entity-public-id(), unparsed-entity-uri()
unparsed entityはXMLの解説書を見るとDTDのなかで例えば次のように定義されます.
<!ENTITY sample-jpeg SYSTEM "sample.jpg" PUBLIC "-//SAMPLE CORP//SAMPLE DATA/" NDATA JPEG>
NDATAはXMLデータでないことを示し、XMLの中では通常の実態参照ではなく属性で、
 
<img data="sample-jpeg">
 
のように参照されます.
例えば次のような入力ファイルに対して
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE img [
<!NOTATION JPEG PUBLIC "Jpeg picture format">
<!ENTITY sample-jpeg PUBLIC "-//SAMPLE CORP//SAMPLE JPEG/"  "file:///C:/sample/sample.jpg"   NDATA JPEG>
<!ELEMENT img EMPTY >
<!ATTLIST img data ENTITY #REQUIRED>
] >
<img data="sample-jpeg"/>
 
次のテンプレートは
 
<xsl:template match="img">
    <xsl:message>unparsed-entity-public-id(@data)=<xsl:value-of select="unparsed-entity-public-id(@data)"/></xsl:message>
    <xsl:message>unparsed-entity-uri(@data)=<xsl:value-of select="unparsed-entity-uri(@data)"/></xsl:message>
    <xsl:apply-templates/>
</xsl:template>
 
unparsed-entity-public-id(@data)=-//SAMPLE CORP//SAMPLE JPEG/
unparsed-entity-uri(@data)=file:///C:/sample/sample.jpg
 
と出力してくれます.でもunparsed entityお使いになりますか?私はXMLでは勉強はして頭の片隅にはありましたが、使った覚えがまったくありません.