Как организовать (группировать) узлы под замкнутым элементом - 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
с и House
s, которые находятся в одной и той же позиции и удаляют повторение номеров позиций. Например, это будет выглядеть так:
<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)