XSLT Группировка с добавлением / комбинацией подэлементов
У меня есть следующий XML
<InvestmentAccount Id="Element01_Source3_Sequqence002" Type="Standard" InvestmentStrategyId="Employer" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="4754.82" />
<Investment FundName="Fund034" FundValue="4643.48" />
<Investment FundName="Fund035" FundValue="2509.46" />
<Investment FundName="Fund038" FundValue="7104.71" />
<Investment FundName="Fund042" FundValue="4244.08" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source4_Sequence003" Type="DWPRebate" InvestmentStrategyId="DSS" ParameterOverrideIds="DWPAllocationRateOverride">
<Investment FundName="Fund032" FundValue="1881.76" />
<Investment FundName="Fund034" FundValue="1584.18" />
<Investment FundName="Fund035" FundValue="872.99" />
<Investment FundName="Fund038" FundValue="2899.53" />
<Investment FundName="Fund042" FundValue="1762.62" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source2_Sequence001" Type="Standard" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="7395.91" />
<Investment FundName="Fund034" FundValue="7222.72" />
<Investment FundName="Fund035" FundValue="3903.52" />
<Investment FundName="Fund038" FundValue="11051.32" />
<Investment FundName="Fund042" FundValue="6602.54" />
</InvestmentAccount>
<InvestmentAccount Id="Element02_Source2_Sequence004" Type="TransferNonPR" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="1439.29" />
<Investment FundName="Fund034" FundValue="1614.31" />
<Investment FundName="Fund035" FundValue="863.68" />
<Investment FundName="Fund038" FundValue="2153.80" />
<Investment FundName="Fund042" FundValue="1306.45" />
</InvestmentAccount>
<InvestmentAccount Id="Element03_Source2_Sequence005" Type="TransferNonPR" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="9617.42" />
<Investment FundName="Fund034" FundValue="10787.03" />
<Investment FundName="Fund035" FundValue="5771.18" />
<Investment FundName="Fund038" FundValue="14391.20" />
<Investment FundName="Fund042" FundValue="8729.81" />
<Investment FundName="fictiousextra" FundValue="1414" />
</InvestmentAccount>
Я хотел бы сделать так, чтобы InvestmentStrategyId AND Type были такими же, как и в случае с последними двумя выше (порядок для ясности), где FundName совпадает, и мне нужно суммировать значения фонда. В этом случае они одинаковы с каждой стороны, но могут быть некоторые дополнительные или меньшие с каждой стороны.
Таким образом, в результате мне нужен доступ к FundName и либо FundValue, либо я могу суммировать или уже суммированное значение.
Помогите!
Правильно, так что это выход, который я пытаюсь достичь.
<InvestmentAccount Id="Element01_Source3_Sequence002" Type="Standard" InvestmentStrategyId="Employer" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="4754.82" />
<Investment FundName="Fund034" FundValue="4643.48" />
<Investment FundName="Fund035" FundValue="2509.46" />
<Investment FundName="Fund038" FundValue="7104.71" />
<Investment FundName="Fund042" FundValue="4244.08" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source4_Sequence003" Type="DWPRebate" InvestmentStrategyId="DSS" ParameterOverrideIds="DWPAllocationRateOverride">
<Investment FundName="Fund032" FundValue="1881.76" />
<Investment FundName="Fund034" FundValue="1584.18" />
<Investment FundName="Fund035" FundValue="872.99" />
<Investment FundName="Fund038" FundValue="2899.53" />
<Investment FundName="Fund042" FundValue="1762.62" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source2_Sequence001" Type="Standard" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="7395.91" />
<Investment FundName="Fund034" FundValue="7222.72" />
<Investment FundName="Fund035" FundValue="3903.52" />
<Investment FundName="Fund038" FundValue="11051.32" />
<Investment FundName="Fund042" FundValue="6602.54" />
</InvestmentAccount>
<!-- THIS ONE IS THE SUMMED COMBINTION DUE TO InvestmentStrategyId and Type being multiply occuring -->
<InvestmentAccount ...>
<Investment FundName="Fund032" FundValue="11056.71" />
<Investment FundName="Fund034" FundValue="12401.34" />
<Investment FundName="Fund035" FundValue="6634.86" />
<Investment FundName="Fund038" FundValue="16545" />
<Investment FundName="Fund042" FundValue="10036.26" />
<Investment FundName="fictiousextra" FundValue="1414" />
</InvestmentAccount>
Включая любые FundNames, которые присутствуют в 1, а не в другом.
Я должен добавить, что я использую.net 4.0
2 ответа
XSLT 1.0 будет использовать Muenchian Grouping.
Я думаю, что в этом случае вы группируете дважды. Сначала вы группируете по элементам InvestmentAccount, поэтому вам понадобится ключ
<xsl:key name="Accounts" match="InvestmentAccount"
use="concat(@Type, '|', @InvestmentStrategyId)" />
И затем, вам также нужно сгруппировать по элементам инвестиций в учетной записи.
<xsl:key name="Investments" match="Investment"
use="concat(../@Type, '|', ../@InvestmentStrategyId, '|', @FundName)" />
Обратите внимание на использование трубы в конкатенации. Это может быть любой символ, но он не должен быть представлен ни в одном из атрибутов.
Чтобы сгруппировать элементы InvestmentAccount, вы можете просто сопоставить первый элемент в каждой группе, как показано ниже:
<xsl:apply-templates
select="InvestmentAccount[
generate-id() =
generate-id(key('Accounts', concat(@Type, '|', @InvestmentStrategyId))[1])]" />
И, попав в группу, вы можете получить все инвестиционные элементы, например, так:
<xsl:apply-templates
select="//InvestmentAccount
[@Type=current()/@Type]
[@InvestmentStrategyId = current()/@InvestmentStrategyId]/Investment
[generate-id() =
generate-id(key('Investments',
concat(../@Type, '|', ../@InvestmentStrategyId, '|', @FundName))[1])]" />
Вот полный XSLT (обратите внимание, что я принял корневой элемент под названием Инвестиции
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Accounts" match="InvestmentAccount" use="concat(@Type, '|', @InvestmentStrategyId)" />
<xsl:key name="Investments" match="Investment" use="concat(../@Type, '|', ../@InvestmentStrategyId, '|', @FundName)" />
<xsl:template match="/Investments">
<xsl:apply-templates select="InvestmentAccount[generate-id() = generate-id(key('Accounts', concat(@Type, '|', @InvestmentStrategyId))[1])]" />
</xsl:template>
<xsl:template match="InvestmentAccount">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="//InvestmentAccount[@Type=current()/@Type][@InvestmentStrategyId = current()/@InvestmentStrategyId]/Investment[generate-id() = generate-id(key('Investments', concat(../@Type, '|', ../@InvestmentStrategyId, '|', @FundName))[1])]" />
</xsl:copy>
</xsl:template>
<xsl:template match="Investment">
<xsl:copy>
<xsl:copy-of select="@FundName" />
<xsl:attribute name="FundValue"><xsl:value-of select="format-number(sum(key('Investments', concat(../@Type, '|', ../@InvestmentStrategyId, '|', @FundName))/@FundValue), '0.00')" /></xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
При применении к вашему образцу XML (с корневым элементом Investments) выводится следующее:
<InvestmentAccount Id="Element01_Source3_Sequqence002" Type="Standard" InvestmentStrategyId="Employer" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="4754.82" />
<Investment FundName="Fund034" FundValue="4643.48" />
<Investment FundName="Fund035" FundValue="2509.46" />
<Investment FundName="Fund038" FundValue="7104.71" />
<Investment FundName="Fund042" FundValue="4244.08" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source4_Sequence003" Type="DWPRebate" InvestmentStrategyId="DSS" ParameterOverrideIds="DWPAllocationRateOverride">
<Investment FundName="Fund032" FundValue="1881.76" />
<Investment FundName="Fund034" FundValue="1584.18" />
<Investment FundName="Fund035" FundValue="872.99" />
<Investment FundName="Fund038" FundValue="2899.53" />
<Investment FundName="Fund042" FundValue="1762.62" />
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source2_Sequence001" Type="Standard" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="7395.91" />
<Investment FundName="Fund034" FundValue="7222.72" />
<Investment FundName="Fund035" FundValue="3903.52" />
<Investment FundName="Fund038" FundValue="11051.32" />
<Investment FundName="Fund042" FundValue="6602.54" />
</InvestmentAccount>
<InvestmentAccount Id="Element02_Source2_Sequence004" Type="TransferNonPR" InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="11056.71" />
<Investment FundName="Fund034" FundValue="12401.34" />
<Investment FundName="Fund035" FundValue="6634.86" />
<Investment FundName="Fund038" FundValue="16545.00" />
<Investment FundName="Fund042" FundValue="10036.26" />
<Investment FundName="fictiousextra" FundValue="1414.00" />
</InvestmentAccount>
Я не был уверен, как вам нужны атрибуты для сгруппированного элемента InvestmentAccount, но, надеюсь, вы можете изменить это самостоятельно.
Решение XSLT 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="InvestmentAccount[1]">
<xsl:for-each-group select="self::*|following-sibling::InvestmentAccount" group-by="concat(@InvestmentStrategyId,@Type)" >
<InvestmentAccount Id="{@Id}" Type="{@Type}" InvestmentStrategyId="{@InvestmentStrategyId}" ParameterOverrideIds="{@ParameterOverrideIds}">
<xsl:for-each-group select="current-group()/Investment" group-by="@FundName">
<Investment FundName="{current-grouping-key()}" FundValue="{sum(for $x in current-group()/@FundValue return xs:double(data($x)))}" />
</xsl:for-each-group>
</InvestmentAccount>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="InvestmentAccount"/>
</xsl:stylesheet>
Я вставляю ваш XML в корень под названием <test></test>
и результат XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<InvestmentAccount Id="Element01_Source3_Sequence002" Type="Standard"
InvestmentStrategyId="Employer" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="4754.82"/>
<Investment FundName="Fund034" FundValue="4643.48"/>
<Investment FundName="Fund035" FundValue="2509.46"/>
<Investment FundName="Fund038" FundValue="7104.71"/>
<Investment FundName="Fund042" FundValue="4244.08"/>
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source4_Sequence003" Type="DWPRebate"
InvestmentStrategyId="DSS" ParameterOverrideIds="DWPAllocationRateOverride">
<Investment FundName="Fund032" FundValue="1881.76"/>
<Investment FundName="Fund034" FundValue="1584.18"/>
<Investment FundName="Fund035" FundValue="872.99"/>
<Investment FundName="Fund038" FundValue="2899.53"/>
<Investment FundName="Fund042" FundValue="1762.62"/>
</InvestmentAccount>
<InvestmentAccount Id="Element01_Source2_Sequence001" Type="Standard"
InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="7395.91"/>
<Investment FundName="Fund034" FundValue="7222.72"/>
<Investment FundName="Fund035" FundValue="3903.52"/>
<Investment FundName="Fund038" FundValue="11051.32"/>
<Investment FundName="Fund042" FundValue="6602.54"/>
</InvestmentAccount>
<InvestmentAccount Id="Element02_Source2_Sequence004" Type="TransferNonPR"
InvestmentStrategyId="Employee" ParameterOverrideIds="AllocationRateOverride">
<Investment FundName="Fund032" FundValue="11056.71"/>
<Investment FundName="Fund034" FundValue="12401.34"/>
<Investment FundName="Fund035" FundValue="6634.860000000001"/>
<Investment FundName="Fund038" FundValue="16545"/>
<Investment FundName="Fund042" FundValue="10036.26"/>
<Investment FundName="fictiousextra" FundValue="1414"/>
</InvestmentAccount>
</test>
Примечание: значение атрибутов InvestmentAccount - это один из первых элементов InvestmentAccount в группе InvestmentAccount, который имеет одинаковые значения для Type и InvestmentStrategyId. Это можно легко изменить.