27

新しいノードを作成するときに ID として使用できるように、ノードの数を数えたい XML ファイルを処理しています。

現在、「カウンター」というグローバル変数があります。テンプレート内でアクセスできますが、テンプレート内で操作する方法が見つかりません。

これは、私の XSLT ファイルの要約版です。

<xsl:variable name="counter" select="1" as="xs:integer"/>

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"></xsl:call-template>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">

   <!-- Increment 'counter' here -->

   <span class="title" id="title-{$counter}"><xsl:value-of select="title"/></span>
</xsl:template>

ここから行く方法はありますか?

4

8 に答える 8

44

他の人は、変数がどのように不変であるかを既に説明しています。つまり、XSLT には割り当てステートメントがありません (一般的な純粋な関数型プログラミング言語と同様)。

これまでに提案されたソリューションに代わるものがあります。パラメータの受け渡しを回避します (これは XSLT では冗長で見苦しくなりますが、私も認めます)。

<section>XPath では、現在の要素の前にある要素の数を単純に数えることができます。

<xsl:template name="section">
  <span class="title" id="title-{1 + count(preceding-sibling::section)}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

(注: 空白のみのテキスト ノードはスタイルシートから自動的に取り除かれるため、空白コードの書式設定は結果に表示されません。したがって、同じ行に命令を入れる必要はありません。)

( を使用する場合とは対照的に) このアプローチの大きな利点の 1 つposition()は、現在のノード リストではなく、現在のノードのみに依存することです。なんらかの方法で処理を変更した場合 (たとえば、<xsl:for-each>セクションだけでなく他の要素も処理した場合)、 の値は必ずしもドキュメント内の要素position()の位置に対応しなくなります。<section>一方、count()上記のように使用すると、常に各<section>要素の位置に対応します。このアプローチは、コードの他の部分との結合を減らします。これは一般的に非常に良いことです。

count() に代わる方法は、<xsl:number>命令を使用することです。デフォルトの動作では、同じレベルのすべての同様の名前の要素に番号が付けられます。これはたまたまあなたが望むものです:

<xsl:template name="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

これは、冗長性 (属性値テンプレートの中括弧を引き続き使用する場合は、追加の変数宣言が必要) とのトレードオフですが、XPath 式が大幅に簡素化されるため、わずかです。

まだ改善の余地があります。現在のノード リストへの依存関係を削除しましたが、現在のノードにはまだ依存しています。それ自体は悪いことではありませんが、テンプレートを見て現在のノードが何であるかがすぐにはわかりません。私たちが知っているのは、テンプレートの名前が " section" であることだけです。何が処理されているかを確実に知るには、コードの別の場所を調べる必要があります。しかし、そうである必要はありません。

<xsl:for-each>and を一緒に使用することに導かれたと感じた場合<xsl:call-template>(例のように)、一歩下がって<xsl:apply-templates>代わりに使用方法を考えてください。

<xsl:template match="/doc">
  <xsl:apply-templates select="section"/>
</xsl:template>

<xsl:template match="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

このアプローチは冗長ではない (と の両方を<xsl:apply-templates/>置き換える) だけでなく、現在のノードが何であるかがすぐに明らかになります。属性を見るだけで、要素を処理していること、および要素を数えていることがすぐにわかります。<xsl:for-each><xsl:call-template/>match<section><section>

テンプレート ルール (つまり、属性<xsl:template>を持つ要素)がどのように機能するかについての簡潔な説明については、 「XSLT の仕組み」を参照してください。match

于 2009-05-13T08:59:37.300 に答える
9

XSLT 変数は変更できません。テンプレートからテンプレートに値を渡す必要があります。

XSLT 2.0 を使用している場合は、パラメーターを指定し、トンネリングを使用して変数を適切なテンプレートに伝達できます。

テンプレートは次のようになります。

<xsl:template match="a">
<xsl:param name="count" select="0">
  <xsl:apply-templates>
     <xsl:with-param select="$count+1"/>
  </xsl:apply-templates>
</xsl:template>

ID を作成する場合は、generate-id() の使用も参照してください。

于 2009-05-07T06:25:25.800 に答える
6

XSLT の変数は不変であるため、そのことを念頭に置いて問題を解決する必要があります。position()次のいずれかを直接使用できます。

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"/>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>

または、よりテンプレート指向の方法で:

<xsl:template match="/"> 
   <xsl:apply-templates select="section"/>
</xsl:template>

<xsl:template match="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>
于 2009-05-07T10:42:44.540 に答える
2

XSLT プロセッサによっては、スクリプト関数を XLST に導入できる場合があります。たとえば、Microsoft XML ライブラリは JavaScript の組み込みをサポートしています。例については、http://msdn.microsoft.com/en-us/library/aa970889( VS.85 ).aspx を参照してください。パブリック クライアント ブラウザーで XSLT を展開/実行することを計画している場合、この戦術は明らかに機能しません。特定の XSLT プロセッサによって実行される必要があります。

于 2009-05-07T06:30:09.983 に答える
2

変数はローカル スコープであり、xslt では読み取り専用です。

于 2009-05-07T06:20:30.037 に答える
1

position() 関数を使用して、必要なことを行うことができます。このようになります。

<xsl:template match="/">
  <xsl:for-each select="section">
    <xsl:call-template name="section">
      <xsl:with-param name="counter" select="{position()}"/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="section">
  <xsl:param name="counter"/>
  <span class="title" id="title-{$counter}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>
于 2009-05-07T06:37:29.467 に答える
0

<xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> 増分値としておよび$RowNumを使用します。

例えば:<xsl:template name="ME-homeTiles" match="Row[@Style='ME-homeTiles']" mode="itemstyle"> <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> ...<a href="{$SafeLinkUrl}" class="tile{$RowNum}"><img ....></a>

これにより、値がtile1、tile2、tile3などのリンクのクラスが作成されます。

于 2013-02-21T23:52:02.013 に答える
0

これを自分で試したことはありませんが、パラメーターをテンプレートに渡すことができます。最初のテンプレートでは、for-each ステートメント内でパラメーターを count() (または current() かな?) に設定し、その値を「セクション」テンプレートに渡します。

テンプレートへのパラメーターの受け渡しについて詳しくは、こちらをご覧ください

于 2009-05-07T06:29:40.610 に答える