5

ノード セットの正しいコンテキストを判断するのに問題があります。次のようなテンプレート マッチがあります (XSL 2.0 を使用):

<xsl:template match="//chapter/body/*[matches(name(), '^toc')][crossref][not(crossref/@idref='cip' or crossref/@idref='copy')]">
  <xsl:variable name="curr_id" select="crossref/@idref"/>
  <xsl:element name="location">
    <xsl:attribute name="id"><xsl:value-of select="$curr_id"/></xsl:attribute>
    <xsl:attribute name="order"><xsl:value-of select="position()"/></xsl:attribute>
    <xsl:element name="label">
        <text><xsl:value-of select="."/></text>
    </xsl:element>
  </xsl:element>
</xsl:template>

XML は次のようになります。

<chapter id="toc">
  <body>
    <title>Contents</title>
    <tocfm><crossref idref="cip">Catalog</crossref></tocfm>
    <tocfm><crossref idref="copy">Copyright</crossref></tocfm>
    <tocfm><crossref idref="ded">Dedication</crossref></tocfm>
    <toc><crossref idref="prologue">Prologue</crossref></toc>
    <toc><crossref idref="pt1">Book One</crossref></toc>
    <toc><crossref idref="pt2">Book Two</crossref></toc>
    <toc><crossref idref="pt3">Book Three</crossref></toc>
  </body>
</chapter>

私の期待は、述語が次を含むノードセットを生成することです。

<tocfm><crossref idref="ded">Dedication</crossref></tocfm>
<toc><crossref idref="prologue">Prologue</crossref></toc>
<toc><crossref idref="pt1">Book One</crossref></toc>
<toc><crossref idref="pt2">Book Two</crossref></toc>
<toc><crossref idref="pt3">Book Three</crossref></toc>

つまり、idref が cip でも copy でもない crossref を含むすべての toc のような要素です。テンプレートは出力に関してこれを行いますが、位置関数はそのノード セットで機能していないようです。代わりに、献身の「3」の位置を生成します。ただし、[1] の述語をたどって見つかったノードの値を出力すると、その値として Dedication が取得されます。だから、私はどのポジションが働いているのか困惑しています。誰でも私を啓発できますか?

4

2 に答える 2

9

コンテキスト シーケンスがどのように定義されるかについてのよくある誤解に基づいているため、期待は間違っています。コンテキスト シーケンスは、テンプレートマッチ パターンによって決定されるのではなく、テンプレートの外部にあるものによって決定されます。

ある時点で xsl:apply-templates が select 式で呼び出されます。この式が評価されて、項目シーケンスが生成されます。現在のコンテキスト シーケンスがスタックにプッシュされます。この項目シーケンスがコンテキスト シーケンスになります。コンテキスト シーケンスは、シーケンス順に繰り返されます。アイテムが訪問されるたびに、このアイテムはコンテキスト アイテムになり、position() 関数はコンテキスト シーケンス内のコンテキスト アイテムの位置を反映します。この時点で、一致式と優先度に基づいて適切なテンプレートが見つかります。一致式はシーケンスを返しません。これらは、コンテキスト アイテムに対する単純なブール テストです。コンテキスト アイテムがテンプレート ルールに一致するか、一致しないかのいずれかです。一致し、優先度が最も高い場合、テンプレート シーケンス コンストラクターが入力されます。この時点でのコンテキスト シーケンスは、context item と position() はすべて、一致条件ではなく、クライアントの xsl:apply-templates によって定義されています。シーケンス コンストラクターを終了した後、制御はクライアントの xsl:apply-templates に戻ります。position() 番号をインクリメントし、コンテキスト アイテムを更新して、適切なテンプレートを再度見つけます。これは、前のアイテムと同じテンプレートでも、別のテンプレートでもかまいません。

このスタイルシートは、テンプレートの一致パターンではなく、クライアントの命令(apply-templates、for-each など) がコンテキスト シーケンスと position() を決定することを示しています。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
 <t>
   <note message ="apply-templates on EVEN items">
    <xsl:apply-templates select="*/item[ (@id mod 2) = 0]"/>
   </note>  
   <note message ="apply-templates on ODD items">
    <xsl:apply-templates select="*/item[ (@id mod 2) = 1]">
     <xsl:sort select="position()" data-type="number" order="descending"/>
    </xsl:apply-templates>
   </note>  
 </t>
</xsl:template>
      
<xsl:template match="item[@colour='blue']">
 <note message='Brought to you by the Blue template!' positon="{position()}"> 
  <xsl:copy-of select='self::*'/>
  </note>  
</xsl:template>
      
<xsl:template match="item[@colour='red']">
 <note message='Brought to you by the Red template!' positon="{position()}"> 
  <xsl:copy-of select='self::*'/>
  </note>  
</xsl:template>
      
</xsl:stylesheet>
    

... このドキュメントに適用 ...

<t>
 <item id="1" colour="blue" /> 
 <item id="2" colour="blue" /> 
 <item id="3" colour="blue" /> 
 <item id="4" colour="red" /> 
 <item id="5" colour="red" /> 
 <item id="6" colour="red" /> 
</t>

... この出力が得られます ...

<t>
  <note message="apply-templates on EVEN items">
    <note message="Brought to you by the Blue template!" positon="1">
      <item id="2" colour="blue" />
    </note>
    <note message="Brought to you by the Red template!" positon="2">
      <item id="4" colour="red" />
    </note>
    <note message="Brought to you by the Red template!" positon="3">
      <item id="6" colour="red" />
    </note>
  </note>
  <note message="apply-templates on ODD items">
    <note message="Brought to you by the Red template!" positon="1">
      <item id="5" colour="red" />
    </note>
    <note message="Brought to you by the Blue template!" positon="2">
      <item id="3" colour="blue" />
    </note>
    <note message="Brought to you by the Blue template!" positon="3">
      <item id="1" colour="blue" />
    </note>
  </note>
</t>
于 2012-07-11T01:37:55.480 に答える
3

position()コンテキスト位置を参照します。XSLT 2.0 仕様から:

コンテキスト位置は、現在処理されている一連のアイテム内のコンテキスト アイテムの位置です。コンテキスト項目が変更されるたびに変更されます。xsl:apply-templatesorなどの命令xsl:for-eachを使用してアイテムのシーケンスを処理する場合、シーケンスの最初のアイテムはコンテキスト位置 1 で処理され、2 番目のアイテムはコンテキスト位置 2 で処理され、以下同様に処理されます。] コンテキスト位置が返されます。 XPath 式によってposition()

理解することが重要なのはxsl:template、コンテキスト アイテムを変更しないということです。xsl:apply-templatesまたはによって変更されている可能性がありxsl:for-eachます。たとえば、次のコードを検討してください。

<xsl:apply-templates select="tocfm|toc"/>

ノードの処理にDedication取り掛かると、そのノードはコンテキスト項目になり、コンテキスト位置が入力シーケンス内のそのノードの位置になります (すべての要素tocfmtoc要素の和集合)。これまたは同様の何かがおそらくあなたの3がどこから来ているかです.

apply-templates仕様の一部が言うように:

xsl:apply-templates命令はノードのシーケンス (通常はソース ツリーのノード) を入力として受け取ります […] 命令に 1 つ以上の子xsl:sortがある場合、入力シーケンスは 13 ソートで説明されているようにソートされます。この並べ替えの結果は、以下では並べ替えられたシーケンスと呼ばれます。要素がない場合xsl:sort、ソートされたシーケンスは入力シーケンスと同じです。[…] 入力シーケンスの各ノードは、そのノードに一致するパターンを持つテンプレート ルールを見つけることによって処理されます。[…] ソートされたシーケンスの N 番目のノードに一致するルールは、そのノードをコンテキスト アイテムとして、N をコンテキスト位置として、ソートされたシーケンスの長さをコンテキスト サイズとして評価されます。

このFAQ エントリが役に立つかもしれません (ただし、XSLT 1.0 のposition()現在のノード リストの概念に関する問題を説明していますが、これは XSLT 2.0 では使用されていません)。

于 2012-07-11T01:38:10.233 に答える