如何用XSLT检测不同PRODUCT节点的ITEMS属性对并添加MULTIPLE节点?
实现思路与具体方案
好的,我来帮你梳理下实现这个需求的具体思路,分几个核心步骤拆解,都是实际项目里常用的方法:
1. 核心思路:按范围分组
首先要解决的核心问题是跨PRODUCT节点,把所有具有相同BEGIN和END属性的ITEMS归为一组。只有先完成分组,才能判断某个范围是否被多个PRODUCT共享。
实现方式(XSLT 1.0 兼容版)
XSLT 1.0里最高效的分组方式是用<xsl:key>建立索引,把ITEMS节点按BEGIN+END的组合值作为键:
<!-- 定义索引:用BEGIN和END的拼接值作为分组键,用|分隔避免误判 --> <xsl:key name="itemsByRange" match="ITEMS" use="concat(@BEGIN, '|', @END)"/>
2. 遍历判断并添加标记
接下来在处理XML结构的过程中,对每个ITEMS节点检查其所在分组的节点数量:如果数量>1,说明这个范围被多个PRODUCT使用,就添加MULTIPLE标记节点。
完整XSLT示例(保留原XML结构)
这个示例会完整复制原XML的所有结构,只在符合条件的ITEMS节点后添加MULTIPLE标记:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 跨PRODUCT分组ITEMS的索引 --> <xsl:key name="itemsByRange" match="ITEMS" use="concat(@BEGIN, '|', @END)"/> <!-- 复制整个文档结构的基础模板 --> <xsl:template match="/"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 复制除ITEMS外的所有节点和属性 --> <xsl:template match="@*|node()[not(self::ITEMS)]"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理ITEMS节点,判断是否添加MULTIPLE标记 --> <xsl:template match="ITEMS"> <!-- 先复制原ITEMS节点 --> <xsl:copy-of select="."/> <!-- 检查当前ITEMS的分组是否有多个节点 --> <xsl:if test="count(key('itemsByRange', concat(@BEGIN, '|', @END))) > 1"> <MULTIPLE/> </xsl:if> </xsl:template> </xsl:stylesheet>
3. XSLT 2.0+ 简化方案
如果你的环境支持XSLT 2.0或更高版本,可以用for-each-group语法更直观地实现分组,代码可读性更强:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:copy> <!-- 遍历所有PRODUCT节点,保留原结构 --> <xsl:apply-templates select="PRODUCT"/> </xsl:copy> </xsl:template> <xsl:template match="PRODUCT"> <xsl:copy> <!-- 按BEGIN+END分组当前PRODUCT下的ITEMS --> <xsl:for-each-group select="ITEMS" group-by="concat(@BEGIN, '|', @END)"> <xsl:copy-of select="current-group()"/> <!-- 检查当前分组是否在全局范围内存在多个节点 --> <xsl:if test="count(//ITEMS[concat(@BEGIN, '|', @END) = current-grouping-key()]) > 1"> <MULTIPLE/> </xsl:if> </xsl:for-each-group> <!-- 复制PRODUCT下的其他节点(如果有的话) --> <xsl:apply-templates select="node()[not(self::ITEMS)]"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
注意事项
- 格式一致性:要确保
BEGIN和END的属性值格式完全一致(比如日期的YYYY-MM-DD、数字的位数),否则会因为格式差异导致分组错误。 - 标记位置调整:如果需要把
MULTIPLE标记放在PRODUCT节点下而不是ITEMS旁边,只需要调整模板的匹配逻辑,检查当前PRODUCT下是否有ITEMS属于多节点分组即可。 - 命名空间处理:如果原XML带有命名空间,记得在
xsl:key和模板匹配中添加对应的命名空间前缀。
内容的提问来源于stack exchange,提问作者wild card
相关产品推荐
相关产品推荐

