XSLT v1.0 — Как сгруппировать неодинаковые атрибуты?

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

Точнее, чего я пытаюсь добиться, так это напечатать в pdf одну строку для нескольких записей, которые имеют определенные идентификаторы для элементов Att со значением «PC» в атрибуте Ty (Att ty = «PC»). Все это должно происходить вместе с моей уже существующей группировкой.

Пример моего xml-кода:

<Document>
    <RecordDetails>
        <Record>
            <contact id="0001" title="Mr" forename="John" surname="Smith" ST='M'/>
            <AggSet>                
                <Att Ty="Addr" Id="43 Menelaou Street" />
                <Att Ty="PC"   Id="15230" />
                <Att Ty="Num"  Id="2580052635" />             
            </AggSet>
            <Charge Amount="3.000" PT="P" />
        </Record>
        <Record>
            <contact id="0001" title="Mr" forename="John" surname="Smith" ST='M'/>
            <AggSet>                
                <Att Ty="Addr" Id="65 Dankan Street" />
                <Att Ty="PC"   Id="15236" />
                <Att Ty="Num"  Id="2580052635" />             
            </AggSet>
            <Charge Amount="10.000" PT="P" />
        </Record>
        <Record>
            <contact id="0002" title="Dr" forename= "Amy" surname="Jones" ST='Y'/>
            <AggSet>                
                <Att Ty="Addr" Id="28 Karman Street" />
                <Att Ty="PC"   Id="15237" />
                <Att Ty="Num"  Id="2584552635" />             
            </AggSet>
            <Charge Amount="-2.000" PT="P" />
        </Record>
        <Record>    
            ...
        </Record>
    </RecordDetails>
</Document>

Так, например, для записей 2,3 я хотел бы напечатать только 1 строку из-за того, что их почтовые индексы относятся к одной и той же области для меня, поскольку Ty="PC" означает сообщение, и я пытаюсь сгруппировать по большей области. .

Я использую следующий xsl на Apache FOP:

<xsl:key name="ct" match="Record[Charge/@PT='P']" use="@ST"/>


<xsl:template match ="RecordDetails">
    <xsl:for-each select="Record[generate-id(.)=generate-id(key('ct',@ST)[1])]">
        <xsl:if test="@ST='M' and (./AggSet/Att[@Ty='PC']/@Id='15236' or ./AggSet/Att[@Ty='TZ']/@Id='15237' or ... )  ">
            <fo:table-row>                          
                    <xsl:apply-templates select="."/>                            
            </fo:table-row>
        </xsl:if> 
        <xsl:for-each select="key('ct',@ST)">                       
            <xsl:choose>                                    
                 <xsl:when test="@ST='M' and (./AggSet/Att[@Ty='PC']/@Id='15236' or ./AggSet/Att[@Ty='TZ']/@Id='15237' or ... )  "> 
                 </xsl:when>                     
                 <xsl:otherwise>
                  <fo:table-row>
                    <xsl:apply-templates select="."/>
                  </fo:table-row>
                 </xsl:otherwise>
            </xsl:choose>             
        </xsl:for-each>                             
    </xsl:for-each>
</xsl:template>

<xsl:template match="Record">
    <fo:table-cell>
        <xsl:choose>
            <xsl:when test="@ST='M' and (./AggSet/Att[@Ty='PC']/@Id='15236' or ./AggSet/Att[@Ty='TZ']/@Id='15237' or ... )">
                <fo:block text-align="center">
                    <xsl:text>Greater area</xsl:text>
                </fo:block>
            </xsl:when>
            <xsl:otherwise>
                <fo:block text-align="center">
                    <xsl:value-of select="./AggSet/Att[@Ty='PC']/@Id" />
                </fo:block>
            </xsl:otherwise>
        </xsl:choose>
    </fo:table-cell>
    <fo:table-cell>
        <xsl:choose>
            <xsl:when test="@ST='M' and (./AggSet/Att[@Ty='PC']/@Id='15236' or ./AggSet/Att[@Ty='TZ']/@Id='15237' or ... )">
                <fo:block text-align="center">
                    <xsl:value-of select="sum(//Record[@ST='M' and (./AggSet/Att[@Ty='PC']/@Id='15236' or ./AggSet/Att[@Ty='TZ']/@Id='15237' or ... )]/contact/Charge/@Amount)" />
                </fo:block>
            </xsl:when>
            <xsl:otherwise>
                <fo:block text-align="center">
                    <xsl:value-of select="./Charge/@Amount" />
                </fo:block>
            </xsl:otherwise>
        </xsl:choose>
    </fo:table-cell>
</xsl:template>

Хотя я реализовал эту логику в прошлом для элементов, которые фактически имеют общее значение атрибута в моей существующей группе, приведенный выше код вообще не дает мне строк для моей желаемой агрегации, и мне интересно, есть ли что-то не так с моими условиями ИЛИ и для по какой-то причине он становится ложным.

Я что-то упускаю ? Любая помощь приветствуется,

Спасибо

Редактировать: Как указывает Томалак, в моем случае я пытаюсь реализовать ручные группы, что означает действительно жестко запрограммированные условия внутри кода. Сейчас у меня нет общего способа рассчитать эти значения.


person jeevium    schedule 22.01.2014    source источник
comment
Не могли бы вы более подробно объяснить, как группировать разные почтовые индексы? Группы определяются вручную или их можно рассчитать? Должно ли это быть настраиваемым или жестко запрограммировано?   -  person Tomalak    schedule 22.01.2014
comment
Очень точный вопрос, пожалуйста, проверьте мой отредактированный ответ внизу страницы.   -  person jeevium    schedule 22.01.2014


Ответы (1)


Как насчет этого подхода:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="http://tempuri.org/config"
  exclude-result-prefixes="my"
>
  <my:config>
    <PC_group>
      <item>15236</item>
      <item>15237</item>
    </PC_group>
    <!-- more groups like this... -->
  </my:config>

  <!-- create a reference to our own config -->
  <xsl:variable name="config" select="document('')/*/my:config" />
  <xsl:variable name="PC_group" select="$config/PC_group" />

  <xsl:template match="RecordDetails">
    <grouped_RecordDetails>
      <xsl:apply-templates mode="group" select="Record[Charge/@PT='P']" />
    </grouped_RecordDetails>
  </xsl:template>

  <xsl:template match="Record" mode="group">
    <xsl:variable name="myPC" select="AggSet/Att[@Ty = 'PC']/@Id" />

    <!-- select all the PCs in this group -->
    <xsl:variable name="groupPCs" select="$PC_group[item = $myPC]/item" />

    <!-- identify all other members of this group -->
    <xsl:variable name="groupMembers" select=". | ../Record[
      Charge/@PT='P' and AggSet/Att[@Ty = 'PC']/@Id = $groupPCs
    ]" />

    <!-- do the actual grouping, just like the Muenchian method... -->
    <xsl:if test="generate-id() = generate-id($groupMembers[1])">

      <!--
        we are at the first Record in this group now
        all the other group members are at $groupMembers
        output whatever details you like here
      -->
      <xsl:copy-of select="." />

    </xsl:if>
  </xsl:template>

  <xsl:template match="text()[normalize-space() = '']" />

</xsl:stylesheet>

образец вывода

<grouped_RecordDetails>
  <Record>
    <contact id="0001" title="Mr" forename="John" surname="Smith" ST="M" />
    <AggSet>
      <Att Ty="Addr" Id="43 Menelaou Street" />
      <Att Ty="PC" Id="15230" />
      <Att Ty="Num" Id="2580052635" />
    </AggSet>
    <Charge Amount="3.000" PT="P" />
  </Record>
  <Record>
    <contact id="0001" title="Mr" forename="John" surname="Smith" ST="M" />
    <AggSet>
      <Att Ty="Addr" Id="65 Dankan Street" />
      <Att Ty="PC" Id="15236" />
      <Att Ty="Num" Id="2580052635" />
    </AggSet>
    <Charge Amount="10.000" PT="P" />
  </Record>
</grouped_RecordDetails>

Редактировать: Конечно, группировку можно выполнить в одном большом беспорядочном выражении XPath, если вы предпочитаете:

<!-- identify all members of this group -->
<xsl:variable name="groupMembers" select="
  . | ../Record[
    Charge/@PT = 'P' 
    and AggSet/Att[@Ty = 'PC']/@Id = $PC_group[
          item = current()/AggSet/Att[@Ty = 'PC']/@Id
        ]/item
  ]
" />

Однако разделение его на несколько переменных упрощает отслеживание.

person Tomalak    schedule 22.01.2014