XSLT разделяет отсортированные данные на разные таблицы

Я пытаюсь отформатировать данные xml в две таблицы HTML. Я успешно могу отсортировать некоторые фиктивные данные xls:sort, но я не могу разделить отсортированные данные на разные таблицы.

Мой xml:

<a>
    <b id="N">text1</b>
    <b id="N">text2</b>
    <b id="N+1">text3</b>
    <b id="N">text4</b>
    <b id="N+2">text5</b>
    <b id="N+3">text6</b>
    <b id="N">text7</b>
    <b id="N+2">text8</b>
</a>

N в данном случае число, но я не знаю, какое число. Это могут быть 2 и 55, 3 и 4, 44 и 52, 78 и 98.

Каждый номер я хочу отправить в свою таблицу, поэтому результат будет таким:

<table>
    <tr><td>text1</td></tr>
    <tr><td>text2</td></tr>
    <tr><td>text4</td></tr>
    <tr><td>text7</td></tr>
</table>

<table>
    <tr><td>text3</td></tr>
</table>

<table>
    <tr><td>text5</td></tr>
    <tr><td>text8</td></tr>
</table>

<table>
    <tr><td>text6</td></tr>
</table>

Как я могу разделить отсортированные данные на разные таблицы в зависимости от их атрибута?

Любые указатели будут оценены.


person user2664413    schedule 08.08.2013    source источник
comment
XSLT 1.0 или 2.0? Последнее проще.   -  person Ian Roberts    schedule 08.08.2013
comment
Мы используем версию 1.0, я боюсь.   -  person user2664413    schedule 08.08.2013
comment
Покажите xslt, который вы пробовали, пожалуйста   -  person Mark Schultheiss    schedule 08.08.2013


Ответы (1)


Стандартный подход к решению такого рода задач в XSLT 1.0 называется группировка по Мюнху. Вы определяете ключ, который группирует ваши целевые элементы так, как вы хотите.

<xsl:key name="bsById" match="b" use="@id" />

затем используйте трюк с generate-id, чтобы извлечь только первый узел в каждой группе в качестве прокси для группы в целом

<xsl:apply-templates select="b[generate-id()
                             = generate-id(key('bsById', @id)[1])]"
                     mode="group">
  <xsl:sort select="@id" />
</xsl:apply-templates>

Итак, теперь следующий шаблон будет запускаться один раз для каждой группы, и вы можете использовать внутри него функцию key, чтобы получить все узлы в группе.

<xsl:template match="b" mode="group">
  <table>
    <!-- extract all the nodes that are grouped with this one -->
    <xsl:apply-templates select="key('bsById', @id)">
      <!-- you could <xsl:sort> here if you want to sort within groups -->
    </xsl:apply-templates>
  </table>
</xsl:template>

<xsl:template match="b">
  <tr><td>...</td></tr>
</xsl:template>

Все вышеперечисленное хорошо, если этот пример представляет собой весь ваш XML-документ, но если в документе есть более одного элемента a, каждый из которых имеет собственный набор элементов b, которые необходимо сгруппировать независимо, тогда ключ должен быть более сложным. Обычный трюк здесь состоит в том, чтобы использовать generate-id родительского узла a как часть значения ключа группировки для его b дочерних элементов:

<xsl:key name="bsByParentAndId" match="a/b" use="concat(generate-id(..), '|', @id)" />

и для выражения мюнхианской группировки

<xsl:template match="a">
  <xsl:apply-templates select="b[generate-id()
                               = generate-id(key('bsByParentAndId', concat(
                                   generate-id(current()), '|', @id))[1])]"
                       mode="group"/>
</xsl:template>

Кстати, если бы вы могли использовать XSLT 2.0, это стало бы значительно проще. Нет необходимости определять сложный ключ, вы просто используете for-each-group

<xsl:template match="a">
  <xsl:for-each-group select="b" group-by="@id">
    <xsl:sort select="current-grouping-key()" />
    <table>
      <xsl:apply-templates select="current-group()" />
    </table>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="b">
  <tr><td>...</td></tr>
</xsl:template>
person Ian Roberts    schedule 08.08.2013
comment
Это делает работу идеально, спасибо за дополнительную часть, где у меня есть более одного ‹a› с тех пор, как я это сделал. Также спасибо за то, что сделали все это, не ожидал этого. Теперь я просто должен понять все это. - person user2664413; 09.08.2013