xslt 1.0 группировка с составными ключами (на разных уровнях)

У меня есть преобразование, при котором я пытаюсь записать набор сглаженных деталей транзакции и в конце файла предоставить сумму итогов, сгруппированных по типу тендера и номеру регистра.
Запись набора отдельных деталей транзакции - простая часть и у меня это работает нормально, но я борюсь с итоговой частью.

Проблема в том, что я не буду знать, что и сколько существует разных номеров регистров, или что или сколько существует типов тендеров (поэтому явное перечисление сводок в xslt со строками статического фильтра недопустимо), поэтому некоторые вроде бы группировка в порядке.

Еще один ключ - я застрял на XSLT 1.0…

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

Есть какие-нибудь предложения о том, как я могу волшебным образом заставить это работать?

вот пример исходного документа:

<s0:SalesCollection xmlns:s0="http://mySourceSchema">
  <s0:Sale transactionnumber="1" register="1">
    <s0:Tender amount="1.11" paymentmethod="visa" />
    <s0:Tender amount="2.22" paymentmethod="mastercard" />
  </s0:Sale>
  <s0:Sale transactionnumber="2" register="1">
    <s0:Tender amount="5.55" paymentmethod="discover" />
    <s0:Tender amount="4.44" paymentmethod="visa" />
  </s0:Sale>
  <s0:Sale transactionnumber="1" register="2">
    <s0:Tender amount="9.99" paymentmethod="amex" />
    <s0:Tender amount="8.88" paymentmethod="visa" />
  </s0:Sale>
</s0:SalesCollection>

вот что я собираюсь сделать (опять же, у меня уже работают записи record [@ type = 'detail']):

<ns0:root xmlns:ns0="http://myDestinationSchema">
  <ns0:record type="detail" transactionnumber="1" register="1" amount="1.11" paymentmethod="visa" />
  <ns0:record type="detail" transactionnumber="1" register="1" amount="2.22" paymentmethod="mastercard" />
  <ns0:record type="detail" transactionnumber="2" register="1" amount="5.55" paymentmethod="discover" />
  <ns0:record type="detail" transactionnumber="2" register="1" amount="4.44" paymentmethod="visa" />
  <ns0:record type="detail" transactionnumber="1" register="2" amount="9.99" paymentmethod="amex" />
  <ns0:record type="detail" transactionnumber="1" register="2" amount="8.88" paymentmethod="visa" />
  <ns0:record type="summary" register="1" amount="5.55" paymentmethod="visa" />
  <ns0:record type="summary" register="1" amount="2.22" paymentmethod="mastercard" />
  <ns0:record type="summary" register="1" amount="5.55" paymentmethod="discover" />
  <ns0:record type="summary" register="2" amount="9.99" paymentmethod="amex" />
  <ns0:record type="summary" register="2" amount="8.88" paymentmethod="visa" />
</ns0:root>

Итак, как мне приступить к созданию итоговых записей, сгруппированных по регистрам и способам оплаты, с помощью xslt 1.0?


person user2051706    schedule 24.04.2013    source источник


Ответы (2)


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

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

 <xsl:key name="kTendByTypeAndReg" match="s0:Tender"
  use="concat(../@register, '#', @paymentmethod)"/>

 <xsl:template match="/*">
  <ns0:root xmlns:ns0="http://myDestinationSchema">
   <xsl:apply-templates select="*/*"/>
   <xsl:apply-templates mode="group" select=
   "*/*[generate-id()
       =generate-id(key('kTendByTypeAndReg',
                        concat(../@register, '#', @paymentmethod))[1]
                        )
       ]"/>
  </ns0:root>
 </xsl:template>

 <xsl:template match="s0:Tender">
   <ns0:record type="detail" transactionnumber="{../@transactionnumber}"
       register="{../@register}" amount="{@amount}" paymentmethod="{@paymentmethod}" />
 </xsl:template>

 <xsl:template match="*" mode="group">
    <ns0:record type="summary" register="{../@register}" paymentmethod="{@paymentmethod}"
  amount="{sum(key('kTendByTypeAndReg',concat(../@register,'#',@paymentmethod))
                   /@amount)}"/>
 </xsl:template>
</xsl:stylesheet>

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

<s0:SalesCollection xmlns:s0="http://mySourceSchema">
  <s0:Sale transactionnumber="1" register="1">
    <s0:Tender amount="1.11" paymentmethod="visa" />
    <s0:Tender amount="2.22" paymentmethod="mastercard" />
  </s0:Sale>
  <s0:Sale transactionnumber="2" register="1">
    <s0:Tender amount="5.55" paymentmethod="discover" />
    <s0:Tender amount="4.44" paymentmethod="visa" />
  </s0:Sale>
  <s0:Sale transactionnumber="1" register="2">
    <s0:Tender amount="9.99" paymentmethod="amex" />
    <s0:Tender amount="8.88" paymentmethod="visa" />
  </s0:Sale>
</s0:SalesCollection>

дает желаемый результат:

<ns0:root xmlns:ns0="http://myDestinationSchema">
    <ns0:record type="detail" transactionnumber="1" register="1" amount="1.11" paymentmethod="visa"/>
    <ns0:record type="detail" transactionnumber="1" register="1" amount="2.22" paymentmethod="mastercard"/>
    <ns0:record type="detail" transactionnumber="2" register="1" amount="5.55" paymentmethod="discover"/>
    <ns0:record type="detail" transactionnumber="2" register="1" amount="4.44" paymentmethod="visa"/>
    <ns0:record type="detail" transactionnumber="1" register="2" amount="9.99" paymentmethod="amex"/>
    <ns0:record type="detail" transactionnumber="1" register="2" amount="8.88" paymentmethod="visa"/>
    <ns0:record type="summary" register="1" paymentmethod="visa" amount="5.55"/>
    <ns0:record type="summary" register="1" paymentmethod="mastercard" amount="2.22"/>
    <ns0:record type="summary" register="1" paymentmethod="discover" amount="5.55"/>
    <ns0:record type="summary" register="2" paymentmethod="amex" amount="9.99"/>
    <ns0:record type="summary" register="2" paymentmethod="visa" amount="8.88"/>
</ns0:root>

Объяснение:

Правильное использование:

  1. метод группировки Мюнхена.

  2. AVT s (шаблоны значений атрибутов).

person Dimitre Novatchev    schedule 24.04.2013
comment
Использование составного ключа группировки очень полезно! - person J. Polfer; 17.09.2013

Когда этот XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ns0="http://myDestinationSchema"
  xmlns:s0="http://mySourceSchema"
  exclude-result-prefixes="s0"
  version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key
    name="kTenderByRegisterAndMethod"
    match="s0:Tender"
    use="concat(parent::*/@register, '+', @paymentmethod)"/>

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

  <xsl:template match="/*">
    <ns0:root>
      <xsl:apply-templates select="*/s0:Tender"/>
      <xsl:apply-templates 
        select="*/s0:Tender[generate-id() = 
                            generate-id(key(
                              'kTenderByRegisterAndMethod',
                              concat(parent::*/@register,
                                     '+',
                                     @paymentmethod))[1])]"
        mode="summary"/>
    </ns0:root>
  </xsl:template>

  <xsl:template match="s0:Tender">
    <ns0:record type="detail">
      <xsl:apply-templates select="parent::*/@*|@*"/>
    </ns0:record>
  </xsl:template>

  <xsl:template match="s0:Tender" mode="summary">
    <ns0:record type="summary" register="{parent::*/@register}">
      <xsl:attribute name="amount">
        <xsl:value-of
          select="sum(
                    key('kTenderByRegisterAndMethod',
                        concat(parent::*/@register,
                        '+', @paymentmethod))/@amount)"/>
      </xsl:attribute>
      <xsl:apply-templates select="@*[not(name() = 'amount')]"/>
    </ns0:record>
  </xsl:template>
</xsl:stylesheet>

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

<s0:SalesCollection xmlns:s0="http://mySourceSchema">
  <s0:Sale transactionnumber="1" register="1">
    <s0:Tender amount="1.11" paymentmethod="visa"/>
    <s0:Tender amount="2.22" paymentmethod="mastercard"/>
  </s0:Sale>
  <s0:Sale transactionnumber="2" register="1">
    <s0:Tender amount="5.55" paymentmethod="discover"/>
    <s0:Tender amount="4.44" paymentmethod="visa"/>
  </s0:Sale>
  <s0:Sale transactionnumber="1" register="2">
    <s0:Tender amount="9.99" paymentmethod="amex"/>
    <s0:Tender amount="8.88" paymentmethod="visa"/>
  </s0:Sale>
</s0:SalesCollection>

... желаемый результат получен:

<ns0:root xmlns:ns0="http://myDestinationSchema">
  <ns0:record type="detail" transactionnumber="1" register="1" amount="1.11" paymentmethod="visa"/>
  <ns0:record type="detail" transactionnumber="1" register="1" amount="2.22" paymentmethod="mastercard"/>
  <ns0:record type="detail" transactionnumber="2" register="1" amount="5.55" paymentmethod="discover"/>
  <ns0:record type="detail" transactionnumber="2" register="1" amount="4.44" paymentmethod="visa"/>
  <ns0:record type="detail" transactionnumber="1" register="2" amount="9.99" paymentmethod="amex"/>
  <ns0:record type="detail" transactionnumber="1" register="2" amount="8.88" paymentmethod="visa"/>
  <ns0:record type="summary" register="1" amount="5.55" paymentmethod="visa"/>
  <ns0:record type="summary" register="1" amount="2.22" paymentmethod="mastercard"/>
  <ns0:record type="summary" register="1" amount="5.55" paymentmethod="discover"/>
  <ns0:record type="summary" register="2" amount="9.99" paymentmethod="amex"/>
  <ns0:record type="summary" register="2" amount="8.88" paymentmethod="visa"/>
</ns0:root>

Объяснение

Вы были на правильном пути, изучая Мюнчианскую группировку. Обратите внимание на составной ключ, который я использовал, который соответствует s0:Tender элементам, объединяя их родительское значение @register, знак «+» (присутствует для удобства и гарантирует, что объединение никогда не искажается) и их значение @paymentmethod.

Придерживайтесь мюнхенской группировки, даже если это не самая легкая концепция для понимания с места в карьер. Я сам узнал, просмотрев вопросы, связанные с Muenchian Grouping, по SO и попытавшись ответить их; со временем это стало для меня проясняться.

person ABach    schedule 24.04.2013