You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用LINQ跨层级移除XML中重复Placemark节点的实现方案

当然可以用LINQ to XML实现跨所有层级的Placemark去重,而且这是相当高效的解决方案。咱们一步步来解决你的问题:

1. 先解决跨层级获取Placemark的问题

你原来的代码只获取了Document直接子节点的Placemark,要遍历所有嵌套层级(比如Folder里的Folder),只需要把Elements换成Descendants方法——它会递归遍历当前节点下的所有子节点,找到所有匹配的元素:

XNamespace ns = "http://www.opengis.net/kml/2.2";
// 递归获取所有层级的Placemark
var allPlacemarks = xdoc.Descendants(ns + "Placemark");
2. 最优去重实现逻辑

去重的核心是如何定义两个Placemark是重复的,这里分两种场景:

场景一:完整结构完全一致才算重复

如果你的需求是只要Placemark的XML结构(包括所有子节点、文本、空格)完全相同就算重复,直接用元素的字符串形式作为分组键是最简单的方式:

allPlacemarks.GroupBy(p => p.ToString())
             .SelectMany(g => g.Skip(1)) // 跳过每组第一个,剩下的都是重复项
             .Remove(); // 从DOM树中移除重复元素

场景二:仅核心字段一致就算重复

如果只关心核心数据(比如name和coordinates)是否相同,忽略格式或其他无关节点的差异,建议自定义分组键,这样更精准:

allPlacemarks.GroupBy(p => new {
    Name = p.Element(ns + "name")?.Value,
    Coordinates = p.Descendants(ns + "coordinates")?.FirstOrDefault()?.Value
})
.SelectMany(g => g.Skip(1))
.Remove();

这种方式避免了因XML格式的细微差异(比如换行、空格)导致的误判,更适合实际业务场景。

3. 保存处理后的XML文件

处理完成后,直接用XDocument.Save方法即可保存为新的KML文件,推荐加上SaveOptions.OmitDuplicateNamespaces参数避免重复的命名空间声明:

// 本地文件加载用XDocument.Load代替Parse
var xdoc = XDocument.Load(@"C:\your-input-path\source.kml");
// ... 去重逻辑 ...
// 保存到新文件
xdoc.Save(@"C:\your-output-path\deduped.kml", SaveOptions.OmitDuplicateNamespaces);
完整可运行Demo

结合你提供的示例字符串,完整测试代码如下:

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main()
    {
        var raw = @"<?xml version='1.0' encoding='UTF-8'?><kml xmlns= 'http://www.opengis.net/kml/2.2'> <Document> <Folder> <Placemark> <name>1</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>2</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>2</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>4</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Folder> <Placemark> <name>3</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>4</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>4</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> </Folder> </Folder> <Placemark> <name>4</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> <Placemark> <name>4</name> <description>abc</description> <Point> <coordinates>102.595626,14.996729</coordinates> </Point> </Placemark> </Document> </kml>";
        
        var xdoc = XDocument.Parse(raw);
        XNamespace ns = "http://www.opengis.net/kml/2.2";
        
        // 跨层级去重Placemark(这里用完整结构匹配)
        xdoc.Descendants(ns + "Placemark")
            .GroupBy(p => p.ToString())
            .SelectMany(g => g.Skip(1))
            .Remove();
        
        // 打印结果或保存到文件
        Console.WriteLine(xdoc.ToString());
        // xdoc.Save(@"deduped.kml", SaveOptions.OmitDuplicateNamespaces);
    }
}
关键知识点总结
  • Descendants:递归遍历所有子节点,完美解决跨层级查找的需求。
  • 分组去重:利用LINQ的GroupBy将重复元素分组,Skip(1)保留每组第一个实例,移除剩余重复项。
  • LINQ to XML的Remove扩展方法:直接操作DOM树,无需手动遍历删除,简洁高效。

内容的提问来源于stack exchange,提问作者user1254053

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:47:38