原文:C# 程序自动批量生成 google maps 的KML文件

google maps 的 KML 文件可以用于静态的地图标注,在某些应用中,我们手上往往有成百上千个地址,我们需要把这些地址和描述批量标注到 google maps 上去,如果手工来做,太耗时间,在这里我写了一个程序批量来生成这个 KML 文件。

首先看一下 KML 文件的格式:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.google.com/earth/kml/2">
<Document>
<name>kml_sample2.kml</name> <Style id="red">
<IconStyle>
<Icon>
<href>http://www.google.com/intl/en_us/mapfiles/ms/icons/red-dot.png</href>
</Icon>
</IconStyle>
</Style> <Style id="green">
<IconStyle>
<Icon>
<href>http://www.google.com/intl/en_us/mapfiles/ms/icons/green-dot.png</href>
</Icon>
</IconStyle>
</Style> <Style id="blue">
<IconStyle>
<Icon>
<href>http://www.google.com/intl/en_us/mapfiles/ms/icons/blue-dot.png</href>
</Icon>
</IconStyle>
</Style> <Placemark>
<name>Google Inc.</name>
<description><![CDATA[
Google Inc.<br />
1600 Amphitheatre Parkway<br />
Mountain View, CA 94043<br />
Phone: +1 650-253-0000<br />
Fax: +1 650-253-0001<br />
<p>Home page: <a href="http://www.google.com">www.google.com</a></p>
]]>
</description>
<styleUrl>#red</styleUrl>
<Point>
<coordinates>-122.0841430, 37.4219720, 0</coordinates>
</Point>
</Placemark> <Placemark>
<name>Yahoo! Inc.</name>
<description><![CDATA[
Yahoo! Inc.<br />
701 First Avenue<br />
Sunnyvale, CA 94089<br />
Tel: (408) 349-3300<br />
Fax: (408) 349-3301<br />
<p>Home page: <a href="http://yahoo.com">http://yahoo.com</a></p>
]]>
</description>
<styleUrl>#green</styleUrl>
<Point>
<coordinates>-122.0250403,37.4163228</coordinates>
</Point>
</Placemark> </Document>
</kml>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

这个是一个典型的用于google maps 的 KML 文件,(注意不同应用的KML 格式会有所不同,比如 google earth 的 kml 格式就复杂得多)

从这个kml 文件格式来看,其实它就是一个 xml 文件,我们只要自动生成这个文件中各个元素的信息就可以得到这个xml  文件。这里其实最大的问题是如何自动通过地址获取经纬度坐标。值得庆幸的是 google 提供了这方面的 api 函数。google api 获取地理坐标的官方例子见:geocodingapi

我的实现稍微复杂一些,因为我需要在函数中为不同的位置自动分配颜色

   1:          /// <summary>
   2:          /// Generate placemark by address description
   3:          /// </summary>
   4:          /// <param name="addrDescription">address and description</param>
   5:          /// <returns>if no matched, return false</returns>
   6:          public bool Generate(AddressDescription addrDescription)
   7:          {
   8:              _LastErrorOrWarning = null;
   9:   
  10:              Thread.Sleep(DelayInMs);
  11:   
  12:              List<GeographicCoordinate> coordinates = Geocoding.Geocode(addrDescription.Address);
  13:   
  14:              if (coordinates.Count == 0)
  15:              {
  16:                  _LastErrorOrWarning = string.Format("Address:{0}, Description:{1} does not find the coordinates, please make sure the address is correctly.",
  17:                      addrDescription.Address, addrDescription.Description);
  18:   
  19:                  return false;
  20:              }
  21:   
  22:              if (coordinates.Count > 1)
  23:              {
  24:                  _LastErrorOrWarning = string.Format("Address:{0}, Description:{1} has more than one coordinates.",
  25:                      addrDescription.Address, addrDescription.Description);
  26:              }
  27:   
  28:              string colorId = Colors[_ColorIndex];
  29:   
  30:              _ColorIndex++;
  31:   
  32:              if (_ColorIndex >= Colors.Count)
  33:              {
  34:                  _ColorIndex = 0;
  35:              }
  36:   
  37:              _Kml.Document.Add(new Placemark(addrDescription.Address, addrDescription.Description, colorId,
  38:                  coordinates[0].Latitude, coordinates[0].Longitude));
  39:   
  40:              return true;
  41:          }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

第32行有个bug,应该是 >=  ,我原来写成 > 了,博客中我改过来了,源码我就不改了。

如上代码,第12行就是通过GeocodingApi 获取指定地址的物理坐标,由于有时候获取不到坐标,有时候由于地址不确切,有多个坐标,所以我加了一个错误和警告的属性,用于调用者得到相关的信息。

_Kml 这个对象是一个 Kml 类的实例,这个类用于生成 KML 文件结构,并可以保存到KML文件中。这个类在后面介绍。

下面的 _Color 部分是自动的顺序分配标注点的颜色,我为了省事,在代码中写死了4种颜色,你也可以修改代码增加颜色或其他图标。

标注颜色这里其实还有一个问题,就是如果让相邻的节点显示不同颜色,这个算法比较复杂了,我没有实现,各位如果有兴趣可以思考一下这个怎么做。

好了,最大的问题解决了,剩下就是写 xml  文件了,这个很简单,我就不深入讲了,直接把代码贴出来。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO; namespace GenerateKML
{
public class Placemark
{
public class KMLPoint
{
public KMLPoint()
{
} public KMLPoint(double latitude, double longitude)
{
SetCoordinates(latitude, longitude);
} private string _coordinates; public void SetCoordinates(double latitude, double longitude)
{
_coordinates = longitude.ToString() + "," + latitude.ToString();
} public string coordinates
{
get
{
return _coordinates;
} set
{
_coordinates = value;
}
}
} [XmlElement("name")]
public string Name { get; set; } [XmlElement("description")]
public string Description { get; set; } [XmlElement("styleUrl")]
public string StyleUrl { get; set; } public KMLPoint Point { get; set; } public Placemark()
{
} public Placemark(string name, string description, string styleUrl,
double latitude, double longitude)
{
Name = name;
Description = description;
StyleUrl = styleUrl; Point = new KMLPoint(latitude, longitude);
} } public class kml
{
[XmlIgnore]
string Name { get; set; } List<Placemark> _Placemarks = new List<Placemark>(); [XmlArray()]
public List<Placemark> Document
{
get
{
return _Placemarks;
} set
{
_Placemarks = value;
}
} public kml()
{
} public kml(string name)
{
Name = name;
} private XmlNode GetColorStyle(XmlDocument xmlDoc, string color)
{
XmlNode style = xmlDoc.CreateNode(XmlNodeType.Element, "Style", "");
XmlAttribute attr = style.OwnerDocument.CreateAttribute("id");
attr.Value = color;
style.Attributes.Append(attr); XmlNode iconStyle = xmlDoc.CreateNode(XmlNodeType.Element, "IconStyle", "");
XmlNode icon = xmlDoc.CreateNode(XmlNodeType.Element, "Icon", "");
XmlNode href = xmlDoc.CreateNode(XmlNodeType.Element, "href", "");
href.InnerText = string.Format("http://www.google.com/intl/en_us/mapfiles/ms/icons/{0}-dot.png",
color); style.AppendChild(iconStyle);
iconStyle.AppendChild(icon);
icon.AppendChild(href); return style;
} public void SaveToFile(string xml)
{
using (FileStream fs = new FileStream(xml, FileMode.Create, FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
{
XmlSerializer serializer = new XmlSerializer(this.GetType());
serializer.Serialize(sw, this);
}
} XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xml);
xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null); XmlNode documentNode = xmlDoc.SelectSingleNode(@"/kml/Document"); XmlNode nameNode = xmlDoc.CreateNode(XmlNodeType.Element, "name", "");
nameNode.InnerText = this.Name; XmlNode placeMarkNode = documentNode.FirstChild;
documentNode.InsertBefore(nameNode, placeMarkNode); documentNode.InsertBefore(GetColorStyle(xmlDoc, "red"), placeMarkNode);
documentNode.InsertBefore(GetColorStyle(xmlDoc, "green"), placeMarkNode);
documentNode.InsertBefore(GetColorStyle(xmlDoc, "blue"), placeMarkNode);
documentNode.InsertBefore(GetColorStyle(xmlDoc, "yellow"), placeMarkNode); XmlNode kmlNode = xmlDoc.SelectSingleNode(@"/kml"); XmlAttribute attr = kmlNode.OwnerDocument.CreateAttribute("xmlns");
attr.Value = "http://earth.google.com/kml/2.0"; kmlNode.Attributes.Append(attr); xmlDoc.Save(xml);
}
} }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

下面看一下调用的方法,使用者如果不想仔细研究细节,那就关注这个就可以了,调用方法非常简单

   1:          static void Main(string[] args)
   2:          {
   3:              Generator kmlGenerator = new Generator("Test");
   4:   
   5:              kmlGenerator.Generate(new AddressDescription("1600 Amphitheatre Parkway, Mountain View, CA 94043",
   6:                  "Google"));
   7:   
   8:              if (!string.IsNullOrEmpty(kmlGenerator.LastErrorOrWarning))
   9:              {
  10:                  Console.WriteLine(kmlGenerator.LastErrorOrWarning);
  11:              }
  12:   
  13:              kmlGenerator.Generate(new AddressDescription("1 Microsoft Way, Redmond, WA 98052",
  14:                  "Microsoft"));
  15:   
  16:              if (!string.IsNullOrEmpty(kmlGenerator.LastErrorOrWarning))
  17:              {
  18:                  Console.WriteLine(kmlGenerator.LastErrorOrWarning);
  19:              }
  20:   
  21:              kmlGenerator.Generate(new AddressDescription("1601 S. California Ave., Palo Alto, CA 95304",
  22:                  "Facebook"));
  23:   
  24:              if (!string.IsNullOrEmpty(kmlGenerator.LastErrorOrWarning))
  25:              {
  26:                  Console.WriteLine(kmlGenerator.LastErrorOrWarning);
  27:              }
  28:   
  29:              kmlGenerator.Generate(new AddressDescription("701 First Ave, Sunnyvale, CA 94089",
  30:                  "Yahoo"));
  31:   
  32:              if (!string.IsNullOrEmpty(kmlGenerator.LastErrorOrWarning))
  33:              {
  34:                  Console.WriteLine(kmlGenerator.LastErrorOrWarning);
  35:              }
  36:   
  37:              kmlGenerator.Save("test.kml");
  38:          }
  39:      }
 
第三行,实例化 KML 生成器,并指定一个名字,这个名字对于 kml 文档中的 name 字段。
第五行,在kml 文件中标注 google 总部的地址
第八行,判断是否有最新的错误,每次执行第五行的Generate 方法,会将最新错误清空,所以这里永远是得到最近一次调用 Generate 方法的错误或警告。
后面以此类推了。
最后 Save 到一个kml文件中就OK了。
 
最后,我们可以把这个 kml 文件导入到我们自己创建的 google map 中。这个在 google maps 里面有相应的导入功能,这里就不介绍了。
 
完整源码下载
 
 
注意源码中 app.config 文件中
 
    <add key="GeocodingApi.Key" value="google api key" />
<add key="GeocodingApi.Url" value="http://maps.google.com/maps/geo?" />

GeocodingApi.key 这里要填写你自己的 google api key,你可以在 google  网站上获取,地址如下:

http://code.google.com/apis/maps/signup.html

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

C# 程序自动批量生成 google maps 的KML文件的更多相关文章

  1. 分享一款一直在维护的【网络开发运维|通用调试工具】: http请求, websocket,cmd, RSA,DES, 参数签名工具,脚本批量生成工具,google动态口令,端口检测,组件注册,js混淆...

    首先发下下载地址:https://files.cnblogs.com/files/taohuadaozhu/ConfigLab.Test.ex.rar 日常开发,运维,跨部门跨公司对接中.  想快速调 ...

  2. 程序自动生成Dump文件

    前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...

  3. 程序自动生成Dump文件()

    前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了 ...

  4. EF-记录程序自动生成并执行的sql语句日志

    在EntityFramework的CodeFirst模式中,我们想将程序自动生成的sql语句和执行过程记录到日志中,方便以后查看和分析. 在EF的6.x版本中,在DbContext中有一个Databa ...

  5. Web程序-----批量生成二维码并形成一张图片

    需求场景:客户根据前台界面列表所选择的数据,根据需要的信息批量生成二维码并形成一张图片,并且每张图片显示的二维码数量是固定的,需要分页(即总共生成的二维码图片超出每页显示的需另起一页生成),并下载到客 ...

  6. Google Maps API V3 之 路线服务

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

  7. Google Maps Android API v2 (1)- 入门

    才可以开始工作的API,你将需要下载的API,并确保你有一个谷歌地图Android的API V2关键.API和关键是免费提供的. 概观 获得谷歌地图Android的API V2 谷歌地图API密钥 显 ...

  8. Google Maps V3 之 路线服务

    概述 您可以使用 DirectionsService 对象计算路线(使用各种交通方式).此对象与 Google Maps API 路线服务进行通信,该服务会接收路线请求并返回计算的结果.您可以自行处理 ...

  9. Google Maps API V3 之 图层

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

随机推荐

  1. 小牟Andorid下面MD5具体实现的思路总结

    Android的开发往往需要一定数目demo 从今起MD5一些加密算法提取物 看看是如何实现的 首先,我们必须明确为什么加密? 1 数据安全处理 2 防止数据窃取 3 有效的避免恶意攻击 4 保证文件 ...

  2. 采用 matlab 阅读SAR 元数据

    这方面能够參考书籍:"Digital processing of synthetic aperture radar data", by Ian Cumming and Frank ...

  3. MEF初体验之二:定义组合部件和契约

    组合部件 在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务.在MEF编程模型中,为了声明组合部件 ...

  4. 1067: spark.components:NavigatorContent 类型值的隐式强制指令的目标是非相关类型 String

    1.错误描写叙述 此行的多个标记: -workId -1067: spark.components:NavigatorContent 类型值的隐式强制指令的目标是非相关类型 String. 2.错误原 ...

  5. Eclipse+Maven创webapp工程

    1.开启eclipse,右键new-->other,例如以下图找到maven project. 选择maven project,点击next 2.选择maven project后.显示创建mav ...

  6. fastboot完成自己主动命令

    于Ubuntu13.10后来Ubuntu 14.04上,由APT安装fastboot以及adb该工具后, 发现fastboot在主动补充一个问题,, fastboot flash 自己主动有问题完成后 ...

  7. SQL Server审计功能入门:SQL Server审核 (SQL Server Audit)

    原文:SQL Server审计功能入门:SQL Server审核 (SQL Server Audit) 介绍 Audit是SQL Server 2008之后才有的功能,它能告诉你"谁什么时候 ...

  8. SharePoint Search之(两)持续抓取Continues crawl

    于SharePoint 2010与在先前的版本号.有两种类型的抓取,Full和Incremental.故名思议.Full Crawl 抓取的时间.该Content Source里面的内容再次攀升.In ...

  9. 【Unity 3D】学习笔记29:游戏的例子——简单的小制作地图

    无论学习.只看不练是坏科学. 因此,要总结回想这怎么生产MMROPG小地图的游戏.于MMROPG游戏类,在游戏世界中行走时导致各地,通常在屏幕的右上角,将有一个区域,以显示当前的游戏场景微缩.在游戏世 ...

  10. SSL/TLS协议运行机制的概述(转)

    互联网的通信安全,建立在SSL/TLS协议之上. 本文简要介绍SSL/TLS协议的运行机制.文章的重点是设计思想和运行过程,不涉及具体的实现细节.如果想了解这方面的内容,请参阅RFC文档. 一.作用 ...