2

次の入力があります。

<articles>
  <item name="B">
    <item name="Bb">
      <item name="Bbb"/>
      <item name="Abb"/>
    </item>
    <item name="Ab">
      <item name="Bab"/>
      <item name="Aab"/>
    </item>
  </item>
  <item name="A">
    <item name="Ba">
      <item name="Bba"/>
      <item name="Aba"/>
    </item>
    <item name="Aa">
      <item name="Baa"/>
      <item name="Aaa"/>
    </item>
  </item>
  <item name="D"/>
  <item name="C">
    <item name="Ac"/>
  </item>
</articles>

そして、次の出力が必要です。

A-Aa-Aaa
A-Aa-Baa
A-Ba-Aba
A-Ba-BBa
B-Ab-Aab
B-Ab-Bab
B-Bb-Abb
B-Bb-Bbb
C-Ac
D

つまり、すべてのパスは明示的に作成され、すべてのレベルでソートされます。パスを生成する次の XSLT がありますが、最初のレベルを除いて、並べ替えがわかりません。

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

  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="articles">
    <xsl:apply-templates select="//item[not(item)]">
      <xsl:sort select="ancestor-or-self::item[parent::articles]/@name"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="item">
    <xsl:for-each select="ancestor-or-self::item">
      <xsl:value-of select="@name"/>
      <xsl:choose>
        <xsl:when test="not(item)">
          <xsl:text>&#xA;</xsl:text>
        </xsl:when>
        <xsl:otherwise>-</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

私の現在のアプローチは行き止まりになっているのではないかと心配しています。アイデア?

4

2 に答える 2

3

XSLT 2.0 ソリューション (パート II) の方がはるかに短くて単純であることに注意してください


I. これは単純な 2 パス ソリューションです。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
    <xsl:apply-templates/>
  </xsl:variable>

  <xsl:for-each select="ext:node-set($vrtfPass1)/*">
   <xsl:sort/>
   <xsl:value-of select="concat(., '&#xA;')"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="item[not(item)]">
     <x>
      <xsl:for-each select="ancestor-or-self::item">
       <xsl:if test="not(position() = 1)">-</xsl:if>
       <xsl:value-of select="@name"/>
      </xsl:for-each>
     </x>
 </xsl:template>
</xsl:stylesheet>

この変換が提供された XML ドキュメントに適用されると、次のようになります。

<articles>
  <item name="B">
    <item name="Bb">
      <item name="Bbb"/>
      <item name="Abb"/>
    </item>
    <item name="Ab">
      <item name="Bab"/>
      <item name="Aab"/>
    </item>
  </item>
  <item name="A">
    <item name="Ba">
      <item name="Bba"/>
      <item name="Aba"/>
    </item>
    <item name="Aa">
      <item name="Baa"/>
      <item name="Aaa"/>
    </item>
  </item>
  <item name="D"/>
  <item name="C">
    <item name="Ac"/>
  </item>
</articles>

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

A-Aa-Aaa
A-Aa-Baa
A-Ba-Aba
A-Ba-Bba
B-Ab-Aab
B-Ab-Bab
B-Bb-Abb
B-Bb-Bbb
C-Ac
D

注意: これは、要素のネストに対して正しく機能する一般的なソリューションです。item

説明:

  1. 2 パス変換を実行します。

  2. 最初のパスの結果は次のとおりです。

    <x xmlns:ext="http://exslt.org/common">B-Bb-Bbb</x>
    <x xmlns:ext="http://exslt.org/common">B-Bb-Abb</x>
    <x xmlns:ext="http://exslt.org/common">B-Ab-Bab</x>
    <x xmlns:ext="http://exslt.org/common">B-Ab-Aab</x>
    <x xmlns:ext="http://exslt.org/common">A-Ba-Bba</x>
    <x xmlns:ext="http://exslt.org/common">A-Ba-Aba</x>
    <x xmlns:ext="http://exslt.org/common">A-Aa-Baa</x>
    <x xmlns:ext="http://exslt.org/common">A-Aa-Aaa</x>
    <x xmlns:ext="http://exslt.org/common">D</x>
    <x xmlns:ext="http://exslt.org/common">C-Ac</x>
    
  3. 最初のパスの処理では、リーフ item要素のみに一致する単一のテンプレートが使用されます。リーフitem要素ごとに、ダッシュで区切られた完全なパスが、 という名前の要素の内容として出力されxます。

  4. 2 番目のパスは、最初のパスの結果を並べ替えるだけです。


Ⅱ.XSLT 2.0 ソリューション:

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

 <xsl:template match="/">
     <xsl:for-each-group select="//item[not(item)]"
     group-by="string-join(ancestor-or-self::item/@name, '-')">
      <xsl:sort select="current-grouping-key()"/>
      <xsl:sequence select="current-grouping-key(), '&#xA;'"/>
     </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>
于 2012-08-23T12:02:37.250 に答える
0

見栄えはよくありませんが、以下は 3 項目の深さでそれを行い、追加のレベルごとに追加の並べ替えが必要になります。私は、教祖がこれをより一般的に行うことができると確信しています:)

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

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="articles">
        <xsl:apply-templates select="//item[not(item)]">
            <xsl:sort select="ancestor-or-self::item[parent::articles]/@name"/>
            <xsl:sort select="ancestor-or-self::item[parent::item[parent::articles]]/@name"/>
            <xsl:sort select="ancestor-or-self::item[parent::item[parent::item[parent::articles]]]/@name"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="item">
        <xsl:for-each select="ancestor-or-self::item">
            <xsl:value-of select="@name"/>
            <xsl:choose>
                <xsl:when test="not(item)">
                    <xsl:text>&#xA;</xsl:text>
                </xsl:when>
                <xsl:otherwise>-</xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>
于 2012-08-23T11:52:53.337 に答える