Группировка узлов по жесткому кодированию значений узлов в XSLT

#xml #group-by #xslt-1.0 #xslt-2.0 #muenchian-grouping

#xml #группировка по #xslt-1.0 #xslt-2.0 #muenchian-группировка

Вопрос:

 <root>
   <Entry>
      <ID>1</ID>
      <Details>
         <Code>A1</Code>
         <Value>1000</Value>
      </Details>
   </Entry>

   <Entry>
      <ID>2</ID>
      <Details>
         <Code>A2</Code>
         <Value>2000</Value>
      </Details>
   </Entry>

   <Entry>
      <ID>3</ID>
      <Details>
         <Code>B1</Code>
         <Value>3000</Value>
      </Details>
   </Entry>

   <Entry>
      <ID>4</ID>
      <Details>
         <Code>B2</Code>
         <Value>4000</Value>
      </Details>
   </Entry>
</root>
  

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

Группировка должна выполняться на основе параметра кода, отображаемого в узле <Code> следующим образом:

  1. Коды ‘A1’ и ‘A2’ должны быть сгруппированы вместе
  2. Коды ‘B1’ и ‘B2’ должны быть сгруппированы вместе

В конечном итоге я суммирую значения, исходящие от <Value> узлов в этих группах. Таким образом, результат будет следующим:

 <Output>
   <Code-group> A </Code-group>
   <Sum> 3000 </Sum>

   <Code-group> B </Code-group>
   <Sum> 7000 </Sum>
</Output>
  

Для этого требования должно быть жесткое кодирование значений группировки (для группировки A1, A2 как A и B1, B2 как B). Я использую слово «жестко закодированный», потому что коды (A1, A2, B1, B2) могут быть в любом порядке, поэтому я хочу скорее жестко кодировать значения для поиска группировки, чем для поиска индексов узлов.

Я рассмотрел метод for-each-group, а также метод группировки Muenchian, но не смог добиться приведенного выше сопоставления групп. Любая помощь приветствуется!

Заранее спасибо

РЕДАКТИРОВАТЬ: отображение A1, A2 —> A amp; B1, B2 —> B является общим примером, фактические значения узлов полностью отличаются от этого, поэтому решение для подстроки не будет работать. Вот почему я сосредоточился на жестком кодировании для достижения этого сопоставления.

Ответ №1:

Требование жесткого кодирования сложно понять. Возможно, вы хотите сделать что-то вроде:

XSLT 2.0

 <xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="entry" match="Entry" use="Details/Code"/>

<xsl:template match="/root">
    <Output>
        <Code-group> A </Code-group>
        <Sum>
            <xsl:value-of select="sum(key('entry', ('A1', 'A2'))/Details/Value)" />
        </Sum>
        <Code-group> B </Code-group>
        <Sum>
            <xsl:value-of select="sum(key('entry', ('B1', 'B2'))/Details/Value)" />
        </Sum>
    </Output>
</xsl:template>

</xsl:stylesheet>
  

Комментарии:

1. Неплохо. Это намного лучшая версия xsl: key, чем моя.

2. Спасибо, Майкл, это именно то, что я искал. Отличное решение!

Ответ №2:

Если у вас есть возможность использовать for-each-group , я бы определенно использовал это поверх Muenchian grouping …

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

  <xsl:template match="/*">
    <Output>
      <xsl:for-each-group select="Entry" group-by="substring(Details/Code,1,1)">
        <Code-group>
          <xsl:value-of select="current-grouping-key()"/>
        </Code-group>
        <Sum>
          <xsl:value-of select="sum(current-group()/Details/Value)"/>
        </Sum>
      </xsl:for-each-group>
    </Output>
  </xsl:template>
  
</xsl:stylesheet>
  

Скрипка: http://xsltfiddle .liberty-development.net/jxNakzX

Если вы действительно хотите жестко запрограммировать отображение «A» -> A1, A2 и «B» -> B1, B2, вы можете использовать xsl: key и вообще не группировать…

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

  <xsl:key name="A" match="Entry[Details/Code=('A1','A2')]" use="'A'"/>
  <xsl:key name="B" match="Entry[Details/Code=('B1','B2')]" use="'B'"/>

  <xsl:template match="/*">
    <xsl:variable name="ctx" select="."/>
    <Output>
      <xsl:for-each select="('A','B')">
        <xsl:variable name="key" select="."/>
        <Code-group>
          <xsl:value-of select="$key"/>
        </Code-group>
        <Sum>
          <xsl:value-of select="sum($ctx/key($key,$key)/Details/Value)"/>
        </Sum>
      </xsl:for-each>
    </Output>
  </xsl:template>
  
</xsl:stylesheet>
  

Скрипка: http://xsltfiddle .liberty-development.net/jxNakzX/1

Комментарии:

1. Спасибо за ответ, но я указал отображение (A1, A2 в A) в общем виде, и фактическое отображение не так просто. Поэтому я не думаю, что взятие подстроки этого значения узла помогло бы в моем случае. Вот почему я сосредоточился на каком-то жестком кодировании значения.

2. Спасибо за обновление, Дэниел. Это сложное использование xsl:key помогло мне очень хорошо понять его концепцию. Спасибо за решение.