Как организовать (группировать) узлы под замкнутым элементом - XSLT

Я попробовал простую группировку XML с XSLT 1.0, и это сработало, но здесь у меня возникла более сложная и действительно другая ситуация. Итак, структура XML в основном такая:

<Main>
 <TB>
    --> some elements and stuff - not relevant
   <City>
     <Area>
       <Position>5</Position>
       <House>

       --> some elements and stuff

       </House>
     </Area>
     <Area>
       <Position>5</Position>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
     <Area>
       <Position>6</Position>
       <House>

       --> some elements and stuff

       </House>
     </Area>
     <Area>
       <Position>6</Position>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
   </City>
   <City>

   --> same structure but with several repetitions of Position 7 and 8.

   </City>
 </TB>
</Main>

Что мне нужно, это сгруппировать Blockс и Houses, которые находятся в одной и той же позиции и удаляют повторение номеров позиций. Например, это будет выглядеть так:

   <City>
     <Area>
       <Position>5</Position>
       <House>

       --> some elements and stuff

       </House>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
     <Area>
       <Position>6</Position>
       <House>

       --> some elements and stuff

       </House>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
   </City>
   <City>

   --> same structure for Position 7 and 8.

   </City>

Это сложнее, потому что Позиция не является атрибутом Района, поэтому мне в основном нужно определить значение Позиции Района, затем взять Дом и Блок, которые попадают под одну и ту же Позицию, и соединить их в окружении одного и того же объекта. <Area> </Area>,

1 ответ

Решение

Для меня это выглядит как довольно стандартная проблема группировок Мюнхена, группировка Area элементы (не House или же Block элементы непосредственно) их Position,

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

  <xsl:key name="areaByPosition" match="Area" use="Position" />

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

  <!-- for the first Area in each Position -->
  <xsl:template match="Area[generate-id() =
                            generate-id(key('areaByPosition', Position)[1])]">
    <Area>
      <!-- copy in the Position element once only -->
      <xsl:apply-templates select="Position" />
      <!-- copy in all sub-elements except Position from all matching Areas -->
      <xsl:apply-templates select="
            key('areaByPosition', Position)/*[not(self::Position)]" />
    </Area>
  </xsl:template>

  <!-- ignore all other Area elements -->
  <xsl:template match="Area" />
</xsl:stylesheet>

Это предполагает, что нет других названных элементов Area в другом месте документа, если любой из "некоторых элементов и вещей" может быть назван Area тогда вам нужно быть более конкретным, например, ограничивая группировку Area элементы, которые являются прямыми детьми City:

<xsl:key name="areaByPosition" match="City/Area" use="Position" />

<xsl:template match="City/Area[generate-id() =
                               generate-id(key('areaByPosition', Position)[1])]"
              priority="2">
  ...
</xsl:template>

<xsl:template match="City/Area" priority="1" />

(с явными приоритетами, потому что без этого оба шаблона будут иметь одинаковый приоритет по умолчанию 0,5)

Другие вопросы по тегам