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

Учитывая этот исходный XML:

<output>
   <report>
      <C01>
         <InvID>001</InvID>
         <Daily>
            <row id="0000">1</row>
            <row id="0001">2</row>
            <row id="0002">5</row>
            <row id="0003">4</row>
         </Daily>
      </C01>
      <C02>
         <InvID>002</InvID>
         <Daily>
            <row id="0000">4</row>
            <row id="0001">3</row>
            <row id="0002">2</row>
            <row id="0003">5</row>
         </Daily>
      </C02>
      <C03>
         <InvID>001</InvID>
         <Daily>
            <row id="0000">3</row>
            <row id="0001">7</row>
            <row id="0002">2</row>
            <row id="0003">4</row>
         </Daily>
      </C03>
   <report>
<output>

Как я могу произвести этот вывод:

<Data invID=001>
   <Value>1</Value>
   <Value>2</Value>
   <Value>5</Value>
   <Value>4</Value>
   <Value>3</Value>
   <Value>7</Value>
   <Value>2</Value>
   <Value>4</Value>
</Data>
<Data invID=002>
   <Value>4</Value>
   <Value>3</Value>
   <Value>2</Value>
   <Value>5</Value>
</Data>

Я пытался использовать что-то вроде этого в качестве основы, но это кажется неправильным:

<xsl:template match="output/report">
   <xsl:for-each select="*[starts-with(name(), 'C') and InvID != '']">
      <xsl:sort select="InvID" />
      <xsl:element name="Data">
         <xsl:attribute name="invID">
            <xsl:value-of select="InvID" />
         </xsl:attribute>
      </xsl:element>
   </xsl:for-each>
</xsl:template>

Мне нужно объединить все элементы, которые имеют общий InvID, вывести один элемент Data для этой группы исходных элементов, а затем вывести все их значения элемента row в дочерние элементы этого элемента Data (Value).

Можно ли это сделать в XPath 1.0?


person DonBoitnott    schedule 10.02.2015    source источник
comment
Найдите мюнхенскую группировку, это стандартный подход для этого в XSLT 1.0.   -  person Ian Roberts    schedule 10.02.2015
comment
Хотя ваш ожидаемый результат не соответствует вашему описанию, вы сгруппировали строки C01 и C02 вместе, а не строки C01 и C03. А также вам нужно будет обернуть вывод в один элемент верхнего уровня, чтобы сделать его правильно сформированным.   -  person Ian Roberts    schedule 10.02.2015
comment
@IanRoberts Хороший улов ... исправлено.   -  person DonBoitnott    schedule 10.02.2015
comment
@IanRoberts Я понял суть метода и кое-что читал раньше. Но я не смог найти пример элемента, у которого нет нестатического имени элемента. т.е. примеры, которые я нахожу, имеют фиксированную структуру узла, но основной узел, который мне нужно сгруппировать, является переменным... C01, C02, C03 и т. д. Не знаю, как это указать...   -  person DonBoitnott    schedule 10.02.2015


Ответы (1)


Как я предлагаю в своем комментарии, метод, который вы ищете, называется группировка по Мюнху. Это работает путем определения ключа, который группирует связанные узлы вместе, а затем использования трюка с generate-id или count для создания набора узлов, состоящего из одного «репрезентативного» узла для каждой группы. В вашем случае, поскольку узлы, которые вы хотите сгруппировать, имеют разные имена, вам нужно быть немного более творческим с соответствующими шаблонами, но принцип тот же:

<xsl:key name="groupByInv" match="*[InvID]" use="InvID" />

Здесь меня интересует любой элемент (независимо от имени), у которого есть дочерний элемент InvID, и я хочу сгруппировать их вместе на основе значения InvID. Теперь фактическая группировка проста:

<xsl:template match="output/report">
  <xsl:for-each select="*[InvID][generate-id() =
         generate-id(key('groupByInv', InvID)[1])]">
    <Data invID="{InvID}">
      <!-- process all the rows under all the elements in the current group -->
      <xsl:apply-templates select="key('groupByInv', InvID)/Daily/row" />
    </Data>
  </xsl:for-each>
</xsl:template>

<xsl:template match="row">
  <Value><xsl:value-of select="."/></Value>
</xsl:template>
person Ian Roberts    schedule 10.02.2015
comment
Большое спасибо, Ян. В последнее время я так редко сталкиваюсь с XML/XPath... Работает как шарм! - person DonBoitnott; 10.02.2015