基于CID节点对比XML Sibling节点差异并提取结果的XSLT求助
基于CID对比XML节点并提取差异的XSLT解决方案
核心思路
放弃使用accumulator,改用XSLT 3.0的xsl:key建立CID索引,快速关联两个数据源中同CID的节点,再逐个对比兄弟节点的值,只保留有差异的部分。这种方式比accumulator更适配“按ID关联+值对比”的场景。
输入示例
假设输入XML包含两个数据源:
<sources> <source1> <record> <CID>1001</CID> <Name>Alice</Name> <Age>30</Age> <City>New York</City> </record> <record> <CID>1002</CID> <Name>Bob</Name> <Age>25</Age> <City>London</City> </record> </source1> <source2> <record> <CID>1001</CID> <Name>Alice M.</Name> <Age>30</Age> <City>New York</City> </record> <record> <CID>1002</CID> <Name>Bob</Name> <Age>26</Age> <City>Paris</City> </record> <record> <CID>1003</CID> <Name>Charlie</Name> <Age>35</Age> </record> </source2> </sources>
预期输出示例
仅保留同CID下值存在差异的节点,并标注来源:
<differences> <record CID="1001"> <diff field="Name"> <source1>Alice</source1> <source2>Alice M.</source2> </diff> </record> <record CID="1002"> <diff field="Age"> <source1>25</source1> <source2>26</source2> </diff> <diff field="City"> <source1>London</source1> <source2>Paris</source2> </diff> </record> </differences>
XSLT 3.0实现代码
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 为两个数据源的record建立CID索引 --> <xsl:key name="source1-cid-index" match="source1/record" use="CID"/> <xsl:key name="source2-cid-index" match="source2/record" use="CID"/> <xsl:template match="/"> <differences> <!-- 遍历同时存在于两个数据源的CID对应的record --> <xsl:for-each select="sources/source1/record[key('source2-cid-index', CID)]"> <xsl:variable name="current-cid" select="CID"/> <xsl:variable name="src1-node" select="."/> <xsl:variable name="src2-node" select="key('source2-cid-index', $current-cid)"/> <!-- 仅当当前CID下存在差异节点时生成record --> <xsl:if test="$src1-node/*[not(self::CID)] ne $src2-node/*[not(self::CID)]"> <record CID="{$current-cid}"> <!-- 对比除CID外的所有子节点 --> <xsl:for-each select="$src1-node/*[not(self::CID)]"> <xsl:variable name="field" select="local-name()"/> <xsl:variable name="val1" select="."/> <xsl:variable name="val2" select="$src2-node/*[local-name() = $field]"/> <!-- 值不同则生成diff节点 --> <xsl:if test="$val1 ne $val2"> <diff field="{$field}"> <source1><xsl:value-of select="$val1"/></source1> <source2><xsl:value-of select="$val2"/></source2> </diff> </xsl:if> </xsl:for-each> </record> </xsl:if> </xsl:for-each> </differences> </xsl:template> </xsl:stylesheet>
代码说明
- 索引建立:用
xsl:key分别给两个数据源的record节点按CID建立索引,能快速定位同ID的节点,避免低效遍历。 - CID过滤:只处理同时出现在两个数据源中的CID,忽略单边存在的记录(比如示例中的CID1003)。
- 差异检查:遍历除CID外的所有子节点,用
ne(非相等)运算符对比值,仅生成有差异的diff节点。 - 输出优化:只有当某个CID下存在至少一个差异节点时,才生成对应的
<record>标签,减少冗余内容。
扩展说明
如果需要处理节点缺失/空值的场景(比如某个CID下source1有Age节点,source2没有),可以修改差异判断条件:
<xsl:if test="$val1 ne $val2 or not(exists($val2)) or not(exists($val1))">
内容的提问来源于stack exchange,提问作者Awanish
相关产品推荐
相关产品推荐

