2

レコードを含むXMLがあり、一部のレコードは相互に関連付けられているため、出力でそれらをグループ化する必要があります。

XML:

<Records>
   <Record id="1" group="10" />
   <Record id="2" group="20" />
   <Record id="3" group="20" />
   <Record id="4" group="20" />
</Records>

現在、表示しています

<span>1</span><span>2</span><span>3</span><span>4</span>

表示したいのは(同じグループのレコードに基づく)

<span>1</span><span>2-4</span>

preceding-sibling::Record/@groupsの反復間でグループ化が変更されたかどうかを確認するためにを使用して調べましたが、必要なグループ化をRecord実現する方法を見つけるのに苦労してい2-4ます。

これが私がこれまでに行ったことであり、私がやろうとしていることを説明するためにいくつかのコメントが点在しています。

<xsl:for-each select="Records/Record">
   <xsl:if test="@group != preceding-sibling::Record/@group">
      <!-- obviously here we need 2-4...somehow? -->
      <span><xsl:value-of="@id" /></span>
   </xsl:if>
</xsl:for-each>
4

2 に答える 2

3

この変換

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

 <xsl:key name="kFollowing" match="Record"
  use="generate-id(preceding-sibling::*
                         [not(@group = current()/@group)
                          ][1])"/>

 <xsl:template match="/*">
       <xsl:apply-templates mode="makeGroup" select=
       "Record[not(@group = preceding-sibling::*[1]/@group)]"/>
 </xsl:template>

 <xsl:template match="Record" mode="makeGroup">
  <xsl:variable name="vGroup"
    select="key('kFollowing', generate-id(preceding-sibling::*[1]))"/>
  <span>
   <xsl:value-of select="$vGroup[1]/@id"/>
   <xsl:if test="$vGroup[2]">
    <xsl:value-of select="concat('-', $vGroup[last()]/@id)"/>
   </xsl:if>
  </span>
 </xsl:template>
</xsl:stylesheet>

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

<Records>
    <Record id="1" group="10" />
    <Record id="2" group="20" />
    <Record id="3" group="20" />
    <Record id="4" group="20" />
</Records>

必要な正しい結果を生成します

<span>1</span><span>2-4</span>

説明

  1. これは、グループを構成するすべての隣接するレコード要素を定義するためのキーを使用した位置グループ化です。

  2. キーが使用されるため、これは効率的な(劣線形)アルゴリズムです。兄弟軸を使用するアルゴリズムは、通常O(N^2)、時間計算量が2乗であり、兄弟の総数が多い場合は遅すぎる可能性がありますN

于 2012-07-13T12:33:24.140 に答える
1

ノードが常に隣接している場合は、次のような単純なものを使用できます。

<xsl:template match="/">
    <xsl:for-each select="Records/Record">
        <xsl:if test="position() = 1 or @group != preceding-sibling::Record[1]/@group">
            <span><xsl:value-of select="@id" />
            <xsl:if test="following-sibling::Record/@group = @group">
                <xsl:variable name="following" select="following-sibling::Record[@group = ./@group]"/>
             - <xsl:value-of select="$following[count($following)]/@id"/>
            </xsl:if>
            </span>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

ただし、そうでない場合は、より堅牢なものを考え出し、ノードを手動でカウントするために、再帰関数が必要になる可能性があります。

于 2012-07-13T11:10:47.743 に答える