2

私はXSLTにかなり慣れておらず、このトピックに関するいくつかの投稿をスキャンしましたが、この作業を行うために必要な最終的なピースを取得できないようです。私が持っているノードデータに表示される既知のデータ文字列からエントリを削除しようとしています。私は、単一ノードの値に対しては機能するが、複数の値に対しては機能しないソリューションをまとめました。

これが私のxmlです

<root>
<item>2</item>
<item>9</item>
<item>5</item>
</root>

これが1つのノード値に対して機能する私のコードです:

<xsl:template match="item">
<xsl:copy>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="replaceChars">
<xsl:param name="original"/>
<xsl:choose>
<xsl:when test="contains($original, current())">
<xsl:value-of select="substring-before($original, current())"/>
<xsl:variable name="after" select="substring-after($original, current())"/>
<xsl:variable name="char" select="substring-before($after, current())"/>
<xsl:value-of select="concat($char, $after)"/>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="substring-after($after, current())"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$original"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

私の最新のテストでは、これを使用しようとしています。

<xsl:template match="item">
<xsl:copy>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="replaceChars">
<xsl:param name="original"/>
<xsl:choose>
<xsl:when test="contains($original, current())">
<xsl:variable name="before" select="substring-before($original, current())"/>
<xsl:variable name="after" select="substring-after($original, current())"/>
<xsl:variable name="char" select="substring-before($after, current())"/>
<xsl:variable name="new" select="concat($before, $after)"/>
<xsl:call-template name="replaceChars">
<xsl:with-param name="original" select="$new"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$original"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

応答で値を数回繰り返して取得し続けます。出力を次のようにしたいと思います。

1 3 4 6 7 8 10

私の例は変更された検索シナリオに基づいていることがわかるので、私はこれを広範囲に検索しました。どんな助けでもいただければ幸いです。

4

2 に答える 2

0

この変換:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output method="text"/>

 <my:sent/>
 <xsl:variable name="vSent" select="document('')/*/my:sent"/>

 <xsl:param name="pGiven" select="'1 2 3 4 5 6 7 8 9 10'"/>

 <xsl:template match="/*">
  <xsl:apply-templates select="item[1]"/>
 </xsl:template>

 <xsl:template match="item">
  <xsl:param name="pText" select="$pGiven"/>

  <xsl:apply-templates select=
   "following-sibling::item[1]|$vSent[not(current()/following-sibling::item)]">
    <xsl:with-param name="pText" select=
    "concat(substring-before(concat($pText, .), .),
            substring-after($pText,.)
            )
    "/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="my:sent">
  <xsl:param name="pText"/>
  <xsl:value-of select="$pText"/>
 </xsl:template>
</xsl:stylesheet>

提供された XML ドキュメントに適用した場合:

<root>
    <item>2</item>
    <item>9</item>
    <item>5</item>
</root>

必要な正しい結果が生成されます。

1  3 4  6 7 8  10

注意してください:

  1. 変換全体にXSLT 条件命令はありxsl:chooseません。いいえ、いいえxsl:when、いいえ、xsl:otherwiseいいえxsl:if

  2. 名前付きテンプレートはなく、明示的な再帰もありません(ただし、xsl:apply-templates暗黙的に再帰します)。

  3. Sentinelプログラミングは、コードを大幅に簡素化し、より効率的にするために、2 つの異なる方法で使用されます。

于 2012-09-15T03:20:18.150 に答える
0

あなたは近くにいます。

文字列 "1 3 4 6 7 8 10" を 1 回生成する場合、表示するコードを要素ごとに 1 回評価するのではitemなく、要素ごとに 1 回評価する必要がありrootます。

再帰テンプレートで兄弟要素のセットのreplaceCharsそれぞれの値をノックアウトしたい場合、現在の構造ではそれができません。なんで?の値をノックアウトし、 の値を変更するために何もせずに再帰的に呼び出すためです。itemitemcurrent()current()

別のアプローチの 1 つは、「数字 1 (入力に現れない限り)、数字 2 (入力に現れない限り)、それに続く文字列を作成したい」と言って、次のように書くことです。 (nb テストされていません):

<xsl:template match="root">
  <survivors>
    <xsl:if test="not(./item = '1')">1 </xsl:if> 
    <xsl:if test="not(./item = '2')">2 </xsl:if> 
    <xsl:if test="not(./item = '3')">3 </xsl:if> 
    <xsl:if test="not(./item = '4')">4 </xsl:if> 
    <xsl:if test="not(./item = '5')">5 </xsl:if> 
    <xsl:if test="not(./item = '6')">6 </xsl:if> 
    <xsl:if test="not(./item = '7')">7 </xsl:if> 
    <xsl:if test="not(./item = '8')">8 </xsl:if> 
    <xsl:if test="not(./item = '9')">9 </xsl:if> 
  </survivors>
</xsl:template>

または、部分文字列の一致を本当に実行したい場合は、再帰がreplaceChars実際にitem要素を反復することを確認する必要があります。

<xsl:template match="root">
  <survivors>
    <xsl:call-template name="replaceChars2">
      <xsl:with-param name="s" select="'1 2 3 4 5 6 7 8 9'"/>
      <xsl:with-param name="item" select="./item[1]"/>
    </xsl:call-template>
  </survivors>
</xsl:template>

<xsl:template name="replaceChars2">
  <xsl:param name="s"/>
  <xsl:param name="item"/>
  <xsl:variable name="s2" select="string($item)"/>
  <xsl:choose>
    <xsl:when test="$item">
      <xsl:call-template name="replaceChars2">
        <xsl:with-param name="s" 
          select="concat(
            substring-before($s,$s2,
            ' ',
            substring-after($s,$s2,
            )"/>
        <xsl:with-param name="item" 
          select="./following-sibling::item[1]"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$s"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

OP で示されているコードと同様に、これは、item要素が削除されるべきではない文字列のどの部分にも誤って一致しないことを前提としています (たとえば、元の文字列は、値が「1」の場合、「11」のような値は決してありません)。 )。

兄弟を繰り返し処理し、パラメータを渡して前の兄弟で何が起こったかを追跡するパターンは、このような変換では、学ぶべき重要なイディオムです。

于 2012-09-14T18:23:40.813 に答える