如何使用XSLT 3.0累加器结合legacyID与legacyLocation实现XML值映射转换
实现方案:用XSLT 3.0累加器完成映射转换
当然可以用XSLT 3.0的累加器来实现这个需求!核心思路是先通过累加器构建legacyID+legacyLocation到AssociateID的映射表,再用这个映射给root下的每一行补充对应的关联ID。
完整XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 累加器:构建legacyID+location到AssociateID的映射 --> <xsl:accumulator name="associate-map" as="map(xs:string, xs:string)" initial-value="map{}"> <xsl:accumulator-rule match="Data/Entry" select=" let $legacy-id := legacyID/text(), $location-list := tokenize(legacyLocation/text(), ',') return fold-left($location-list, $value, function($current-map, $loc) { map:put($current-map, concat($legacy-id, '|', normalize-space($loc)), AssociateID/text()) }) "/> </xsl:accumulator> <!-- 处理根节点,生成目标结构 --> <xsl:template match="/AggregatedData"> <root> <worker> <xsl:apply-templates select="root/row"/> </worker> </root> </xsl:template> <!-- 处理每个row,补充AssociateID --> <xsl:template match="root/row"> <row> <!-- 从累加器映射中获取对应AssociateID --> <AssociateID> <xsl:value-of select="accumulator-before('associate-map')(concat(legacyID/text(), '|', legacyLocation/text()))"/> </AssociateID> <!-- 复制原row的所有字段 --> <xsl:copy-of select="*"/> </row> </xsl:template> </xsl:stylesheet>
代码说明
累加器逻辑:
- 初始值是空的
map{},用来存储键值对。 - 遍历每个
Data/Entry时,用tokenize()把逗号分隔的legacyLocation拆分成单个位置值。 - 通过
fold-left遍历拆分后的位置列表,把legacyID|清理后的location作为唯一键(用竖线分隔避免ID和位置本身包含特殊字符的冲突),将AssociateID存入映射表。
- 初始值是空的
模板处理逻辑:
- 匹配根节点后,生成你需要的
<root><worker>结构。 - 处理每个
root/row时,从累加器的映射表中根据当前行的legacyID和legacyLocation查找对应的AssociateID,插入到行的最前面,再复制原行的所有字段。
- 匹配根节点后,生成你需要的
细节处理:
- 用
normalize-space()清理拆分后位置值的前后空格(比如如果输入里有Test_Loc1, Test_Loc2这种带空格的情况,也能正确匹配)。 - 如果同一个
legacyID+location对应多个AssociateID,后面的会覆盖前面的,这符合你给出的示例场景;如果需要保留所有关联ID,可以把累加器的map类型改成map(xs:string, xs:string*),并调整map:put为map:merge来追加值。
- 用
内容的提问来源于stack exchange,提问作者Thusara Deemantha
相关产品推荐
相关产品推荐

