可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
For each "agency" node I need to find the "stmt" elements that have the same key1, key2, key3 values and output just one "stmt" node with the "comm" and "prem" values summed together. For any "stmt" elements within that "agency" that don't match any other "stmt" elements based on key1, key2 and key3 I need to output them as is. So after transformation the first "agency" node would only have two "stmt" nodes (one summed) and the second "agency" node would be passed as is because the keys don't match. XSLT 1.0 or 2.0 solutions are ok...though my stylesheet is currently 1.0. Note that the agency nodes could have any number of "stmt" elements that have matching keys which need to be grouped and summed and any number that don't.
<statement> <agency> <stmt> <key1>1234</key1> <key2>ABC</key2> <key3>15.000</key3> <comm>75.00</comm> <prem>100.00</prem> </stmt> <stmt> <key1>1234</key1> <key2>ABC</key2> <key3>15.000</key3> <comm>25.00</comm> <prem>200.00</prem> </stmt> <stmt> <key1>1234</key1> <key2>ABC</key2> <key3>17.50</key3> <comm>25.00</comm> <prem>100.00</prem> </stmt> </agency> <agency> <stmt> <key1>5678</key1> <key2>DEF</key2> <key3>15.000</key3> <comm>10.00</comm> <prem>20.00</prem> </stmt> <stmt> <key1>5678</key1> <key2>DEF</key2> <key3>17.000</key3> <comm>15.00</comm> <prem>12.00</prem> </stmt> </agency>
回答1:
And an XSLT 2.0 solution:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="agency"> <agency> <xsl:for-each-group select="stmt" group-by= "concat(key1, '+', key2, '+', key3)"> <stmt> <xsl:copy-of select= "current-group()[1]/*[starts-with(name(),'key')]"/> <comm> <xsl:value-of select="sum(current-group()/comm)"/> </comm> <prem> <xsl:value-of select="sum(current-group()/prem)"/> </prem> </stmt> </xsl:for-each-group> </agency> </xsl:template> </xsl:stylesheet>
回答2:
In XSLT 1.0 use the Muenchian method for grouping (with compound key).
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:key name="kStmtByKeys" match="stmt" use="concat(generate-id(..), key1, '+', key2, '+', key3)"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="agency"> <agency> <xsl:for-each select= "stmt[generate-id() = generate-id(key('kStmtByKeys', concat(generate-id(..), key1, '+', key2, '+', key3) )[1] ) ] "> <xsl:variable name="vkeyGroup" select= "key('kStmtByKeys', concat(generate-id(..), key1, '+', key2, '+', key3))"/> <stmt> <xsl:copy-of select="*[starts-with(name(), 'key')]"/> <comm> <xsl:value-of select="sum($vkeyGroup/comm)"/> </comm> <prem> <xsl:value-of select="sum($vkeyGroup/prem)"/> </prem> </stmt> </xsl:for-each> </agency> </xsl:template> </xsl:stylesheet>
when applied on the provided XML document, produces the wanted result:
<statement> <agency> <stmt> <key1>1234</key1> <key2>ABC</key2> <key3>15.000</key3> <comm>100</comm> <prem>300</prem> </stmt> <stmt> <key1>1234</key1> <key2>ABC</key2> <key3>17.50</key3> <comm>25</comm> <prem>100</prem> </stmt> </agency> <agency> <stmt> <key1>5678</key1> <key2>DEF</key2> <key3>15.000</key3> <comm>10</comm> <prem>20</prem> </stmt> <stmt> <key1>5678</key1> <key2>DEF</key2> <key3>17.000</key3> <comm>15</comm> <prem>12</prem> </stmt> </agency> </statement>
回答3:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/|*"> <xsl:copy> <xsl:apply-templates select="*" /> </xsl:copy> </xsl:template> <xsl:template match="stmt"> <xsl:variable name="stmtGroup" select="../stmt[(key1=current()/key1) and (key2=current()/key2) and (key3=current()/key3)]" /> <xsl:if test="generate-id()=generate-id($stmtGroup[1])"> <xsl:copy> <key1> <xsl:value-of select="key1"/> </key1> <key2> <xsl:value-of select="key2"/> </key2> <key3> <xsl:value-of select="key3"/> </key3> <comm> <xsl:value-of select="format-number(sum($stmtGroup/comm), '#.00')"/> </comm> <prem> <xsl:value-of select="format-number(sum($stmtGroup/prem), '#.00')"/> </prem> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>