如何在C#中分离KML文件头部以拆分大文件?
基于C#的KML头部提取与文件拆分方案
问题说明
已提取KML文件的根信息,需分离包裹根信息的头部,以便在文件数据量过大时拆分根数据,生成多个较小的KML文件,实现头部独立复用。KML结构示例如下:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://www.opengis.net/kml/2.2"> <Document> <name>LoopLengthSpeedExport</name> <Schema name="Part2" id="kml_schema_ft_Part2"> <SimpleField type="string" name="Download"> <displayName>Download</displayName> </SimpleField> <SimpleField type="string" name="Upload"> <displayName>Upload</displayName> </SimpleField> <SimpleField type="string" name="DataDSLAM"> <displayName>DataDSLAM</displayName> </SimpleField> <SimpleField type="string" name="MetaDSLAM"> <displayName>MetaDSLAM</displayName> </SimpleField> <SimpleField type="string" name="Service Type"> <displayName>Service Type</displayName> </SimpleField> </Schema> <Folder> <name>LoopLengthSpeedExport</name> <Placemark> <!-- 省略Placemark内容 --> </Placemark> </Folder> </Document></kml>
解决方案
利用.NET的XDocument类处理XML结构,精准提取头部、尾部,并拆分Placemark生成多个小KML文件。
1. 提取KML头部与尾部
头部包含XML声明、<kml>标签、<Document>内到<Folder>之前的所有节点;尾部包含</Folder>、</Document>、</kml>闭合标签。
using System; using System.IO; using System.Linq; using System.Xml.Linq; public class KmlSplitter { private const string KmlNamespace = "http://www.opengis.net/kml/2.2"; public static void ExtractHeaderAndTail(string inputKmlPath, out string header, out string tail) { XDocument doc = XDocument.Load(inputKmlPath); XNamespace ns = KmlNamespace; // 构建头部:XML声明 + kml标签开头 + Document内到Folder之前的内容 var headerBuilder = new StringWriter(); headerBuilder.WriteLine(doc.Declaration.ToString()); headerBuilder.WriteLine($"<kml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns=\"{KmlNamespace}\">"); headerBuilder.WriteLine("<Document>"); // 取Document下除了Folder之外的所有直接子节点 var documentChildren = doc.Root.Element(ns + "Document").Elements().Where(e => e.Name.LocalName != "Folder"); foreach (var elem in documentChildren) { headerBuilder.WriteLine(elem.ToString()); } // 添加Folder开头标签到头部 headerBuilder.WriteLine("<Folder>"); headerBuilder.WriteLine($"<name>{doc.Root.Element(ns + "Document").Element(ns + "Folder").Element(ns + "name").Value}</name>"); header = headerBuilder.ToString(); // 构建尾部 tail = "</Folder>\n</Document>\n</kml>"; } }
2. 拆分KML生成多个小文件
提取所有Placemark节点,按指定数量拆分,每个文件拼接头部、拆分后的Placemark、尾部。
public static void SplitKml(string inputKmlPath, string outputDir, int placemarksPerFile) { if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir); ExtractHeaderAndTail(inputKmlPath, out string header, out string tail); XDocument doc = XDocument.Load(inputKmlPath); XNamespace ns = KmlNamespace; var placemarks = doc.Descendants(ns + "Placemark").ToList(); int fileIndex = 1; for (int i = 0; i < placemarks.Count; i += placemarksPerFile) { var batch = placemarks.Skip(i).Take(placemarksPerFile); string outputPath = Path.Combine(outputDir, $"split_{fileIndex}.kml"); using (var writer = new StreamWriter(outputPath)) { writer.Write(header); foreach (var pm in batch) { writer.WriteLine(pm.ToString()); } writer.Write(tail); } fileIndex++; } }
3. 使用示例
class Program { static void Main(string[] args) { string inputPath = @"C:\input.kml"; string outputDir = @"C:\split_kmls"; int perFile = 100; // 每个文件包含100个Placemark KmlSplitter.SplitKml(inputPath, outputDir, perFile); } }
关键说明
- 处理KML的XML命名空间:KML默认命名空间为
http://www.opengis.net/kml/2.2,必须在查询节点时指定,否则无法匹配。 - 头部包含了Schema、Document名称等复用性内容,确保拆分后的KML文件结构完整、样式一致。
- 拆分逻辑可根据需求调整(比如按地域、类型拆分),示例中按数量均分。
内容的提问来源于stack exchange,提问作者to_Bewilder
相关产品推荐
相关产品推荐

