XSLT v1.0 - Как сгруппировать неровные атрибуты?
Я пытаюсь реализовать группировку, используя xslt для элементов xml для атрибутов, которые на самом деле не имеют общего значения, и я не уверен, следует ли мне использовать группировку muenchian или нет, хотя я уже сгруппировал свои элементы с помощью этого метода в своем коде. Я также искал в форуме, но без удачи, так как большинство группировок, кажется, происходит по атрибутам с общими значениями.
Более конкретно, что я пытаюсь добиться, это напечатать в формате 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>
Хотя в прошлом я реализовал эту логику для элементов, которые на самом деле имеют общее значение атрибута в моей существующей группировке, приведенный выше код не дает мне вообще никаких строк для моей желаемой агрегации, и мне интересно, если что-то не так с моими условиями ИЛИ и для по какой-то причине это становится ложным.
Я что-то пропустил? Любая помощь приветствуется,
Спасибо
Редактировать: Как указывает Томалак в моем случае, я пытаюсь реализовать ручные группы, то есть действительно жестко закодированные условия внутри кода. Для меня сейчас нет общего способа рассчитать эти значения.
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
]
" />
Разделение его на несколько переменных облегчает отслеживание.