xsl группировка повторяющихся узлов по элементу xml в xslt1

У меня есть сложная структура XML, которая выглядит следующим образом:

  <Items>
      <Item>
          <ItemTexts>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
              <ItemTextsLine>1</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
              <ItemTextsLine>2</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
              <ItemTextsLine>3</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
              <ItemTextsLine>4</ItemTextsLine>
            </ItemText>
          </ItemTexts>
         </Item>
    <Item>
          <ItemTexts>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
              <ItemTextsLine>1</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
              <ItemTextsLine>2</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
              <ItemTextsLine>3</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
              <ItemTextsLine>4</ItemTextsLine>
            </ItemText>
          </ItemTexts>
         </Item>
<Item>
          <ItemTexts>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
              <ItemTextsLine>1</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type1</ItemTextsType>
              <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
              <ItemTextsLine>2</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
              <ItemTextsLine>3</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
              <ItemTextsLine>4</ItemTextsLine>
            </ItemText>
          </ItemTexts>
         </Item>
    <Item>
          <ItemTexts>
            <ItemText>
              <ItemTextsType>type3</ItemTextsType>
              <ItemTextsTypeDesc>description31</ItemTextsTypeDesc>
              <ItemTextsLine>1</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type3</ItemTextsType>
              <ItemTextsTypeDesc>description32</ItemTextsTypeDesc>
              <ItemTextsLine>2</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
              <ItemTextsLine>3</ItemTextsLine>
            </ItemText>
            <ItemText>
              <ItemTextsType>type2</ItemTextsType>
              <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
              <ItemTextsLine>4</ItemTextsLine>
            </ItemText>
          </ItemTexts>
         </Item>
    </Items>

Я использую xsl для каждого элемента, например:

<xsl:for-each select="Items/Item">

Мне нужен пример того, как группировать <ItemText> от <ItemTextsType> индивидуально для каждого <Item> итак результат будет такой:

Для первого <Item> в этом примере:

Тип 1

description11

description12

типа2

description21

description22

Для второго Item в этом примере:

3тип

description31

description32

типа2

description21

description22

конечно я организую результат в таблице как:

<table width="100%" border="1" style="display: block;">
        <tbody>
            <tr>
                <td id="SelectedRowLinkageContents">
                    <table width="100%" dir="ltr">
                        <tbody>
                            <tr style="background-color: #507CD1; text-align: center">
                                <td colspan="3" style="font: bold; color: white">
                                    Item1
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type1
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription11
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription12
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type2
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription21
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription22
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription23
                                </td>
                            </tr>
                        </tbody>
                    </table>

                    <table width="100%" dir="ltr">
                        <tbody>
                            <tr style="background-color: #507CD1; text-align: center">
                                <td colspan="3" style="font: bold; color: white">
                                    Item2
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type1
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription11
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription12
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type2
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription21
                                </td>
                            </tr>

                            <tr>
                                <td>
                                    desription23
                                </td>
                            </tr>
                        </tbody>
                    </table>

                    <table width="100%" dir="ltr">
                        <tbody>
                            <tr style="background-color: #507CD1; text-align: center">
                                <td colspan="3" style="font: bold; color: white">
                                    Item3
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type1
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription11
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription12
                                </td>
                            </tr>
                            <tr>
                                <td style="height: 35px; font: bold; color: #507CD1;">
                                    type2
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    desription21
                                </td>
                            </tr>

                            <tr>
                                <td>
                                    desription23
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </td>
            </tr>
        </tbody>
    </table>

Дело в том, что существует отдельная группировка для каждого <Item> в свое собственное <table> и внутри этого <table> там глотает <ItemTextsType>

Я пробовал что-то вроде

<xsl:key name="item-texts-type" match="ItemText" use="ItemTextsType" />


<xsl:for-each select="ItemTexts/ItemText[count(. | key('item-texts-type', ItemTextsType)[1]) = 1]">

                        <xsl:sort select="ItemTextsType" />
                        <tr>
                          <td style ="height:35px;font: bold; color:#507CD1;">
                            <xsl:value-of select="ItemTextsType" />
                          </td>
                        </tr>

                        <xsl:for-each select="key('item-texts-type', ItemTextsType)">
                          <tr>
                            <td>
                               <xsl:value-of select="ItemTextsTypeDesc" />
                            </td>
                          </tr>
                        </xsl:for-each>


                      </xsl:for-each>

но он работает только на неповторяющихся узлах (если был только один <Item> это будет работать нормально). Я не могу изменить XML, потому что это исходит от клиента.

Пожалуйста, помогите мне, мне это нужно как можно скорее.

Спасибо!!!!

1 ответ

Решение

Из-за некоторых расхождений все еще трудно сказать, какое искомое решение имеет место - например, ваш входной XML имеет 4 <Item> элементы, но желаемый результат учитывает только 3 из них. Кроме того, несколько описаний в желаемом выводе не совпадают с их ожидаемым расположением во входном XML-документе.

Тем не менее, если мы сосредоточимся на вашем заявленном желаемом решении:

"Дело в том, что существует отдельная группировка для каждого <Item> в свое собственное <table> и внутри этого <table> там глотает <ItemTextsType>"

... тогда это должно привести вас в правильном направлении.

Когда это XSLT:

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

  <xsl:key
    name="kItemTextByType"
    match="ItemText"
    use="concat(generate-id(ancestor::Item[1]), '+', ItemTextsType)" />

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

  <xsl:template match="/*">
    <table width="100%" border="1" style="display: block;">
      <tbody>
        <tr>
          <td id="SelectedRowLinkageContents">
            <xsl:apply-templates />
          </td>
        </tr>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="Item">
    <table width="100%" dir="ltr">
      <tbody>
        <tr style="background-color: #507CD1; text-align: center">
          <td colspan="3" style="font: bold; color: white">
            <xsl:value-of select="concat('Item', position())" />
          </td>
        </tr>
        <xsl:apply-templates 
          select="ItemTexts/ItemText[
            generate-id() = 
            generate-id(
              key(
                'kItemTextByType', 
                 concat(generate-id(current()), '+', ItemTextsType)
              )[1]
            )
          ]">
          <xsl:sort select="ItemTextsType" />
        </xsl:apply-templates>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="ItemText">
    <tr>
      <td style="height: 35px; font: bold; color: #507CD1;">
        <xsl:value-of select="ItemTextsType" />
      </td>
    </tr>
    <xsl:for-each
      select="key(
        'kItemTextByType', 
        concat(
          generate-id(ancestor::Item[1]),
          '+',
          ItemTextsType
        )
      )"
    >
      <xsl:sort select="ItemTextsTypeDesc" />
      <tr>
        <td>
          <xsl:value-of select="ItemTextsTypeDesc" />
        </td>
      </tr>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

... применяется к предоставленному входному XML:

<?xml version="1.0" encoding="UTF-8"?>
<Items>
  <Item>
    <ItemTexts>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
        <ItemTextsLine>1</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
        <ItemTextsLine>2</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
        <ItemTextsLine>3</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
        <ItemTextsLine>4</ItemTextsLine>
      </ItemText>
    </ItemTexts>
  </Item>
  <Item>
    <ItemTexts>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
        <ItemTextsLine>1</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
        <ItemTextsLine>2</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
        <ItemTextsLine>3</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
        <ItemTextsLine>4</ItemTextsLine>
      </ItemText>
    </ItemTexts>
  </Item>
  <Item>
    <ItemTexts>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description11</ItemTextsTypeDesc>
        <ItemTextsLine>1</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type1</ItemTextsType>
        <ItemTextsTypeDesc>description12</ItemTextsTypeDesc>
        <ItemTextsLine>2</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
        <ItemTextsLine>3</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
        <ItemTextsLine>4</ItemTextsLine>
      </ItemText>
    </ItemTexts>
  </Item>
  <Item>
    <ItemTexts>
      <ItemText>
        <ItemTextsType>type3</ItemTextsType>
        <ItemTextsTypeDesc>description31</ItemTextsTypeDesc>
        <ItemTextsLine>1</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type3</ItemTextsType>
        <ItemTextsTypeDesc>description32</ItemTextsTypeDesc>
        <ItemTextsLine>2</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description21</ItemTextsTypeDesc>
        <ItemTextsLine>3</ItemTextsLine>
      </ItemText>
      <ItemText>
        <ItemTextsType>type2</ItemTextsType>
        <ItemTextsTypeDesc>description22</ItemTextsTypeDesc>
        <ItemTextsLine>4</ItemTextsLine>
      </ItemText>
    </ItemTexts>
  </Item>
</Items>

... желаемый результат получается (я думаю):

<table width="100%" border="1" style="display: block;">
  <tbody>
    <tr>
      <td id="SelectedRowLinkageContents">
        <table width="100%" dir="ltr">
          <tbody>
            <tr style="background-color: #507CD1; text-align: center">
              <td colspan="3" style="font: bold; color: white">Item1</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type1</td>
            </tr>
            <tr>
              <td>description11</td>
            </tr>
            <tr>
              <td>description12</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type2</td>
            </tr>
            <tr>
              <td>description21</td>
            </tr>
            <tr>
              <td>description22</td>
            </tr>
          </tbody>
        </table>
        <table width="100%" dir="ltr">
          <tbody>
            <tr style="background-color: #507CD1; text-align: center">
              <td colspan="3" style="font: bold; color: white">Item2</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type1</td>
            </tr>
            <tr>
              <td>description11</td>
            </tr>
            <tr>
              <td>description12</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type2</td>
            </tr>
            <tr>
              <td>description21</td>
            </tr>
            <tr>
              <td>description22</td>
            </tr>
          </tbody>
        </table>
        <table width="100%" dir="ltr">
          <tbody>
            <tr style="background-color: #507CD1; text-align: center">
              <td colspan="3" style="font: bold; color: white">Item3</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type1</td>
            </tr>
            <tr>
              <td>description11</td>
            </tr>
            <tr>
              <td>description12</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type2</td>
            </tr>
            <tr>
              <td>description21</td>
            </tr>
            <tr>
              <td>description22</td>
            </tr>
          </tbody>
        </table>
        <table width="100%" dir="ltr">
          <tbody>
            <tr style="background-color: #507CD1; text-align: center">
              <td colspan="3" style="font: bold; color: white">Item4</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">type2</td>
            </tr>
            <tr>
              <td>description21</td>
            </tr>
            <tr>
              <td>description22</td>
            </tr>
            <tr>
              <td style="height: 35px; font: bold; color: #507CD1;">
              type3</td>
            </tr>
            <tr>
              <td>description31</td>
            </tr>
            <tr>
              <td>description32</td>
            </tr>
          </tbody>
        </table>
      </td>
    </tr>
  </tbody>
</table>

... который при рендеринге на HTML-странице выглядит следующим образом:

HTML таблица

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