1. ホーム
  2. xslt

XSLT ドキュメント内のテンプレートはどのような順序で実行され、ソース XML とバッファリングされた出力のどちらで一致するのでしょうか?

2023-09-22 23:57:15

質問

XSLTについて、私がいつも不思議に思っていることがあります。

  1. テンプレートはどのような順序で実行されるのか、そして
  2. 実行されるとき、(a) オリジナルのソース XML、または (b) その時点までの XSLT の現在の出力にマッチしますか。

例を挙げます。

<person>
  <firstName>Deane</firstName>
  <lastName>Barker</lastName>
</person>

XSLTの断片を示します。

<!-- Template #1 -->
<xsl:template match="/">
  <xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
</xsl:template>

<!-- Template #2 -->
<xsl:template match="/person/firstName">
  First Name: <xsl:value-of select="firstName"/>
</xsl:template>

これに関して2つの質問があります。

  1. 私は、テンプレート #1 が最初に実行されると仮定しています。 なぜそう仮定するのか分かりませんが、単にドキュメントで最初に表示されるからでしょうか?
  2. テンプレート#2は実行されるのでしょうか? それはソース XML のノードに一致しますが、このテンプレートに到達するまでに (それが 2 番目に実行されると仮定して)、 "firstName" ノードは出力ツリーに存在しないでしょう。

つまり、quot; later" テンプレートは、quot; earlier" テンプレートで発生したことに従うのでしょうか、それとも、quot; prior" で変換されたことに気づかず、ソース ドキュメント上で動作するのでしょうか。 (これらの言葉はすべて引用符で囲まれています。そもそもテンプレートの順序がどのように決定されるのか、私にはほとんど分からないのに、時間ベースの問題を議論するのは難しいと思うからです......)

上記の例では、ルート ノード ("/") にマッチするテンプレートがあり、それが実行されたとき、出力からすべてのノードを本質的に削除しています。 この場合、最初のテンプレートが完了した後にマッチするものがないため、他のすべてのテンプレートが実行されるのを先取りしてしまうのではないでしょうか?

この点で、私は、操作したノードが出力に表示されないため、後のテンプレートが実行されないことを懸念してきましたが、逆はどうでしょうか。 先のテンプレートが、後のテンプレートが何かを行うことができるノードを作成することができますか?

上記と同じXMLで、このXSLを考えてみましょう。

<!-- Template #1 -->
<xsl:template match="/">
  <fullName>
    <xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
  </fullName>
</xsl:template>

<!-- Template #2 -->
<xsl:template match="//fullName">
  Full Name: <xsl:value-of select="."/>
</xsl:template>

テンプレート #1 は "fullName" という名前の新しいノードを作成します。 テンプレート#2はその同じノードにマッチします。 テンプレート#2にたどり着くまでに、"fullName"ノードが出力に存在するので、テンプレート#2は実行されますか?

私は、XSLT の「禅」について深く無知であることを自覚しています。 今日まで、私のスタイルシートは、ルート ノードに一致するテンプレートで構成されており、そこから先は完全に手続き的です。 これにはうんざりしています。 私はむしろ実際にXSLTを正しく理解したいので、私の質問をしました。

どのように解決するのですか?

私はあなたの質問が好きです。あなたは、まだ理解していないことについて非常に明確です。あなたはただ、物事を結びつける何かが必要なのです。私のお勧めは、次の本を読むことです。 XSLT の仕組み」を読むことです。 を読んでみることをお勧めします。この章は、まさにあなたが質問していることに取り組むために書いたものです。

あまり堅苦しく考えずに、あなたの質問にそれぞれ答えてみましょう。

  1. テンプレートはどのような順序で実行されるのですか、そして
  2. 実行されるとき、(a) オリジナルのソース XML にマッチするか、(b) そのソース XML への XSLT の現在の出力にマッチするか。 その時点までの XSLT の現在の出力にマッチしますか? に一致するか。

XSLT 処理の任意の時点で、ある意味で 2 つのコンテキストがあり、それを (a) と (b) と見なします。 ソース ツリー にいるところ、そして 結果ツリー . ソースツリーのどこにいるかは カレントノード . XPath を使用して処理するノードのセットを任意に選択するため、カレント ノードはソース ツリーのあちこちに移動し、変化することがあります。しかし、概念的には、結果ツリーを同じように飛び回ることはありません。XSLT プロセッサは、まず結果ツリーのルートノードを作成し、次に子ノードを追加して、文書順に結果を構築していきます(深さ優先)。[あなたの投稿は、私が XSLT の実験のためのソフトウェア視覚化を再びピックアップする動機付けになりました...。]

スタイルシート内のテンプレート規則の順序は決して重要ではありません。スタイルシートを見ただけでは、テンプレート ルールがどのような順序でインスタンス化されるか、ルールが何回インスタンス化されるか、あるいは全くインスタンス化されないかどうかを知ることはできません。( match="/" は例外です。これがトリガーされることは常に知ることができます)。

テンプレート#1が最初に実行されると仮定しています。 が最初に実行されると仮定しています。なぜそう思うのかわかりません。 ドキュメントで最初に表示されるからでしょうか? ドキュメントで最初に表示されるからでしょうか?

いいえ。ドキュメント内で最後に置いたとしても、最初に呼ばれるでしょう。テンプレートルールの順番は決して重要ではありません(同じノードに同じ優先順位を持つ複数のテンプレートルールがマッチした場合のエラー条件を除いて。) が最初に呼び出されるからです。 が常に が最初に呼ばれるのは、XSLT プロセッサを実行するときはいつでも、仮想的に <xsl:apply-templates select="/"/> . この 1 つの仮想呼び出しが結果ツリー全体を構築します。その外側では何も起こりません。テンプレートルールを定義することによって、その命令の振る舞いをカスタマイズすることができます。

テンプレート#2は実行されるのでしょうか?これはソースXMLのノードにマッチしますが に到達するまでに、この テンプレートに到達するまでに(2番目に実行されると仮定して)。 firstName" ノードは出力ツリーに存在しません。 は出力ツリーにはありません。

テンプレート#2(あるいは他のテンプレートルール)は、あなたが <xsl:apply-templates/> のどこかで match="/" のルールのどこかで呼び出す必要があります。もし、何もないのであれば、以下のようなテンプレートルールはありません。 match="/" 以外のテンプレートルールはトリガーされません。このように考えてください。テンプレート・ルールが起動するためには、単に入力のノードにマッチすればよいというわけではありません。テンプレート規則を発動させるには、入力のノードにマッチするだけではいけません。 処理 を選択したノードにマッチする必要があります (それには <xsl:apply-templates/> ). 逆に、あなたが処理を選択する限り、何度でもノードにマッチし続けます。

Would [the match="/" テンプレート] は他のすべてのテンプレート が実行されることはないでしょう。 その最初のテンプレートが完了した後、マッチするものがない が完了した後にマッチするものがないからです。

このルールは、他のルールに先立って、どこにも <xsl:apply-templates/> を含まないことで、他のルールを先取りしています。まだたくさんのノードがあり、その中には ができた を処理できるノードが、ソースツリーにはまだたくさんあります。それらはすべて常にそこにあり、ピッキングのために熟しています; 望むだけ何度でも各ノードを処理してください。しかし、テンプレートルールを使ってそれらを処理する唯一の方法は <xsl:apply-templates/> .

ここまでで、私が心配していたのは 後のテンプレートが実行されないことを というのも、操作したノードが出力に現れないからです。 が出力に現れないため、後のテンプレートが実行されないことを懸念してきましたが その逆はどうでしょうか?逆に はノードを作成することができますか? テンプレートはノードを作成することができますか? ノードを作成できますか?

それは、"earlier" テンプレートが処理される新しいノードを作成するのではなく、"earlier" テンプレートがその同じ命令を使ってソースツリーからさらにノードを処理するということです ( <xsl:apply-templates ). これは、同じ "関数" を、毎回異なるパラメータで再帰的に呼び出していると考えることができます(コンテキストによって決定される処理するノードと select 属性によって決定される処理するノード) を指定して再帰的に呼び出すと考えることができます。

最終的に得られるのは、同じ"関数"への再帰的な呼び出しのツリー構造のスタックです( <xsl:apply-templates> ). そしてこのツリー構造は 同型である であることがわかります。誰もがこのことに気づいたり、このように考えたりしたわけではありません。それは、効果的な可視化ツールがないからです...まだね。

テンプレート#1 では、次のような新しいノードが作成されます。 という新しいノードを作成します。テンプレート #2 はその同じノードにマッチします。 という新しいノードを作成します。テンプレート#2は は実行されるでしょうか。 は実行されますか? テンプレート#2が実行されるでしょうか?

いいえ。処理の連鎖を行うには、明示的にそのように設定するしかありません。変数を作成し、例えば $tempTree を含む変数を作成し、そこに新しい <fullName> 要素を含む それ というように <xsl:apply-templates select="$tempTree"> . XSLT 1.0でこれを行うには、変数参照を拡張関数でラップする必要があります(例, exsl:node-set() ) が必要ですが、XSLT 2.0ではそのまま動作します。

元のソースツリーからノードを処理する場合でも、自分で構築した一時的なツリーで処理する場合でも、いずれにせよ、処理したいノードを明示的に指定する必要があります。

まだ取り上げていないのは、XSLT がどのようにすべての暗黙の振る舞いを取得するかということです。また 組み込みのテンプレート規則 . 私はいつも、ルート・ノードに対する明示的なルールさえ含まないスタイルシートを書いています ( match="/" ). その代わりに、ルートノードに対する組み込みのルール(子ノードにテンプレートを適用する)に頼っています。このように、入力の大部分を無視して XSLT プロセッサに自動的に走査させ、興味のあるノードに出会ったときだけ特別な処理をさせることができるのです。あるいは、すべてを再帰的にコピーするルール(同一性変換と呼ばれる)を1つだけ書いて、必要な部分だけ上書きし、入力に漸進的な変更を加えることもできる。XSLT の仕組み」を読んだら、次の課題として「identity transform」を調べてください。

私は、自分が深く無知であることを自覚しています。 XSLT の Zen" について深く無知であることを理解しています。今日まで、私の スタイルシートは テンプレートで構成されており、ルート ノードにマッチします。 そこから先は完全に手続き的です。 これにはうんざりしているんだ。私は むしろ実際にXSLTを理解したい を正しく理解したいので、私の質問をしました。

私はあなたに拍手を送ります。さて、次は「赤いピル」を飲む番です。 XSLT の仕組み」を読んでください。