タグ別アーカイブ: XPath

XProcの紹介

makeが良い、悪い」という話が一部で盛り上がっているのを見ました。
結局ツールなので、「用途に向いていなくても慣れなどを取る」か「学習が必要でも別のものを使う価値が見合う」かといった、状況に合わせた選択が必要になるでしょう。個人的にはファイルの絶対パスをハードコードするのは可能な限り避けてほしいですが。

ビルドツールにも様々な得手不得手があるものですが、XMLに特化したものもあります。そんな導入で、XProcの話題です。

XProc: An XML Pipeline LanguageはXML文書やその他の処理を記述するための言語です*1
W3CのページのAbstractには“Pipelines generally accept zero or more XML documents as input and produce zero or more XML documents as output.”とあります。ステップ処理として記述ができる、ファイル操作についてもある程度はできるなど他にもありますが、XSLTとは目的も書き味も結構違います。

2010年に1.0がW3C仕様として勧告された後、勧告としてはそれが最新の状態がまだ続いています。しかし、2020年8月19日にXProc 3.0の最終ドラフトが上がっており*2、期待が持てるようになってきました。Editor’s Draftは8月31日に更に更新されていますが。ちなみに2.0は諸般の事情で見送られています。

また、XMLPressから2020年4月に『XProc 3.0 Programmer Reference』(Erik Siegel)*3が刊行されています。W3CのXProc仕様のEditorであるNorman Tovey-Walsh氏による推薦文もついていますし、Erik Siegel氏も XProc 3.0 editorial teamのメンバーです。
XProc 3.0についてはドラフト版仕様とこの本を読むのが確実でしょう。

XProc 3.0でのもっとも大きな改良点はXSLT同様にXPath 3.1に対応したことだと思いますが、今回はXProcの雰囲気だけ紹介します。


<!-- 1. Pipeline document: -->
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0">

  <!-- 2. Pipeline port declarations: -->
  <p:input port="source" primary="true" />
  <p:output port="result" primary="true" />
  <!-- 3. Convert document to HTML: -->
  <p:xslt>
    <p:with-input port="stylesheet" href="xsl/basic-conversion.xsl" />
  </p:xslt>
</p:declare-step>

上のコードは『XProc 3.0 Programmers Reference』*3「Getting started with XProc」にある例です。
<p:declare-step>がルート要素です。inputやoutputを省略できる<p:pipeline>も使用できますが、
2行程度では大して労力は変わらないですね。

XMLSchemaのネームスペースが宣言されているのは、XSLT同様asで型を明示できるからです。

書かれた処理を簡単に書けば、「入力をxsl/basic-conversion.xslのXSLTで処理し、出力へ渡す」ということになります。しかし、よくわからないプロパティportの存在がありますね。それぞれの指定で想像が付くかと思いますが、inputによる入力を処理対象(source)というportにつなぎ、with-inputによる入力は(XSLT)スタイルシートというportにつなぎ、このスタイルシートによってsourceを処理します。そしてresultというportにつながった出力へ結果を渡す、という流れです。こう書くと同語反復をしているように感じられるかと思いますが、それぞれのportにきたものをステップ処理していく流れが直観に近い記述で書けるということです。他のportとしては、スキーマの検証のスキーマを渡すためのschemaなどがあります。
<p:xslt><p:validate-with-xml-schema>はデフォルトのstepです。portは決まったstepと結びついていて、portに渡したものは結びついたstepが記述されていれば、そのstepで処理されます。デフォルトのstepとport、そして独自のstepと結びついた独自のportを記述していくことがXProcの基本となります。

*1 https://www.w3.org/TR/xproc/
*2 https://spec.xproc.org/lastcall-2020-08/head/xproc/
*3 https://xmlpress.net/publications/xproc-3-0/



XSLT 3.0(XPath 3.1)JSONをXMLに変換せずに利用する

先週はXMLの形にしたJSONを、XMLにしないまま扱う方法について紹介します。CSLはでてきません。

XPath 3.1*1で名前にJSONが入る関数は4つです。

  • fn:parse-json($json-text as xs:string?, $options as map(*))
  • fn:json-doc($href as xs:string?, $options as map(*))
  • fn:json-to-xml($json-text as xs:string?, $options as map(*))
  • fn:xml-to-json($input as node()?, $options as map(*))

$optionsについては説明しません。JSONをテキストとして引数にとるのがfn:parse-json()fn:json-to-xml()
fn:json-doc()は外部JSONファイルを読み込むときなどに指定します。fn:unparsed-text()で取得したテキストをfn:parse-json()へ適用するのと
大体同じことを行います。今回取り上げるのはfn:parse-json()fn:json-doc()についてです。

mapとarray

関係する名前空間は次に挙げるものです。

  • fn=”http://www.w3.org/2005/xpath-functions”
  • map=”http://www.w3.org/2005/xpath-functions/map”
  • array=”http://www.w3.org/2005/xpath-functions”

XPath 3.1のmap構造とarray構造は一般的なプログラミング言語におけるそれとほぼ同じもので、JSONオブジェクトをそのままの形で格納できます。
先週登場したJSONを見てみましょう。

{
    "items": [
        {
            "id": "7646893/2E3MJB9A",
            "type": "book",
            "title": "スタイルシート開発の基礎",
            "publisher": "アンテナハウス株式会社",
            "publisher-place": "Tokyo",
            "event-place": "Tokyo",
            "ISBN": "978-4-900552-23-4",
            "language": "ja",
            "author": [
                {
                    "family": "アンテナハウス株式会社",
                    "given": ""
                }
            ],
            "issued": {
                "date-parts": [
                    [
                        2016,
                        5
                    ]
                ]
            }
        }
    ]
}

このJSONを外部ファイルとして取り込むには次のように記述します。

<xsl:param name="input" >'exported-data.json'</xsl:param>
...
<xsl:variable as="map(*)" name="jsonMap" select="fn:json-doc($input)"/>
<!-- または -->
<xsl:variable as="xs:string" name="json-text" select="fn:unparsed-text($input)"/>
<xsl:variable as="map(*)" name="jsonMap" select="parse-json($json-text)"/>

XMLに変換した先週と、mapやarrayを活用する今回はこの後がまったく異なります。

次の記述で、先頭のtitleを一息で取得します。

<xsl:value-of select="map:get(array:head(map:get($jsonMap, 'items')), 'title')" />

まず、最も外側のmapから、itemsのキーを持つ要素を取得します(map:get($jsonMap, 'items'))。
キーitemsの値はarray型です。このままmap:get()を行おうとしてもできませんから、arrayの先頭を取り出すarray:head()を使用しています。ところで上の記述はパイプ演算子を使えば次のように書けます。

<xsl:value-of select="map:get($jsonMap, 'items') => array:head() => map:get('title')" />

mapのarrayでは、map:find()を利用することで指定したキーの値を配列で得ることもできます。挙動の詳細はXPath 3.1*1かXSLT 3.0*2のページを確認してください。

typeの値が何種類かに決まっていて、その種類を元にif文の判定をしたいのであれば、次のように書けます。

     <xsl:variable as="map(*)" name="item" select="map:get($jsonMap, 'items') => array:head()" />
      <xsl:if test="map:get($item,  'type') =  'book' or 'proceedings'">
      <xsl:value-of select="map:get($item, 'type')" /> <!-- book -->
      </xsl:if>

もちろんXMLの構造に変換しても同じことはできますが、より一般的なプログラミング言語に近い形で扱えています。

mapやarrayとして扱うために、JSONテキストとして記述してパースしたり、select="map{"key":value}"のような書き方をする以外に、<xsl:map><map-entry>を使うことができます。

mapの操作はエントリの追加やキー指定での削除などの他、map:merge()によるmapの統合、map:for-each()によるmap要素単位での関数適用などが可能です。arrayの方はarray:fold-left()array:fold-right()の畳み込み関数や、array:for-each()でarrayの要素ごとに関数適用などなど、XML形式を扱うよりもすっきりした構文で記述が可能な関数が用意されています。

注意しなければならないこととして、mapであるかarrayであるかを間違えるとうまく値を取り出せません。$itemnodeでもないので、直接xml-to-json()は使えません。

仕様やSaxonのドキュメントとにらめっこをしながら紹介してきたXSLT 3.0とXPath 3.1のJSONの扱いですが、誤りなどありましたらご指摘ください。

*1 https://www.w3.org/TR/xpath-31/
*2 https://www.w3.org/TR/xslt-30/


参考資料



XSLTを学ぶ (11)論理値(Boolean)と関連する基本的な関数のいくつか

第9回[1]では、式の生成規則を辿っている途中に幾つかわからない項目が出てきました。その一つは、ノード集合に対する演算の扱いです。ここでは論理演算や比較の演算におけるノード集合の扱いを調べてみます。

論理値(Booleans)[2]

or式は左辺と右辺の両方のオペランドをboolean関数と同じように論理値に変換して評価します。どちらかが真であれば真となり、そうでないとき偽となります。boolean関数はXPathで規定するコア関数の一種であり、引数を論理値に変換します。ノード集合は空でないとき真となります(詳しくは下に紹介しました)。

and式は両方のオペランドをboolean関数と同じように論理値に変換して評価します。両方が真であれば真となります。そうでないとき偽となります。

第9回の規則[23]の関係式(RelationalExpr)すなわち <=、<、>=、>、および等価式(EqualityExpr)すなわち=または!=、は左辺と右辺の二つのオペランドを次のように比較します。(ノード集合が関係するときだけを取り上げてみます。)

ノード集合同士を比較するときは、最初のノード集合と二つ目のノード集合の中に、ノードの文字列値同士を比較したときに真になるようなノードが含まれている時に限り、その比較は真になります。

ノード集合と数値の比較では、ノードの文字列値をnumber関数で数値に変換し、数値同士として比較します。ノード集合の中に、数値同士を比較して真になるようなノードが含まれていれば、比較が真になります。

ノード集合と文字列値の比較では、ノードの文字列値と他方の文字列値を比較し、文字列値同士を比較して真になるようなノードが含まれていれば、比較が真になります。

ノード集合と論理値の比較では、ノード集合をboolean関数で論理値にして、他方の論理値と比較します。

XPathには基本的な関数が規定されています。次に今日出てきた関数を紹介します。

boolean関数[3]
形式: boolean boolean(object)

boolean関数は引数を次のように論理値に変換します。
・数値は、ポジティブゼロでもネガティブゼロでもなく、NaN(Not-a-Number:数値でない)でもないとき真となります。
・ノード集合は空でないとき真となります。
・文字列は、長さがゼロでないとき真となります。
・四つの基本型以外のオブジェクトはその型依存の方法で論理値に変換されます。

number関数[4]
形式: number number(object?)

number関数は引数を次のように論理値に変換します。
・数値の後が空白で、前にオプションのマイナス記号、さらにその前のオプションの空白から構成される文字列は、その文字列によって表現される数学的値に最も近いIEEE 754数に変換されます。それ以外の文字列はNaNに変換されます。
・論理値の真は1に変換され、論理値の偽は0に変換されます。
・ノード集合は最初にstring関数を使ったように文字列に変換され、次いで引数が文字列のときと同様に数値に変換されます。
・四つの基本型以外のオブジェクトはその型依存の方法で数値に変換されます。

もし、引数が省略されたときは、既定値として文脈ノードのみから成るノード集合が使われます。

string関数[5]
形式: string string(object?)

文字列関数はオブジェクトを次のように文字列に変換します。
・ノード集合はノード集合の中で文書順で最初のノードの文字列値を返すことで文字列値に変換されます。ノード集合が空のときは空文字列が返されます。
・数値は次のように文字列に変換されます。
 ・NaNは文字列NaNに変換されます。
 ・ポジティブゼロは文字列0に変換されます。
 ・ネガティブゼロは文字列0に変換されます。
 ・ポジティブな無限大は文字列Infinityに変換されます。
 ・ネガティブな無限大は文字列-Infinityに変換されます。
 ・数値が整数型のときは、小数点や先行するゼロのない十進数で表現されます。数値がマイナスのときは、マイナス記号が先行します。
 ・整数でないときは、小数点を含み、小数点の前に少なくとも1個の十進数があり、小数点の後に少なくとも1個の十進数があり、マイナスのときは、マイナス記号が先行する形式となります。不要な先行するゼロがあってはならず、少数点の後には他のIEEE 754と区別するのに必要なだけの数値がなければなりません。
・論理値の偽は文字列falseになり、論理値の真は文字列trueになります。
・四つの基本型以外のオブジェクトはその型依存の方法で文字列に変換されます。

もし、引数が省略されたときは、既定値として文脈ノードのみから成るノード集合が使われます。

なお、string 関数は表示用に整形するために用意されているものではありません。整形にはXSLTのxsl:number要素を使います。

[1] XSLTを学ぶ(9)ステップの文法を追求する-述部(Predicates)と式
[2] 3.4 Booleans
[3] boolean関数
[4] number関数
[5] string関数

前回:
XSLTを学ぶ(10)式によるノード集合の作成、ノード集合の和集合、フィルター式

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (10)式によるノード集合の作成、ノード集合の和集合、フィルター式

前回[1]の定義[19]にあるようにロケーションパスをパス式として使うことができます。そのときパス式はロケーションパスによって選択したノードの集合を返します。

ノードの集合は、’|’オペレータで和集合にできます(前回の定義[18])。定義[18]だけでは分かりませんが、XPath仕様書[2]には「オペランドはノード集合でなければならない」とされています。

以上により、の中では、ロケーションパスでノード集合を作り、ノード集合の和集合を作ることができます。

定義[19]では、パス式の生成方法にFilterExpr(フィルター式)を使う方法もあります。フィルター式には、FilterExprの後に述部(Predicate)を付けるものがあります。このときの述部は「ロケーションパスで使われるときと同様に式をフィルターするために使われる。フィルターされる式がノード集合にならなければエラーとなる。述部は、ノード集合をchild軸に関してフィルターする」とされています。

つまり、パス式がFilterExpr Predicateで生成されるとき、FilterExprはノード集合でなければなりません。

FilterExprは基本式(PrimaryExpr)で構成されます。基本式の中でノード集合を生成できるのは、VariableReference(変数参照)、()で囲った式、FunctionCallです。

[15] PrimaryExpr ::= VariableReference
| ‘(‘ Expr ‘)’
| Literal
| Number
| FunctionCall

前回述部に二種類あることに注意しましたが、この違いは()で囲った式と組み合わせると明確になります。

XML文書中で、例えばpが要素ノードであるとき、パス式p(child::p)自体は基本式ではありませんが、(p)は基本式です。

述部[]と組み合わせたとき、次の二種類となります。
(1) p[1]はステップであり、ロケーションパスです。
(2) それに対して、(p)[1]はフィルター式です。

この場合は違いは明確ではありませんが、次のような場合は違いが明確になります。

preceding::foo[1] と(preceding::foo)[1]の比較

preceding軸の定義は次のようになっています。「起点ノードと同じ文書の中で、文書順で起点ノードの前にあるすべてのノードを含みます。但し、先祖と属性ノードと名前空間ノードは除外します。」(XPath 2.2 Axes)

軸には文書順の軸と、逆文書順の軸があります。起点ノードと起点ノードよりも文書の中で後のノードを含む軸は文書順の軸です。起点ノードと起点ノードよりも文書の中で前方のノードを含む軸は逆順の軸です。preceding軸は、逆順の軸に属します(XPath 2.4 Predicates)。

ノード集合のメンバーの軸に関する近接位置(proximity position)とは、文書順の軸ではメンバーを文書順に並べたときの順番、逆順の軸では文書で出現する順序の逆に並べたときの順番です。

そして、述部[]はノード集合を絞り込んで新しいノード集合を作ります。述部の中の式は、ノード集合の各ノードを起点のノードとし、近接位置を文脈位置として評価します。評価結果が真であれば、そのノードは新しいノード集合に含まれます。

そこで、preceding::foo[1] は起点ノードの先行ノードであるfoo要素ノードを文書の逆順にたどり、そのときの1番目のfoo要素ノードを選択します。

(preceding::foo)[1] は[1]に適用する軸はchild軸なので先行ノードであるfoo要素の集合の最初のノードを選択します[3]

[1] XSLTを学ぶ(9)ステップの文法を追求する-述部(Predicates)と式
[2] XML Path Language (XPath) Version 1.0
[3] 3.3 Node-setsには、このように書かれています。ちょっと強弁の印象がありますが。

【広告】
Formatter(XML)関連技術書、PDF関連書籍ご紹介

次回:
XSLTを学ぶ (11)論理値(Boolean)と関連する基本的な関数のいくつか

前回:
XSLTを学ぶ(9)ステップの文法を追求する-述部(Predicates)と式

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ(9) ステップの文法を追求する-述部(Predicates)と式

第3回[1]からパスの文法を調べてきました。パスの重要な構成要素にステップがあり、ステップ(省略)は軸、ノードテスト、述部(オプションなので必須ではない)から構成されることを調べました。

ステップの最後の構成部品はオプションの述部です。第6回[2]で見ましたが、述部はを[]で囲った形式です。

式とはどんなものでしょうか? まず、XPathの式の生成規則[3]をトップから辿ってみます。

スタートは定義の[14]ですが、式Exprとは、OrExprです。[21]orExprはAndExprを’or’でつなげたものです。そして、[22]AndExprとは、EqualityExprを’and’でつなげたものです。[23]EqualityExprは、RelationalExprを’=’でつなげたものまたは’!=’でつなげたもの。[24]RelationalExprは、AdditiveExprを'<‘ ‘>”<=’ ‘>=’でつなげたもののようです。つまり、このあたりまでは、式はAdditiveExpr(加算式)の論理演算ということになります。

[14] Expr ::= OrExpr
[21] OrExpr ::= AndExpr | OrExpr ‘or’ AndExpr
[22] AndExpr ::= EqualityExpr | AndExpr ‘and’ EqualityExpr
[23] EqualityExpr ::= RelationalExpr
| EqualityExpr ‘=’ RelationalExpr
| EqualityExpr ‘!=’ RelationalExpr
[24] RelationalExpr ::= AdditiveExpr
| RelationalExpr ‘<‘ AdditiveExpr | RelationalExpr ‘>’ AdditiveExpr
| RelationalExpr ‘<=’ AdditiveExpr | RelationalExpr ‘>=’ AdditiveExpr

ということで、さらにAdditiveExprとは何かを見てみます。[25]ではAdditiveExprは、MultiplicativeExprを’+’または’-‘でつなげたものです。

[25] AdditiveExpr ::= MultiplicativeExpr
| AdditiveExpr ‘+’ MultiplicativeExpr
| AdditiveExpr ‘-‘ MultiplicativeExpr

[26]ではMultiplicativeExprとは、UnaryExpr(単項式)、またはMultiplicativeExprにUnaryExprを掛けた(’*’)、またはMultiplicativeExprをUnaryExprで割り算(’div’)、剰余算(’mod’)したものです。
[26] MultiplicativeExpr ::= UnaryExpr
| MultiplicativeExpr MultiplyOperator UnaryExpr
| MultiplicativeExpr ‘div’ UnaryExpr
| MultiplicativeExpr ‘mod’ UnaryExpr
[34] MultiplyOperator ::= ‘*’

UnaryExprは、UnionExprまたはその前にマイナス記号(’-‘)をつけたもの。

[27] UnaryExpr ::= UnionExpr | ‘-‘ UnaryExpr

UnionExprは、ひとつのPathExpr(パス式)、またはそれを’|’で結合したものです。

[18] UnionExpr ::= PathExpr| UnionExpr ‘|’ PathExpr

PathExpr式は、LocationPath(ロケーションパス)、またはFilterExprまたは、FilterExprと相対ロケーションパスを’/’、’//’ で結合したものです。

[19] PathExpr ::= LocationPath
| FilterExpr
| FilterExpr ‘/’ RelativeLocationPath
| FilterExpr ‘//’ RelativeLocationPath

ロケーションパスについては第3回[2]ですでに学びましたが、XMLツリーのノードを選択するものです。ノードの選択結果はノードの集まり(ノード集合)ですが、これに対して、掛け算(’*’)、割り算(’div’)、剰余算(’mod’)、足し算(’+’)、引き算(’-‘)、比較などの演算をするのは少し不思議な気もします。これは後ほど調べてみることにします([5])。

FilterExprの方は、PrimaryExprまたはPrimaryExprに述部(Predicate)を付けたものとなります。ここに出てくる述部はFilterExpr Predicateのように使われますが、ステップの中で出てくる述部の使われ方はAxisSpecifier NodeTest Predicate*です。この2種類の述部の使われ方の違いはなんでしょうか? これも後ほど調べてみましょう([4])。

PrimaryExprは、VariableReference(変数参照)、式を()で囲ったもの、リテラル、数値、FunctionCall(関数呼び出し)のどれかです。ですので、式には数置の四則演算も表現したものも含まれます(よく知っている初歩的な数式も含まれるということで一安心です)。

[20] FilterExpr ::= PrimaryExpr
| FilterExpr Predicate
[15] PrimaryExpr ::= VariableReference
| ‘(‘ Expr ‘)’
| Literal
| Number
| FunctionCall

最も単純なケースでは、一つの数値(Number)だけでも式となります。例えば、次のように下から辿ってみます。
(1) PrimaryExprがNumber:100
(2) FilterExprがPrimaryExpr:100
(3) PathExprがFilterExpr:100
(4) UnionExprがPathExpr:100
(5) UnaryExprがUnionExpr :100
(6) MultiplicativeExprがUnaryExpr:100
(7) AdditiveExprがMultiplicativeExpr:100
(8) RelationalExprがAdditiveExpr :100
(9) EqualityExprがRelationalExpr :100
(10) AndExprがEqualityExpr:100
(11) OrExprがAndExpr:100
(12) ExprがOrExpr:100

ということで、述部に[100]と書くことができます。

まとめますと、述部([]内)にはを書きますが、式としてはロケーションパスを書くこともできますし、また、数値、変数、関数呼び出し、数式を書くこともできる、ということになります。

途中で、いろいろわからない言葉が出てきていますので、次回以降、もう少し詳しく調べてみます。

[1] XSLTを学ぶ (3) パスとは
[2] XSLTを学ぶ (6) ステップの文法を追求するの[8]、[9]式
[3] 3 Expressions
[4] 次回(第10回)のpreceding::foo[1] と(preceding::foo)[1]の比較 の項を参照してください。
[5] ノード集合の論理演算、比較演算については第11回を参照してください。

【広告】★AH Formatter XML関連出版物の紹介

次回:
XSLTを学ぶ (10)式によるノード集合の作成、ノード集合の和集合、フィルター式

前回:
XSLTを学ぶ(8)ステップの文法を追求する-NodeTest

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (8) ステップの文法を追求する-NodeTest

前回は軸について調べましたので、今回はNodeTestを調べてみます。XPath仕様では、NodeTestを次のように規定しています[1]

[7] NodeTest ::= NameTest | NodeType ‘(‘ ‘)’ | ‘processing-instruction’ ‘(‘ Literal ‘)’
[37] NameTest ::= ‘*’ | NCName ‘:’ ‘*’ |QName
[38] NodeType ::= ‘comment’|’text’|’processing-instruction’|’node’

まず主ノードタイプを次のように定義します。ステップの文法では軸の指定に続いてNodeTestを記述します。NodeTestでは軸毎に主ノードタイプに該当するノードを選択することになります。

・attribute軸の主ノードタイプは属性
・namespace軸の主ノードタイプは名前空間
・その他の軸の主ノードタイプは要素

文法上は、attribute::text()のような組み合わせができますが、これは無意味なので何も選択しません。

(1) NameTest

NameTestでは要素や属性の名前を指定して一致するものを選択します。

NameTestでは’*’を使えます。’*’は主ノードタイプが何であれすべてのノードに対して真となります。但し、NameTestの前には、軸指定子(AxisSpecifier)が置かれます。軸指定子が省略されないときは、例えば、child::* は起点ノードの子供であるすべての要素ノードを選択します。attribute::*は起点ノードのすべての属性を選択します。

ステップでは軸指定子を省略できます。するとステップは*または@*の形式となります。ステップにおいて*を指定するとchild::*であり、@*とするとAttribute::*です(第6回[3]の[5]と[13]の規定による)。

二番目のNCNameは、名前空間の接頭辞です。接頭辞はXML名前空間の仕様で規定されています[2]

xmlns:svg=”http://www.w3.org/2000/svg”

という名前空間の宣言があるとしますと、NCNameは’svg’にあたります。svg:*はsvg名前区間にあるすべてのノードを選択し、child::svg:*は文脈ノードの子供でsvg名前空間に属する要素ノードをすべて選択します。

QNameは名前空間接頭辞(オプション)で修飾された名前です。

(2) NodeType ‘(‘ ‘)’

NodeTestは、ノードの種類でノードを選択することもできます。ノードの種類は次の4種類です。

comment()
text()
processing-instruction()
node()

例えば、child::text()は起点ノードの子供のテキストノードを選択します。
comment()はコメントノード、processing-instruction()は処理命令のノードを選択します。
node()は任意の種類のノードを選択します。

ステップで、node()と記述すると、軸を省略したことになり、child::node()を意味します。従って、要素ノードのみを選択します。

[1] 2.3 Node Tests
[2] 3 Declaring Namespaces
[3] XSLTを学ぶ(6)ステップの文法を追求する

【広告】★AH Formatter XML関連出版物の紹介

次回:
XSLTを学ぶ(9) ステップの文法を追求する-述部(Predicates)と式

前回:
XSLTを学ぶ(7)ステップの文法を追求する-軸とは

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (7) ステップの文法を追求する-軸とは

パスは、ステップを’/’オペレータで結合したものであること、そしてステップは、AxisSpecifier NodeTest Predicate*の形式または省略形で記述されることを前回まで[1]に学びました。

ステップの例として、child::para[position()=1]を取り上げてみます。child::が軸指定子(AxisSpecifier)であり、あるノードを起点とするとき、その起点ノードの子供を選択します[2]

その後のparaがNodeTestでノードの名前の指定であり、child::paraは、起点ノードの子供で名前がparaのノードを選択します。NodeTestには’*’を使うこともでき、child::*とすると起点ノードの子供であるノードをすべて選択します。

[position()=1]はオプションの述部(Predicate)です。この場合、述部はノード集合の中での最初のノードを選択します。

軸は起点のノードからXML文書のツリーの方向を指定します。第1回[3]で学びましたが、ノードには7種類があり、また、軸の名前にはancestor、ancestor-or-self、attribute、child、descendant、descendant-or-self、following、following-sibling、namespace、parent、preceding、preceding-sibling、selfの13種類があります。

この中でself軸は起点となるノード自身を含みます。起点ノードが要素ノードのとき、self、ancestor、descendant、following、precedingは一つのXML文書の(属性、名前空間を除外して)すべてのノードを網羅します。

例えば、次のようなXML文書を考えてみます。

<!–?xml version=”1.0″?–>
<doc>
<body>
<p s=”man1″>Hello! How are you?</p>
<p s=”man2″><img src=”pic1″/>I am fine, thank you.<img src=”pic2″/></p>
<p s=”man3″>I am fine, thank you.</p>
</body>
</doc>

このXML文書をノードのツリーで表します。仮に起点が二つ目の要素ノードpであるとします。このときself::はpノードです。そこを起点にしてancestor、descendant、following、precedingは次のような関係になります。

XSLT2

上の図では、selfの子供pの属性ノード(src=”pic1″など)は除外しています。第2回[4]で説明しましたように属性ノードは子供(child)にはなりません。XSLT仕様では、decendentは、「childまたはchildの子供である」とされています。従って、属性や(名前空間ノードも)decendentにはなりません[5]

また、属性や(名前空間ノードも)はprecedenig、followingからも除外されています。

上の図とは異なりますが、もし、属性ノードsrc=”pic1″がselfであった時は、ancestorはその親であるpノードからルートノードまでとなります[6]。しかし、 following-sibling、preceding-siblingは空です。

child、parentについては第2回[4]で説明しました。child軸、parent軸はそれぞれselfノードの子または親です。child軸は複数の子供ノードを含みます。parent軸はあるとしてもひとつの親ノードのみを含みます。

attribute軸、namespace軸はそれぞれselfの属性ノード、名前空間ノードを含みます。

[1] XSLTを学ぶ(3)パスとは
XSLTを学ぶ(6)ステップの文法を追求する
[2] XPathでは起点ノードを文脈ノードといいます。そして、以下の説明の起点ノードのところは文脈ノードになっています。
[3] XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う
[4] XSLTを学ぶ(2)ノードツリーとノードの親子、子孫関係
[5] 2.2 Axes
[6] XPathの仕様の2.2 Axesには、文脈ノードのancestorは、文脈ノードの親(parent)と親の親、以下同じ、から成るとあります。そして、5.3 Attribute Nodesには、要素はそれに付随する属性ノードの親である、と書いてあります。従って、属性ノードのancestorにはその親である要素ノードを選択することになります。

【広告】

次回:
XSLTを学ぶ(8)ステップの文法を追求する-NodeTest

前回:
XSLTを学ぶ(6)ステップの文法を追求する

★AH Formatter XML関連出版物の紹介

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (6) ステップの文法を追求する

第3回([1])と前回([2])でパスには「式の構成部品としてのパス」(ロケーションパス)と「パターンの記述のためのパス」(パターンパス)の2種類あること、そしてロケーションパスは式の一部でありxsl:要素のselect属性で使われること。パターンパスは、match属性で使われることを説明しました。

パスを構成する文法を調べると、ステップがその基本的な単位になっています。パスはステップを’/’で結合して構成します。

そこで、ステップについてもう少し詳しく調べてみます。

1. ロケーションパスのステップは、XPath仕様[3]で決まっています。第3回でステップの文法の入り口として、次の項を紹介しました。

[4] Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep

ステップは軸の指定子(AxisSpecifier)とノードテスト(NodeTest)とオプション(*)の述部(Predicate)、または、省略形(AbbreviatedStep)から構成します。

ステップの省略形は ‘.’(自分自身、self::node()の省略形)、または’..’(親、parent::node()の省略形)です。

[12] AbbreviatedStep ::= ‘.’ | ‘..’

軸の指定子の定義は、次のようになっています。

[5] AxisSpecifier ::= AxisName ‘::’ | AbbreviatedAxisSpecifier
[6] AxisName ::= ‘ancestor’ | ‘ancestor-or-self’ | ‘attribute’ | ‘child’ | ‘descendant’ | ‘descendant-or-self’ | ‘following’ | ‘following-sibling’ | ‘namespace’ | ‘parent’ | ‘preceding’ | ‘preceding-sibling’ | ‘self’

軸の指定子は、軸の名前(AxisName)と’::’または省略形の軸指定子(AbbreviatedAxisSpecifier)で、軸の名前は’ancestor’から’self’まで13種類あります。

[13] AbbreviatedAxisSpecifier ::= ‘@’?

省略形の軸指定子はなにも指定しないか’@’です。なにも指定しないとデフォルトはchild::です。
@はattribute::の省略形です。その他、’//’は/descendant-or-self::node()/の省略形とされています(規則[11]省略)。

NodeTest以下は次のようになっていますが、次回以降もう少し詳しく調べてみます。

[7] NodeTest ::= NameTest | NodeType ‘(‘ ‘)’ | ‘processing-instruction’ ‘(‘ Literal ‘)’
[37] NameTest ::= ‘*’ | NCName ‘:’ ‘*’ | QName  
[38] NodeType ::= ‘comment’ | ‘text’ | ‘processing-instruction’ | ‘node’

NCName、QNameはXML名前空間([4])で規定されています。

[8] Predicate ::= ‘[‘ PredicateExpr ‘]’
[9] PredicateExpr ::= Expr 

述部は式(Expr)を'[‘ ‘]’で囲ったものです。

2. パターンの構成要素であるステップ(ステップパターン)は、XSLT仕様([5])で決まっています。その文法は次の通りです。

[5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
[6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
| (‘child’ | ‘attribute’) ‘::’

NodeTest、Predicate、AbbreviatedAxisSpecifierはXPathのステップを参照しています。XSLT仕様はXPath仕様を利用して作られていることがよく分かります。

[1] XSLTを学ぶ(3)パスとは
[2] XSLTを学ぶ(5)パターンの記述のためのパス
[3] XML Path Language (XPath) Version 1.0
[4] Namespaces in XML 1.0 (Third Edition)
[5] XSL Transformations (XSLT) Version 1.0
[6] 『スタイルシート開発の基礎』

【広告】★AH Formatter XML関連出版物の紹介

次回:
XSLTを学ぶ(7)ステップの文法を追求する-軸とは

前回:
XSLTを学ぶ(5)パターンの記述のためのパス

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (5) パターンの記述のためのパス

前回[1]は、「式の構成部品としてのパス」を調べてみました。これはXPath仕様[2]で規定されているものです。

もう一つは、「パターンの記述のためのパス」があります。こちらはXSLT仕様[3]で規定されています。本書(『スタイルシート開発の基礎』[4])では、パターンについては、3.7.1 パタン(p.33)で触れています。しかし、パスの役割についてはあまり詳しく記述されていませんので、仕様書で少し詳しく調べてみます。

式は主にselectの属性の値として設定します。XSLT V1.0ではselect属性は次の要素に定義されています。

xsl:variable
xsl:param
xsl:apply-templates (ノード集合式のみ)
xsl:value-of (文字列式のみ)
xsl:with-param
xsl:sort (文字列式のみ)
xsl:copy-of
xsl:if(論理式のみ)
xsl:when(論理式のみ)
xsl:for-each(ノード集合式のみ)

パターンは、スタイルシート規則(xsl:template)のmatch属性の値として規定されています。これを含めてmatch属性が使えるのは次の三つの要素です。

xsl:template
xsl:key
xsl:number

XSLTのxsl:templateの説明の項(5 Template Rules)にはパターンについて書いてあります。それを読みますと、select属性の式は、主にソース文書から処理の対象とするノードのリストを作るのに使われるのに対して、パターンはノードに適用するテンプレート規則を識別するのに使うという関係のようです。

パターンの構文は、式の構文のサブセットです。具体的には次のようになっています。

[1] Pattern ::= LocationPathPattern
| Pattern ‘|’ LocationPathPattern

パターンは一つのロケーションパスパターンまたは、それを’/’オペレータでつなげたものです。

[2] LocationPathPattern ::= ‘/’ RelativePathPattern?
| IdKeyPattern ((‘/’ | ‘//’) RelativePathPattern)?
| ‘//’? RelativePathPattern

[3] IdKeyPattern ::= ‘id’ ‘(‘ Literal ‘)’
| ‘key’ ‘(‘ Literal ‘,’ Literal ‘)’

IDkeyPatternは式では出てきませんでしたが、IDまたはkeyとなっています。あとは式としてのロケーションパスの生成規則で出てきたもの(第(3)回[5]を参照)と大よそ対応しているようです。

[4] RelativePathPattern ::= StepPattern
| RelativePathPattern ‘/’ StepPattern
| RelativePathPattern ‘//’ StepPattern
[5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
[6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
| (‘child’ | ‘attribute’) ‘::’

ChildOrAttributeAxisSpecifierは、child軸とattribute軸のみになっています。

[1] XSLTを学ぶ (4) 式の構成部品としてのパスの使い方
[2] XML Path Language (XPath) Version 1.0
[3] XSL Transformations (XSLT) Version 1.0
[4] 『スタイルシート開発の基礎』
[5] XSLTを学ぶ (3) パスとは

【広告】★AH Formatter XML関連出版物の紹介

次回:
XSLTを学ぶ (6) ステップの文法を追求する

前回:
XSLTを学ぶ (4) 式の構成部品としてのパスの使い方

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


XSLTを学ぶ (4) 式の構成部品としてのパスの使い方

前回[1]はパス(ロケーションパス)の構成法を学びました。続いてパスの使い方を調べてみます。

スタイルシートで重要な役割を果たす要素の一つにxsl:apply-templatesがあります。XSLT[2]の5.4 Applying Template Rulesを見ますと、xsl:apply-templatesの定義は次のようになっています。

<xsl:apply-templates
 select = node-set-expression
 mode = qname>
 <!– Content: (xsl:sort | xsl:with-param)* –>
</xsl:apply-templates>

select属性を省略すると、xsl:apply-templatesはカレントノードのすべての子供を処理します。select属性の値に式を記述することで、処理対象とするノードの集合を限定できます。この式はどのように評価されるのでしょうか?

XSLTの5.1 Processing Modelを読むと、ノードにmatchするテンプレート規則の中から、あるテンプレート規則が選択されると、テンプレート規則はそのノードをカレントノードとして起動されるとあります。

本書[3]には次のような例(2.18の一部)が出ています。

<xsl:template match=”body”>
 <fo:page-sequence master-reference=”main”>
  <fo:flow flow-name=”xsl-region-body”>
   <xsl:apply-templates select=”p”/>
  </fo:flow>
 </fo:page-sequence>
</xsl:template>

<xsl:template match=”p”>
 <fo:block>
  <xsl:apply-templates/>
 </fo:block>
</xsl:template>

最初のブロックのテンプレート規則(xsl:template)は、(要素ノード)bodyにmatchしています。従って、最初のブロックではbodyがカレントノードです。

XPath[4]の式は文脈ノードで評価されます。XSLTの4 Expressionsを見ますと、最も外側の式(ある式の一部でない式)は文脈を次のように取得します。

a. 文脈ノードはカレントノードから
b. 文脈ノードの位置は、カレントノードリストにおけるカレントノードの位置から
c. 文脈ノードの大きさは、カレントノードリストの大きさから

こうして、最初のxsl:apply-templatesのselect属性の値である式p(child::pの省略記法)の文脈ノードはbodyになることが分かります。こうしてselect属性によりbodyの子であるpを選択したノード集合を作ることになります。(bodyの子のpではない要素ノードや、bodyの兄弟p要素ノードは対象になりません)。

[1] XSLTを学ぶ (3) パスとは
[2] XSL Transformations (XSLT) Version 1.0
[3] 『スタイルシート開発の基礎』
[4] XML Path Language (XPath) Version 1.0

【広告】★AH Formatter XML関連出版物の紹介

次回:
XSLTを学ぶ(5)パターンの記述のためのパス

前回:
XSLTを学ぶ (3) パスとは

初回:
XSLTを学ぶ(1)XMLのツリーモデルとXPath/XSLTのツリーモデルではルートの意味が違う


Pages: 1 2 Next