如何用XSLT基于OBJ_ID列表筛选/移除XML节点?
基于XSLT批量处理INTERLIS XML的OBJ_ID筛选方案
问题说明
现有一份INTERLIS格式XML,DATASECTION节点下包含2-4万个不同结构的子节点,每个子节点都带有唯一的<OBJ_ID>子元素。需完成两个批量处理任务:
- a) 生成仅保留OBJ_ID在指定列表中的节点的新XML
- b) 生成移除所有OBJ_ID在指定列表中的节点的新XML
原尝试的XSLT未生效,核心需求是用简洁方式处理数百个OBJ_ID,避免重复编写匹配逻辑。
原代码问题分析
原代码失效的核心原因:
- 错误使用
@OBJ_ID匹配属性,但实际OBJ_ID是子元素,不是节点属性 - 模板匹配范围过宽(
ili:DATASECTION//node()),会匹配所有子节点包括文本节点,破坏XML结构 - 未保留原XML的顶层结构(如
TRANSFER、HEADERSECTION)
解决方案
通用优化:用键索引高效匹配OBJ_ID
为避免重复判断数百个OBJ_ID,使用XSLT的key功能创建索引,实现快速查找,提升大文件处理效率。
任务a:保留指定OBJ_ID的节点
以下XSLT会完整保留原XML结构,仅筛选出符合条件的节点:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:ili="http://www.interlis.ch/INTERLIS2.3" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> <!-- 目标OBJ_ID列表,可替换为外部XML文件引用 --> <xsl:param name="target-obj-ids"> <id>ch17fnufWDNTSs6C</id> <id>ch17fnuf3f5P2bPQ</id> </xsl:param> <!-- 创建OBJ_ID索引 --> <xsl:key name="obj-id-key" match="id" use="." /> <!-- 默认模板:复制所有节点和属性,保留原结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <!-- 筛选DATASECTION下带OBJ_ID的节点:仅保留在列表中的项 --> <xsl:template match="ili:DATASECTION//*[ili:OBJ_ID]"> <xsl:if test="key('obj-id-key', ili:OBJ_ID, $target-obj-ids)"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>
扩展说明
若OBJ_ID列表是外部纯文本文件(每行一个ID),可先将其转为XML格式(如obj-ids.xml),再通过document('obj-ids.xml')/ids/id引用。
任务b:移除指定OBJ_ID的节点
仅需修改判断逻辑,用空模板直接匹配并移除目标节点:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:ili="http://www.interlis.ch/INTERLIS2.3" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" /> <!-- 需要移除的OBJ_ID列表 --> <xsl:param name="remove-obj-ids"> <id>ch17fnufWDNTSs6C</id> <id>ch17fnuf3f5P2bPQ</id> </xsl:param> <xsl:key name="remove-id-key" match="id" use="." /> <!-- 默认模板:保留原结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <!-- 匹配并移除目标节点 --> <xsl:template match="ili:DATASECTION//*[ili:OBJ_ID][key('remove-id-key', ili:OBJ_ID, $remove-obj-ids)]" /> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Pierre de la Verre
相关产品推荐
相关产品推荐

