Вложенная группировка XSLT для каждой группы

Мне нужно сгруппировать значения на основе определенных атрибутов. Поэтому я хотел бы использовать для каждой группы.

Это входной XML, который я использую:

<?xml version="1.0" encoding="ISO-8859-1"?>
<cities>
  <city country="Germany"   continent="Europe">Munich</city>
  <city country="Germany"   continent="Europe">Dortmund</city>
  <city country="France"    continent="Europe">Brest</city>
  <city country="Japan"         continent="Asia" >Tokyo</city>
  <city country="Korea"      continent="Asia" >Seoul</city>
  <city country="Germany"   continent="Europe">Hannover</city>
  <city country="Poland"         continent="Europe">Krakau</city>
  <city country="Russia"      continent="Asia" >Omsk</city>
  <city country="Japan"         continent="Asia" >Kobe</city>
  <city country="Japan"         continent="Asia" >Ibaraki</city>
  <city country="Russia"      continent="Europe">St. Petersburg</city>
  <city country="Saudi-Arabia" continent="Africa">Riad</city>
  <city country="Ireland"        continent="Europe">Galway</city>
  <city country="Cameroon"       continent="Africa">Yaoundé</city>
  <city country="Austria"    continent="Europe">Vienna</city>
</cities>

Теперь я хочу создать выходной файл в формате вложенного списка.
Прежде всего я хочу сгруппировать по континентам, а затем внутренне по странам, т. е. сгруппировать города внутри стран и континентов.

Вывод должен выглядеть примерно так:

<ul>
  <li>Europe
    <ul>
      <li>Germany
        <ul>
          <li>Munich</li>
          <li>Dortmund</li>
          <li>...</li>
        </ul>          
      </li>
      <li>France
        <ul>
          <li>...</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Asia
    <ul>...</ul>
  </li>
  <li>Africa
    <ul>...</ul>
  </li>
</ul>

На данный момент у меня есть следующая таблица стилей XSLT:

<xsl:template match="cities">
  <ul>
    <xsl:for-each-group select="city" group-by="@continent">
      <li>
        <xsl:value-of select="@continent" />
          <xsl:for-each-group select="stadt" group-by="@land">
           <ul>
             <li>
               <xsl:value-of select="@land" />
             </li>
           </ul>
         </xsl:for-each-group>
      </li>
    </xsl:for-each-group>
  </ul>
</xsl:template>

Это отлично работает для первого уровня, т.е. группировки по континентам. Но это не работает для вложенных уровней в списке. Мне нужен способ сослаться на текущий элемент группировки, чтобы группировать по странам только для текущего континента.

Каким будет лучший/самый удобный способ сделать это?


person mawo    schedule 01.11.2012    source источник


Ответы (1)


Ваш XSLT не совсем соответствует XML, потому что ваш вложенный xsl:for-each-group ссылается на элемент stadt и атрибут @land< /strong>, которые не отображаются в XML. Однако я думаю, что вам действительно нужно использовать функцию current-group() для перебора элементов в группе. В этом случае вы группируете по странам в пределах текущего континента.

<xsl:for-each-group select="current-group()" group-by="@country">

И тогда вам понадобится еще один вложенный цикл для перебора городов страны.

<xsl:for-each select="current-group()">

Вот полный XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="cities">
      <ul>
         <xsl:for-each-group select="city" group-by="@continent">
            <li>
               <xsl:value-of select="@continent"/>
               <ul>
                  <xsl:for-each-group select="current-group()" group-by="@country">
                     <li>
                        <xsl:value-of select="@country"/>
                        <ul>
                           <xsl:for-each select="current-group()">
                              <li>
                                 <xsl:value-of select="."/>
                              </li>
                           </xsl:for-each>
                        </ul>
                     </li>
                  </xsl:for-each-group>
               </ul>
            </li>
         </xsl:for-each-group>
      </ul>
   </xsl:template>
</xsl:stylesheet>

При запуске на данном XML выводится следующее

<ul>
   <li>Europe
      <ul>
         <li>Germany
            <ul>
               <li>Munich</li>
               <li>Dortmund</li>
               <li>Hannover</li>
            </ul></li>
         <li>France
            <ul>
               <li>Brest</li>
            </ul></li>
         <li>Poland
            <ul>
               <li>Krakau</li>
            </ul></li>
         <li>Russia
            <ul>
               <li>St. Petersburg</li>
            </ul></li>
         <li>Ireland
            <ul>
               <li>Galway</li>
            </ul></li>
         <li>Austria
            <ul>
               <li>Vienna</li>
            </ul></li>
      </ul></li>
   <li>Asia
      <ul>
         <li>Japan
            <ul>
               <li>Tokyo</li>
               <li>Kobe</li>
               <li>Ibaraki</li>
            </ul></li>
         <li>Korea
            <ul>
               <li>Seoul</li>
            </ul></li>
         <li>Russia
            <ul>
               <li>Omsk</li>
            </ul></li>
      </ul></li>
   <li>Africa
      <ul>
         <li>Saudi-Arabia
            <ul>
               <li>Riad</li>
            </ul></li>
         <li>Cameroon
            <ul>
               <li>Yaound</li>
            </ul></li>
      </ul></li>
</ul>

Обратите внимание: вы можете заменить самый внутренний xsl:for-each на xsl:apply-templates, чтобы избежать чрезмерного отступа!

person Tim C    schedule 01.11.2012
comment
Есть ли способ создать атрибут на уровне континента, указывающий количество стран в группе? - person AP.; 01.07.2019