2

特定の条件下でカウンターをインクリメントする際に問題があります。

入力:

<Users>
  <User>
    <id>1</id>
    <username>jack</username>
  </User>
  <User>
    <id>2</id>
    <username>bob</username>
  </User>
  <User>
    <id>3</id>
    <username>bob</username>
  </User>
  <User>
    <id>4</id>
    <username>jack</username>
  </User>
</Users>

必要な出力:

<Users>
  <User>
    <id>1</id>
    <username>jack01</username>
  </User>
  <User>
    <id>2</id>
    <username>bob01</username>
  </User>
  <User>
    <id>3</id>
    <username>bob02</username>
  </User>
  <User>
    <id>4</id>
    <username>jack02</username>
  </User>
</Users>

これを実現するには、次のアルゴリズムを使用できます。

  • 入力をユーザー名でソート
  • ユーザーごとに
    • 以前のユーザー名が現在のユーザー名と等しい場合
      • インクリメントカウンターと
      • ユーザー名を「$username$counter」に設定します
    • それ以外は
      • カウンターを1に設定
  • (再度 ID でソート - 実際には必要ありません)

だから私はこれをXSLTに変換しようとしました:

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

  <xsl:template match="Users">
    <Users>
    <xsl:apply-templates select="create_user">
      <xsl:sort select="User/username"/>
    </xsl:apply-templates>
    </Users>
  </xsl:template>

  <xsl:template match="create_user">
    <id><xsl:value-of select="id"/></id>
    <xsl:choose>
      <xsl:when test="username=(preceding-sibling::User[1]//username)">
        <xsl:variable name="count">
          <xsl:number format="01"/>
        </xsl:variable>
        <username><xsl:value-of select="concat(username, $count)"/></username>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="count">
          <xsl:number value="1" format="01"/>
        </xsl:variable>
        <username><xsl:value-of select="concat(username, $count)"/></username>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>    

ただし、これを実行すると、次のエラーが発生します。

  • ユーザー名がソートされない
  • カウンターが増えない
    • 代わりに、条件が一致する場合、counter が現在のノード位置になります。
    • この例では、id = 3 のノードのユーザー名は bob03 になります。
  • タグがありません

何かご意見は?

4

2 に答える 2

5

この変換:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="username/text()">
  <xsl:value-of select="."/>
  <xsl:value-of select=
  "format-number(count(../../preceding-sibling::*[username=current()])+1,
                '00')
  "/>
 </xsl:template>
</xsl:stylesheet>

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

<Users>
    <User>
        <id>1</id>
        <username>jack</username>
    </User>
    <User>
        <id>2</id>
        <username>bob</username>
    </User>
    <User>
        <id>3</id>
        <username>bob</username>
    </User>
    <User>
        <id>4</id>
        <username>jack</username>
    </User>
</Users>

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

<Users>
   <User>
      <id>1</id>
      <username>jack01</username>
   </User>
   <User>
      <id>2</id>
      <username>bob01</username>
   </User>
   <User>
      <id>3</id>
      <username>bob02</username>
   </User>
   <User>
      <id>4</id>
      <username>jack02</username>
   </User>
</Users>
于 2012-12-05T04:33:57.170 に答える
0

「カウンターをインクリメントする」ことは、関数型プログラミング言語で行うことではありません。出力を計算するためのプロセスや手順を記述するのではなく、必要な出力を入力の関数として記述する必要があります (Dimitre が行ったように)。

于 2012-12-05T08:44:23.077 に答える