如何使用XSLT基于元素进行合并?附输入XML示例
Merging
userFee Elements by owner/Id with XSLT Great question! To merge your userFee elements based on the owner/Id and sum their corresponding Amount/sum values, you can leverage XSLT's grouping features. Below are solutions for both XSLT 2.0+ (the most straightforward approach) and XSLT 1.0 (for compatibility with older processors).
First, Let's Complete Your Input XML
For clarity, here's the full input we'll work with:
<Fees> <user> <value>userA</value> </user> <feeList> <userFee> <owner> <Id>owner1</Id> </owner> <Amount> <sum>100</sum> </Amount> </userFee> <userFee> <owner> <Id>owner1</Id> </owner> <Amount> <sum>100</sum> </Amount> </userFee> <userFee> <owner> <Id>owner2</Id> </owner> <Amount> <sum>50</sum> </Amount> </userFee> </feeList> </Fees>
Solution 1: XSLT 2.0+ (Using xsl:for-each-group)
This version uses native grouping syntax which is clean and easy to read:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- Identity Template: Copies all elements/attributes unless overridden --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Override processing for `feeList` to group `userFee` elements --> <xsl:template match="feeList"> <xsl:copy> <!-- Group `userFee` by the value of `owner/Id` --> <xsl:for-each-group select="userFee" group-by="owner/Id"> <userFee> <!-- Copy the `owner` element from the first item in the group (all are identical) --> <xsl:apply-templates select="current-group()[1]/owner"/> <Amount> <!-- Sum all `sum` values in the current group --> <sum><xsl:value-of select="sum(current-group()/Amount/sum)"/></sum> </Amount> </userFee> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
Output XML:
<Fees> <user> <value>userA</value> </user> <feeList> <userFee> <owner> <Id>owner1</Id> </owner> <Amount> <sum>200</sum> </Amount> </userFee> <userFee> <owner> <Id>owner2</Id> </owner> <Amount> <sum>50</sum> </Amount> </userFee> </feeList> </Fees>
Key Explanations:
- The identity template ensures all parts of the XML (like the
userelement) are copied exactly as-is unless we specify otherwise. xsl:for-each-groupgroupsuserFeeelements by theirowner/Idvalue.current-group()refers to alluserFeeelements in the current group, sosum(current-group()/Amount/sum)calculates the total for that owner.
Solution 2: XSLT 1.0 (Muenchian Grouping)
If you're restricted to XSLT 1.0, use Muenchian grouping (a standard technique for grouping in older versions):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- Define a key to group `userFee` elements by `owner/Id` --> <xsl:key name="userFeeByOwnerId" match="userFee" use="owner/Id"/> <!-- Identity Template --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Process `feeList` to select only the first `userFee` in each group --> <xsl:template match="feeList"> <xsl:copy> <xsl:apply-templates select="userFee[generate-id() = generate-id(key('userFeeByOwnerId', owner/Id)[1])]"/> </xsl:copy> </xsl:template> <!-- Process each grouped `userFee` to calculate the total sum --> <xsl:template match="userFee"> <userFee> <xsl:apply-templates select="owner"/> <Amount> <sum> <!-- Sum all `sum` elements in the group defined by the key --> <xsl:value-of select="sum(key('userFeeByOwnerId', owner/Id)/Amount/sum)"/> </sum> </Amount> </userFee> </xsl:template> </xsl:stylesheet>
Key Explanations:
- The
xsl:keycreates an index ofuserFeeelements mapped to theirowner/Idvalues. - The condition
generate-id() = generate-id(key('userFeeByOwnerId', owner/Id)[1])selects only the firstuserFeein each group (since all elements in the same group share the same generated ID for their first element). key('userFeeByOwnerId', owner/Id)retrieves alluserFeeelements for the current owner, allowing us to sum theirsumvalues.
内容的提问来源于stack exchange,提问作者Maverick Riz
相关产品推荐
相关产品推荐

