Группировка вложенных элементов в xslt 1.0

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

Мой XML в настоящее время выглядит так:

<?xml version="1.0" encoding="utf-8"?>
<ContestResults>
  <Contests>
    <Contest sportId="35">
      <Sport>Beach Volleyball</Sport>
      <Event>Men's</Event>
      <Ranks>
        <Rank position="1" eventId="1">
          <Athlete>Athlete 1a / Athlete 2a [GER]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="1">
          <Athlete>Athlete 1b / Athlete 2b [NED]</Athlete>
          <Result>0</Result>
        </Rank>
      </Ranks>
    </Contest>
    <Contest sportId="32">
      <Sport>Tennis</Sport>
      <Event>Women's Singles</Event>
      <Ranks>
        <Rank position="1" eventId="2">
          <Athlete>Tennis Athlete 1</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="2">
          <Athlete>Tennis Athlete 2</Athlete>
          <Result>1</Result>
        </Rank>
      </Ranks>
    </Contest>
    <Contest sportId="35">
      <Sport>Beach Volleyball</Sport>
      <Event>Men's</Event>
      <Ranks>
        <Rank position="1" eventId="3">
          <Athlete>Athlete 3a / Athlete 4a [AUT]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="3">
          <Athlete>Athlete 3b / Athlete 4b [SUI]</Athlete>
          <Result>0</Result>
        </Rank>
      </Ranks>
    </Contest>
    </Contests>
</ContestResults>

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

<?xml version="1.0" encoding="utf-8"?>
<ContestResults>
  <Contests>
    <Contest sportId="35">
      <Sport>Beach Volleyball</Sport>
      <Event>Men's</Event>
      <Ranks>
        <Rank position="1" eventId="1">
          <Athlete>Athlete 1a / Athlete 2a [GER]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="1">
          <Athlete>Athlete 1b / Athlete 2b [NED]</Athlete>
          <Result>0</Result>
        </Rank>
        <Rank position="1" eventId="3">
          <Athlete>Athlete 3a / Athlete 4a [AUT]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="3">
          <Athlete>Athlete 3b / Athlete 4b [SUI]</Athlete>
          <Result>0</Result>
        </Rank>
      </Ranks>
    </Contest>
    <Contest sportId="32">
      <Sport>Tennis</Sport>
      <Event>Women's Singles</Event>
      <Ranks>
        <Rank position="1" eventId="2">
          <Athlete>Tennis Athlete 1</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="2">
          <Athlete>Tennis Athlete 2</Athlete>
          <Result>1</Result>
        </Rank>
      </Ranks>
    </Contest>
  </Contests>
</ContestResults>

Я просто немного растерялся, как это сделать, так как единственные другие примеры имеют дело с гораздо более простой структурой, и я не уверен, возможно ли это или как мой ключ и шаблоны должны быть структурированы для этого. Кто-нибудь может привести несколько примеров, как этого можно достичь?

Любой совет будет принят во внимание.

1 ответ

Решение

Это преобразование:

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

 <xsl:key name="kContestById" match="Contest" use="@sportId"/>

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

 <xsl:template match="Contests">
      <Contests>
       <xsl:apply-templates/>
      </Contests>
 </xsl:template>

 <xsl:template match=
  "Contest
    [not(generate-id()
    =
     generate-id(key('kContestById', @sportId)[1]))
     ]"/>
 <xsl:template match="Ranks">
  <Ranks>
    <xsl:apply-templates select="key('kContestById', ../@sportId)/Ranks/Rank"/>
  </Ranks>
 </xsl:template>
</xsl:stylesheet>

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

<ContestResults>
  <Contests>
    <Contest sportId="35">
      <Sport>Beach Volleyball</Sport>
      <Event>Men's</Event>
      <Ranks>
        <Rank position="1" eventId="1">
          <Athlete>Athlete 1a / Athlete 2a [GER]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="1">
          <Athlete>Athlete 1b / Athlete 2b [NED]</Athlete>
          <Result>0</Result>
        </Rank>
      </Ranks>
    </Contest>
    <Contest sportId="32">
      <Sport>Tennis</Sport>
      <Event>Women's Singles</Event>
      <Ranks>
        <Rank position="1" eventId="2">
          <Athlete>Tennis Athlete 1</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="2">
          <Athlete>Tennis Athlete 2</Athlete>
          <Result>1</Result>
        </Rank>
      </Ranks>
    </Contest>
    <Contest sportId="35">
      <Sport>Beach Volleyball</Sport>
      <Event>Men's</Event>
      <Ranks>
        <Rank position="1" eventId="3">
          <Athlete>Athlete 3a / Athlete 4a [AUT]</Athlete>
          <Result>2</Result>
        </Rank>
        <Rank position="2" eventId="3">
          <Athlete>Athlete 3b / Athlete 4b [SUI]</Athlete>
          <Result>0</Result>
        </Rank>
      </Ranks>
    </Contest>
    </Contests>
</ContestResults>

дает желаемый, правильный результат:

<ContestResults>
   <Contests>
      <Contest sportId="35">
         <Sport>Beach Volleyball</Sport>
         <Event>Men's</Event>
         <Ranks>
            <Rank position="1" eventId="1">
               <Athlete>Athlete 1a / Athlete 2a [GER]</Athlete>
               <Result>2</Result>
            </Rank>
            <Rank position="2" eventId="1">
               <Athlete>Athlete 1b / Athlete 2b [NED]</Athlete>
               <Result>0</Result>
            </Rank>
            <Rank position="1" eventId="3">
               <Athlete>Athlete 3a / Athlete 4a [AUT]</Athlete>
               <Result>2</Result>
            </Rank>
            <Rank position="2" eventId="3">
               <Athlete>Athlete 3b / Athlete 4b [SUI]</Athlete>
               <Result>0</Result>
            </Rank>
         </Ranks>
      </Contest>
      <Contest sportId="32">
         <Sport>Tennis</Sport>
         <Event>Women's Singles</Event>
         <Ranks>
            <Rank position="1" eventId="2">
               <Athlete>Tennis Athlete 1</Athlete>
               <Result>2</Result>
            </Rank>
            <Rank position="2" eventId="2">
               <Athlete>Tennis Athlete 2</Athlete>
               <Result>1</Result>
            </Rank>
         </Ranks>
      </Contest>
   </Contests>
</ContestResults>

Пояснение:

Правильное использование метода группирования по Мюнхену и переопределение правила идентичности.

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