如何用XSL Muenchian分组实现多级别嵌套XML结构转换
Fixing XSL with Muenchian Grouping for Trailer-Output Record Association
Let's walk through how to adjust your XSL to achieve the nested structure you need—grouping first by compartment code, then by converted unit name (K → KG), all linked to the correct trailer via its ID.
First, here's a sample input XML to reference:
<root> <output> <record trailerId="T1" compartmentCode="C1" unitName="K" capacity="1000"/> <record trailerId="T1" compartmentCode="C1" unitName="K" capacity="1500"/> <record trailerId="T1" compartmentCode="C2" unitName="L" capacity="2000"/> <record trailerId="T2" compartmentCode="C1" unitName="K" capacity="800"/> </output> <trailer id="T1" type="Refrigerated"/> <trailer id="T2" type="DryVan"/> </root>
Corrected XSL with Muenchian Grouping
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Key 1: Group records by trailer ID + compartment code --> <xsl:key name="compartment-group" match="record" use="concat(@trailerId, '|', @compartmentCode)"/> <!-- Key 2: Group records by trailer ID + compartment code + converted unit name (K → KG) --> <xsl:key name="capacity-group" match="record" use="concat(@trailerId, '|', @compartmentCode, '|', translate(@unitName, 'K', 'KG'))"/> <xsl:template match="/root"> <trailers> <!-- Loop through each trailer in the input --> <xsl:for-each select="trailer"> <xsl:variable name="trailer-id" select="@id"/> <trailer id="{$trailer-id}" type="{@type}"> <configurations> <!-- Group records by compartment code for the current trailer --> <xsl:for-each select="../output/record[@trailerId = $trailer-id][count(. | key('compartment-group', concat($trailer-id, '|', @compartmentCode))[1]) = 1]"> <xsl:variable name="compartment-code" select="@compartmentCode"/> <compartment code="{$compartment-code}"> <!-- Group records by converted unit name within the current compartment --> <xsl:for-each select="key('compartment-group', concat($trailer-id, '|', $compartment-code))[count(. | key('capacity-group', concat($trailer-id, '|', $compartment-code, '|', translate(@unitName, 'K', 'KG')))[1]) = 1]"> <xsl:variable name="converted-unit" select="translate(@unitName, 'K', 'KG')"/> <capacity unit="{$converted-unit}"> <!-- Optional: Sum all capacities for this unit, or just take the first value --> <xsl:value-of select="sum(key('capacity-group', concat($trailer-id, '|', $compartment-code, '|', $converted-unit))/@capacity)"/> </capacity> </xsl:for-each> </compartment> </xsl:for-each> </configurations> </trailer> </xsl:for-each> </trailers> </xsl:template> </xsl:stylesheet>
How This Works
Let's break down the key parts:
- Muenchian Grouping Keys:
compartment-groupensures we only create one<compartment>per trailer-compartment pair. Theconcat()avoids conflicts between different trailers with the same compartment code.capacity-groupbuilds on that, adding the converted unit name (usingtranslate()to swap K for KG) so we group records by the standardized unit.
- Trailer-Record Association:
We store the current trailer's ID in a variable, then filter<record>nodes to only those matching that ID. - Nested Grouping:
- First, we loop through unique compartment groups for the trailer. The
count(. | key(...)[1]) = 1check identifies the first record in each group (the "group leader"), so we only create one<compartment>per group. - Inside each compartment, we repeat the pattern for capacity units—using the second key to group by converted unit, then creating a
<capacity>node for each unique unit.
- First, we loop through unique compartment groups for the trailer. The
- Capacity Handling:
The example usessum()to total all capacities for the same unit in a compartment. If you just need to list individual capacities instead of summing, replace thesum()call with<xsl:value-of select="@capacity"/>and adjust the loop to iterate all records in the capacity group.
Sample Output
For the input above, the output will look like this:
<trailers> <trailer id="T1" type="Refrigerated"> <configurations> <compartment code="C1"> <capacity unit="KG">2500</capacity> </compartment> <compartment code="C2"> <capacity unit="L">2000</capacity> </compartment> </configurations> </trailer> <trailer id="T2" type="DryVan"> <configurations> <compartment code="C1"> <capacity unit="KG">800</capacity> </compartment> </configurations> </trailer> </trailers>
内容的提问来源于stack exchange,提问作者user3529643
相关产品推荐
相关产品推荐

