如何通过XSLT基于节点ID合并XML节点,生成正确item嵌套结构?
解决XML中按ID匹配嵌套orderList节点的XSLT方案
先给出符合需求的示例输入XML结构:
<root> <customers> <customer id="1"> <name>Alice</name> <position></position> </customer> <customer id="2"> <name>Bob</name> <position></position> </customer> </customers> <orderList> <order id="1"> <position> <price>100</price> <currency>USD</currency> </position> <position> <price>200</price> <currency>EUR</currency> </position> </order> <order id="2"> <position> <price>150</price> <currency>GBP</currency> </position> </order> </orderList> </root>
下面是实现需求的XSLT代码(基于XSLT 1.0,兼容性覆盖绝大多数XML处理器):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 按order的id建立position节点的索引,用于快速匹配 --> <xsl:key name="order-positions" match="orderList/order/position" use="../@id"/> <!-- 通用模板:原样复制所有未特殊处理的节点,保留原有XML结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理customer下的position节点,插入对应id的order position作为独立item --> <xsl:template match="customer/position"> <xsl:copy> <!-- 通过key快速获取当前customer对应id的所有order position --> <xsl:apply-templates select="key('order-positions', ../@id)"> <xsl:with-param name="wrap-tag" select="'item'"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <!-- 将每个position节点包装为指定的item标签 --> <xsl:template match="position"> <xsl:param name="wrap-tag"/> <xsl:element name="{$wrap-tag}"> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> </xsl:stylesheet>
代码逻辑说明
- 索引定义:用
<xsl:key>建立order的id与下属position节点的映射,比直接路径查询更高效,适合处理大体积XML。 - 通用模板:保证除了需要修改的部分,XML中所有节点(属性、文本、其他元素)都原样复制,避免丢失原有内容。
- customer节点处理:匹配每个customer下的position节点,插入对应id的所有order position,且每个position都被包装为独立的
<item>节点。 - 标签包装:通过参数传递包装标签名,后续若需修改标签名称,只需调整参数值即可,提升模板灵活性。
输出结果示例
处理后每个customer的position下会生成独立的item节点,每个item对应一个order里的position:
<root> <customers> <customer id="1"> <name>Alice</name> <position> <item> <price>100</price> <currency>USD</currency> </item> <item> <price>200</price> <currency>EUR</currency> </item> </position> </customer> <customer id="2"> <name>Bob</name> <position> <item> <price>150</price> <currency>GBP</currency> </item> </position> </customer> </customers> <orderList> <order id="1"> <position> <price>100</price> <currency>USD</currency> </position> <position> <price>200</price> <currency>EUR</currency> </position> </order> <order id="2"> <position> <price>150</price> <currency>GBP</currency> </position> </order> </orderList> </root>
可选优化
如果不需要保留原有的orderList节点,只需添加以下模板让它不输出:
<xsl:template match="orderList"/>
内容的提问来源于stack exchange,提问作者Eminen
相关产品推荐
相关产品推荐

