如何用XSLT匹配同@BEGIN-@END异@TEXT的TOKEN节点并添加标记
解决XML中同BEGIN/END但TEXT不同的TOKEN节点添加MULTIPLE节点问题
我来帮你搞定这个XSLT的问题!你的需求是给那些共享相同@BEGIN和@END属性,但@TEXT属性不全一致的<TOKEN>节点都加上<MULTIPLE TYPE='YES'>子节点,对吧?之前用key没成功,大概率是判断逻辑或者key的使用方式没到位,我给你一套完整的解决方案:
完整XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义key:按@BEGIN和@END的组合分组,用|分隔避免属性值拼接冲突 --> <xsl:key name="tokenByBeginEnd" match="TOKEN" use="concat(@BEGIN, '|', @END)"/> <!-- 默认模板:复制所有节点和属性,保证原有结构不受破坏 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 专门处理TOKEN节点的模板 --> <xsl:template match="TOKEN"> <xsl:copy> <!-- 先复制原TOKEN的所有属性 --> <xsl:apply-templates select="@*"/> <!-- 判断当前组内是否存在不同的@TEXT值 --> <xsl:if test="count(distinct-values(key('tokenByBeginEnd', concat(@BEGIN, '|', @END))/@TEXT)) > 1"> <MULTIPLE TYPE='YES'/> </xsl:if> <!-- 复制原TOKEN的子节点(如果有的话) --> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码逻辑解释
- Key的定义:用
concat(@BEGIN, '|', @END)作为分组标识,这样能避免比如BEGIN="1" END="23"和BEGIN="12" END="3"被误判为同一组的情况,确保分组精准。 - 默认模板:负责原样复制XML中所有不需要特殊处理的节点和属性,保证原有文档结构完整。
- TOKEN处理逻辑:
- 先复制当前
<TOKEN>节点本身及其所有属性; - 通过
key()获取和当前TOKEN同@BEGIN+@END的所有节点,用distinct-values()提取组内所有不同的@TEXT值,只要数量大于1,就说明组内存在TEXT不一致的情况,此时添加<MULTIPLE TYPE='YES'>节点; - 最后复制原TOKEN的子节点(如果有)。
- 先复制当前
输入输出示例
输入XML
<ROOT> <TOKEN BEGIN="1" END="5" TEXT="apple"/> <TOKEN BEGIN="1" END="5" TEXT="apple"/> <TOKEN BEGIN="1" END="5" TEXT="orange"/> <TOKEN BEGIN="6" END="10" TEXT="banana"/> <TOKEN BEGIN="6" END="10" TEXT="grape"/> <TOKEN BEGIN="11" END="15" TEXT="pear"/> </ROOT>
输出XML
<ROOT> <TOKEN BEGIN="1" END="5" TEXT="apple"> <MULTIPLE TYPE='YES'/> </TOKEN> <TOKEN BEGIN="1" END="5" TEXT="apple"> <MULTIPLE TYPE='YES'/> </TOKEN> <TOKEN BEGIN="1" END="5" TEXT="orange"> <MULTIPLE TYPE='YES'/> </TOKEN> <TOKEN BEGIN="6" END="10" TEXT="banana"> <MULTIPLE TYPE='YES'/> </TOKEN> <TOKEN BEGIN="6" END="10" TEXT="grape"> <MULTIPLE TYPE='YES'/> </TOKEN> <TOKEN BEGIN="11" END="15" TEXT="pear"/> </ROOT>
你看,这样就完美实现了你的需求:同BEGIN/END且TEXT不全相同的TOKEN都加上了MULTIPLE节点,而只有单个或全同TEXT的节点则保持原样。
内容的提问来源于stack exchange,提问作者wild card
相关产品推荐
相关产品推荐

