使用XSLT合并InterfaceHeader并按仓库排序XML节点
解决XML多节点合并与分组排序的XSLT实现
你有一段包含多个<InterfaceHeader>节点的XML,每个节点下的<Warehouse>分为WH1和WH2,且每个仓库对应固定的<LicenseNumber>与<GoodsOwnerId>。需要实现以下需求:
- 将所有
<InterfaceHeader>合并为单个节点 - 按WH1在前、WH2在后的顺序排列仓库,同时把同仓库、同许可、同货主的
<Item>合并到同一个<Warehouse>节点下
之前尝试的XSLT仅输出XML声明,无有效内容,下面是可行的实现方案:
输入XML示例
<Root> <InterfaceHeader> <Warehouse>WH2</Warehouse> <LicenseNumber>L2</LicenseNumber> <GoodsOwnerId>GO2</GoodsOwnerId> <Item> <ItemCode>ItemB1</ItemCode> <Qty>10</Qty> </Item> </InterfaceHeader> <InterfaceHeader> <Warehouse>WH1</Warehouse> <LicenseNumber>L1</LicenseNumber> <GoodsOwnerId>GO1</GoodsOwnerId> <Item> <ItemCode>ItemA1</ItemCode> <Qty>5</Qty> </Item> </InterfaceHeader> <InterfaceHeader> <Warehouse>WH1</Warehouse> <LicenseNumber>L1</LicenseNumber> <GoodsOwnerId>GO1</GoodsOwnerId> <Item> <ItemCode>ItemA2</ItemCode> <Qty>8</Qty> </Item> </InterfaceHeader> <InterfaceHeader> <Warehouse>WH2</Warehouse> <LicenseNumber>L2</LicenseNumber> <GoodsOwnerId>GO2</GoodsOwnerId> <Item> <ItemCode>ItemB2</ItemCode> <Qty>15</Qty> </Item> </InterfaceHeader> </Root>
实现XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义分组键:Warehouse + LicenseNumber + GoodsOwnerId,确保同属性节点归为一组 --> <xsl:key name="warehouse-group" match="InterfaceHeader" use="concat(Warehouse, '|', LicenseNumber, '|', GoodsOwnerId)"/> <xsl:template match="/Root"> <!-- 生成单个合并后的InterfaceHeader节点 --> <InterfaceHeader> <!-- 筛选每个分组的首个节点,避免重复处理 --> <xsl:for-each select="InterfaceHeader[generate-id() = generate-id(key('warehouse-group', concat(Warehouse, '|', LicenseNumber, '|', GoodsOwnerId))[1])]"> <!-- 按仓库名称排序,确保WH1优先 --> <xsl:sort select="Warehouse" order="ascending" case-order="upper-first"/> <!-- 输出仓库、许可、货主的固定信息 --> <Warehouse><xsl:value-of select="Warehouse"/></Warehouse> <LicenseNumber><xsl:value-of select="LicenseNumber"/></LicenseNumber> <GoodsOwnerId><xsl:value-of select="GoodsOwnerId"/></GoodsOwnerId> <!-- 遍历当前分组下的所有Item,合并到当前节点 --> <xsl:for-each select="key('warehouse-group', concat(Warehouse, '|', LicenseNumber, '|', GoodsOwnerId))/Item"> <xsl:copy-of select="."/> </xsl:for-each> </xsl:for-each> </InterfaceHeader> </xsl:template> </xsl:stylesheet>
关键逻辑说明
- Muenchian分组:通过
key定义唯一分组键,将属性完全相同的<InterfaceHeader>归为一组,避免重复输出仓库信息 - 排序控制:用
<xsl:sort>按仓库名称升序排列,保证WH1始终排在WH2之前 - 节点合并:遍历每个分组的首个节点输出基础信息,再批量复制分组内所有
<Item>到当前节点下,完成合并 - 根节点处理:直接匹配根节点
<Root>,生成单个<InterfaceHeader>作为最终输出容器
输出XML示例
<InterfaceHeader> <Warehouse>WH1</Warehouse> <LicenseNumber>L1</LicenseNumber> <GoodsOwnerId>GO1</GoodsOwnerId> <Item> <ItemCode>ItemA1</ItemCode> <Qty>5</Qty> </Item> <Item> <ItemCode>ItemA2</ItemCode> <Qty>8</Qty> </Item> <Warehouse>WH2</Warehouse> <LicenseNumber>L2</LicenseNumber> <GoodsOwnerId>GO2</GoodsOwnerId> <Item> <ItemCode>ItemB1</ItemCode> <Qty>10</Qty> </Item> <Item> <ItemCode>ItemB2</ItemCode> <Qty>15</Qty> </Item> </InterfaceHeader>
内容的提问来源于stack exchange,提问作者Jesper Hansen
相关产品推荐
相关产品推荐

