2

次のようなインデックスのエントリがあります。

<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />

今、私は次のようなものを取得したいと思います

<index name="a" pages="1 />
<index name="b" pages="3-4, 6" />
<index name="c" pages="7" />

そのためにすぐに使える機能はありますか?

私は2パスの解決策を考えていました.最初にインデックスエントリを次のような形式にします.

<index name="a" pages="1 />
<index name="b" pages="3 4 6" />
<index name="c" pages="7" />

「3 4 6」を「3-4, 6」に変えます。最初のステップは簡単です:

<xsl:for-each-group select="index" group-adjacent="@name">
  <xsl:element name="index">
    <xsl:attribute name="name" select="@name"/>
    <xsl:attribute name="pages" select="current-group()/@page"/>
  </xsl:element>
</xsl:for-each-group>

(もちろん、ここでの「ページ」属性は別のものである可能性があります)

次は難しいステップです。リストをどのように反復処理すればよいでしょうか。次の sibling/@page (ページをシーケンスに入れることができます) が現在の @page + 1 であるかどうかを確認するための賢い解決策が必要です。

4

2 に答える 2

2

サンプルは次のとおりです。

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  version="2.0">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:template match="entries">
    <xsl:for-each-group select="entry" group-by="@name">
      <index name="{current-grouping-key()}">
        <xsl:attribute name="pages">
          <xsl:for-each-group select="current-group()/xs:integer(@page)" group-by="position() - .">
            <xsl:if test="position() gt 1">
              <xsl:text>, </xsl:text>
            </xsl:if>
            <xsl:value-of select="if (current-group()[2]) 
                                  then (current-group()[1], current-group()[last()])
                                  else ." 
                          separator="-"/>
          </xsl:for-each-group>
        </xsl:attribute>
      </index>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

入力が

<entries>
<entry name="a" page="1" />
<entry name="b" page="3" />
<entry name="b" page="4" />
<entry name="b" page="6" />
<entry name="c" page="7" />
</entries>

結果が出ます

<index name="a" pages="1"/>
<index name="b" pages="3-4, 6"/>
<index name="c" pages="7"/>
于 2012-04-27T11:08:09.207 に答える
0

ここに別の解決策があります

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"      >
      <xsl:output omit-xml-declaration="yes" indent="yes"/>

      <xsl:template match="entries">
        <xsl:for-each-group select="entry" group-by="@name">
          <index name="{current-grouping-key()}">
            <xsl:attribute name="pages">
              <xsl:variable name="vAtribVals" as="xs:integer*">
                <xsl:perform-sort select="current-group()/@page/xs:integer(.)">
                  <xsl:sort data-type="number"/>
                </xsl:perform-sort>
              </xsl:variable>

              <xsl:sequence select=
                "$vAtribVals[1],
                 for $k in 2 to count($vAtribVals)
                   return
                     if($vAtribVals[$k] - $vAtribVals[$k -1] ne 1)
                       then concat(',', $vAtribVals[$k])
                       else
                         if($vAtribVals[$k+1] - $vAtribVals[$k] ne 1)
                           then concat('-', $vAtribVals[$k])
                           else()
                 "/>
            </xsl:attribute>
          </index>
        </xsl:for-each-group>
      </xsl:template>
</xsl:stylesheet>

この変換が次のXMLドキュメントに適用される場合

<entries>
    <entry name="a" page="1" />
    <entry name="b" page="3" />
    <entry name="b" page="4" />
    <entry name="b" page="6" />
    <entry name="c" page="7" />
</entries>

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

<index name="a" pages="1"/>
<index name="b" pages="3-4,6"/>
<index name="c" pages="7"/>

注意してください

  1. 属性はさらに処理する前にソートされます。これにより、ソースXMLドキュメントで要素がソートされた順序で発生していなくpageても、正しい処理が可能になります。entry

  2. 処理は整数値と位置の関係に依存しないため、属性値が整数でない他の場合にも適用できます。

于 2012-04-27T13:31:27.280 に答える