如何创建自己的谷歌地图
从多个位置创建您自己的 Google 地图的简单方法。
引言
几天前,我收到了一个任务,需要用几个点创建我自己的 Google 地图。逐个创建点很容易,但我很懒。 我认为最简单的方法是创建一个包含 POI(兴趣点)的 Excel 表格,然后创建一个程序来获取 POI 的 LAT-LON 坐标。这项任务并不难。 Google API 提供了从邮政地址获取 LAT-LON 坐标的可能性,这正是我所需要的。
此解决方案解决了什么问题?
该程序有助于使用 .kml 文件创建您自己的 Google 地图。无需逐点创建自己的地图,您可以创建一个简单的 Excel 文件,其中包含 POI 和邮政地址,只需点击几下,您的自定义地图就准备好了。
背景
首先,在这里学习 Google Maps API 非常有用:https://developers.google.com/maps/documentation/geocoding/
但我希望从我的代码中可以理解基本知识和主要内容。然后,对操作 Microsoft Excel 表格有一些经验,并且对 xml 文件和 Linq 有一些经验,这很有帮助。
简单的 Excel 文件包含此格式的 POI:名称、邮编、城市、街道、门牌号、国家/地区。
在这个例子中,我创建了一个 Excel 文件进行尝试,并查看这个过程的源文件格式。下载示例,编译并试用。加载我的示例 (ownmap.xls) 导出 .kml 文件,然后查看结果。现在您可以将此 kml 文件导入 Google Maps。
重要提示!您每天可以从 Google Api 读取 2500 个地址,无需许可证。如果您需要更多,则必须购买 Google 的商业许可证。
有什么教育意义?
在此简单代码中,我演示了 C# 中的 Web 请求和 Web 响应。您可以查看一个在 Linq 中解析 xml 文件的示例。 POI 位于 Excel 文件中,因此这是一个通过 Office Interop 读取和写入 Excel 文件的非常简单的示例。最后但并非最不重要的一点是,此程序创建一个 .kml 文件,它实际上是一个 xml 文件,因此这里有一个如何创建简单 xml 文件(如文本文件)的示例。
关键词
- 通过 Office Interop 读取和写入 Microsoft Excel 表格
- 简单的 Web 请求和响应
- 用于解析 xml 的简单 Linq。
使用代码
首先,我制作了一个结构体mylocatinon
,作为位置的容器。 GPS 坐标将采用十进制格式,例如 47.197484。因此,LAT 和 LON 坐标将是double
数字。
/// <summary>
/// Location container for LAT-LON coordinates. They are doubles
/// </summary>
public struct mylocation
{
/// <summary>
/// Holds the latitude information
/// </summary>
public double latitude;
/// <summary>
/// Holds the longitude information
/// </summary>
public double longitude;
}
根据我的经验,Google API 可以使用我们的(匈牙利)国家字符,例如 á、é,但有时不行。除此之外,我必须从邮政地址创建一个标准 URL,即把空格更改为 %20 等。 因此,convuri
方法将任何文本转换为 URL 格式,而无需国家字符。
/// <summary>
/// This routine converts the national characters to standard.
/// Goolgle api can parse the national characters, but my experinece is better change to standard chars.
/// This method is especially converts hungarian national chars.
/// If You use another national chars, please overwrite this methos.
/// </summary>
/// <param name="be">Input parameter for convert</param>
/// <returns>
/// string
/// </returns>
public string convuri(string be)
{
if (be == "")
{
return null;
public string convuri(string be)
{
if (be == "")
{
return null;
}
// Output will be the input in default case
string ret = be;
// Old, national chars to be changed
string[] oldchars = { "á", "í", "ű", "ő", "ü",
"ö", "ú", "ó", "é", " ", "Á", "Í",
"Ű", "Ő", "Ü", "Ö", "Ú", "Ó", "É", "." };
// New chars to change for
string[] newchars = { "a", "i", "u", "o", "u", "o",
"u", "o", "e", " ", "A", "I", "U",
"O", "U", "O", "U", "O", "E", "." };
// Changing cycle
for (int i = 0; i < oldchars.Length - 1; i++)
{
ret = ret.Replace(oldchars[i], newchars[i]);
}
//converts the space to hex 20 (32) that means the space in URL
ret = ret.Replace(
" ", "%20");
return ret;
}
}
string ret = be;
string[] oldchars = { "á", "í", "ű", "ő", "ü", "ö",
"ú", "ó", "é", " ", "Á", "Í", "Ű",
"Ő", "Ü", "Ö", "Ú", "Ó", "É", "." };
string[] newchars = { "a", "i", "u", "o", "u", "o",
"u", "o", "e", " ", "A", "I", "U",
"O", "U", "O", "U", "O", "E", "." };
for (int i = 0; i < oldchars.Length - 1; i++)
{
ret = ret.Replace(oldchars[i], newchars[i]);
}
//converts the space to hex 20 (32) that means the space in URL
ret = ret.Replace(" ", "%20");
return ret;
}
接下来要强调的是 Web 请求。我编写了一个名为Getloc
的方法。此方法返回邮政地址的 LAT LON 坐标。如果发生错误,getloc
方法将返回 -1,-1 坐标。
在此示例中,myuri
变量包含转换后的(见下文)带有邮政地址的 URL。地址必须采用以下格式:门牌号 街道 邮编 城市 国家/地区。 空格将被转换为 URL 格式:%20
//Define wbrequest, and webresponse. Response will be an xml document.
System.Net.HttpWebRequest webRequest;
System.Net.HttpWebResponse webResponse;
//create address from excel
string cim = hsz.Trim() + " " + utca.Trim() + " " + zip.Trim() +
" " + varos.Trim() + " " + orszag.Trim();
//convert and clean url
cim = convuri(cim);
Uri myuri = new Uri("http://maps.googleapis.com/maps/api/geocode/xml?address=" +
cim + "&sensor=true");
webRequest = (HttpWebRequest)(WebRequest.Create(myuri));
webRequest.Credentials = CredentialCache.DefaultCredentials;
// Companies mostly uses proxy servers. If You use it from home, proxy is not necessary
WebProxy p = new WebProxy(textBox2.Text, Convert.ToInt32(textBox3.Text));
//You can use default (login) credentials, or some else credential, like this
// p.Credentials = new NetworkCredential("user","password","domain")
p.Credentials = CredentialCache.DefaultCredentials;
if (checkBox1.Checked)
{
webRequest.Proxy = p;
}
webRequest.Proxy = p;
webRequest.Method = "GET";
webRequest.ContentType = "text/xml";
//Call a normal WEB request. Response will be a standard xml file.
webResponse = (System.Net.HttpWebResponse)(webRequest.GetResponse());
webResponse.GetResponseStream();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
Web 请求的答案将是一个 XML。 此示例演示了如何使用 linq 解析 xml。 在此示例中,ret
是一个类型为 mylocation
的局部变量(见下文)
//Create a new xml document named resxml
XmlDocument resxml = new XmlDocument();
//Load stream content into resxml variable
resxml.LoadXml(sr.ReadToEnd());
//Closes the stream.
sr.Close();
//Converts xml content into a string
string sss = resxml.InnerXml.ToString();
//Not needed
resxml = null;
//Parsing the xml contetnt with linq.
// xml nodes result - geometry - location and values what we needed is lat, and lon.
//There are NOT attributes.
//<result>
//....
// <geometry>
//...
// <location>
// <lat> 47,19745464</lat>
// <lon> 19,15678664</lon>
// </location>
//etc
// </summary>
XDocument xdoc = XDocument.Parse(sss);
//Linq question. Result will be a LAT-LON struct, like mylocatin struct
var aaas = from aaa in xdoc.Descendants("result").Descendants("geometry").Descendants("location")
select new
{
lat = aaa.Element("lat").Value,
lon = aaa.Element("lng").Value
};
//Cycle for get linq query's values, and put into a mylocation typed struct.
foreach (var aaa in aaas)
{
ret.latitude = Convert.ToDouble(aaa.lat);
ret.longitude = Convert.ToDouble(aaa.lon);
}
最后,但并非最不重要的一点是,如何使用 interop 模块操作 MS Excel 文件
//Call Excel interop. The excel application represents oApp variable
Microsoft.Office.Interop.Excel.Application oApp = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = null;
Worksheet ws = null;
// Excel will NOT visible is this routine
oApp.Visible = false;
// Its maybe necessary when use excel from a program.
oApp.UserControl = false;
// The best method to change the culture info to en-Us when using excel.
// I had problems with excel interoperation with another culture info.
System.Globalization.CultureInfo oldCI = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Globalization.CultureInfo Cli = new System.Globalization.CultureInfo("en-US");
System.Threading.Thread.CurrentThread.CurrentCulture = Cli;
// Creates a stringbuilder method. The result kml will be created into sb variable.
StringBuilder sb = new StringBuilder();
// Creates the kml file's header. In fact kml is a special xml.
// The own map's name can give in textbox5.text on form.
sb.AppendLine("");
sb.AppendLine("<kml xmlns="http://www.google.com/earth/kml/2">");
sb.AppendLine("<document>");
sb.AppendLine("<name>" + textBox5.Text + "</name>");
try
{
// Opens an excel file, name given in textbox1.text
wb = oApp.Workbooks.Open(textBox1.Text);
// Sets worksheets object
Sheets sheets = wb.Worksheets;
// To set diplayalerts to fals is necessary. If you not set to false,
// excel will ask to "Save document" before quiting.
oApp.DisplayAlerts = false;
// Sets the first worksheet to work on.
ws = (Worksheet)sheets.get_Item(1);
// Ask userd range of excel.
Range ur = ws.UsedRange;
Range cell;
// Declares some variables
string orszag;
string nev;
string varos;
string utca;
string hsz;
string zip;
string lat;
string lon;
// Cycle to read excel row by row in used range
for (int i = 1; i <= ur.Cells.Rows.Count; i++)
{
// First column is the name of POI. Writes into the form into label1
cell = (Range)ws.Cells[i, 1];
nev = cell.Value.ToString();
label1.Text = nev;
// Second column column is the ZIP of POI
cell = (Range)ws.Cells[i, 2];
zip = cell.Value.ToString();
// Third column column is the varos of POI
cell = (Range)ws.Cells[i, 3];
varos = cell.Value.ToString();
// Fourth column is the street of POI
cell = (Range)ws.Cells[i, 4];
utca = cell.Value.ToString();
// Fifth column is the housenumber of POI
cell = (Range)ws.Cells[i, 5];
hsz = cell.Value.ToString();
// Sixth column is the country of POI
cell = (Range)ws.Cells[i, 6];
orszag = cell.Value.ToString();
// Seventh column is the LAT value of POI
cell = (Range)ws.Cells[i, 7];
lat = cell.Value.ToString();
// Eighth column is the LAT value of POI
cell = (Range)ws.Cells[i, 8];
lon = cell.Value.ToString();
// Appends parameters into sb stringbuilder in kml format
sb.AppendLine("<placemark>");
sb.AppendLine("<name>" + nev + "</name>");
sb.AppendLine("<description>" + varos.Trim() + ", " + zip.Trim() +
" " + utca.Trim() + " " + hsz.Trim() + "</description>");
sb.AppendLine("<point>");
sb.AppendLine("<coordinates>" + lon + "," + lat + ",0</coordinates>");
sb.AppendLine("</point>");
sb.AppendLine("</placemark>");
}
}
catch (Exception ex)
{
// In case of any problem shows a message
MessageBox.Show(ex.Message);
}
// Finally will do this with excel either everithing was good or not.
finally
{
// Saves back the worksheet
wb.Save();
// Quits from excel
oApp.Quit();
// Sets back excelapp displayalerts property to true
oApp.DisplayAlerts = true;
// Sets back the original cultureinfo
System.Threading.Thread.CurrentThread.CurrentCulture = oldCI;
// Releases COM objects, the workbook, worksheet and excelapp objects
Marshal.ReleaseComObject(ws);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(oApp);
}
// Appends the end of kml into sb stringbuilder
sb.AppendLine("</document>");
sb.AppendLine("</kml>");
如何从生成的 .kml 文件制作自己的 Google 地图?
在使用此程序后(从 excel 开始,然后将结果导出到 .kml),您可以制作自己的 Google 地图。 上传自己的地图需要一个 Google 帐户(gmail)。 转到 Google 地图 站点,选择自己的地点。 创建一个新地图。 命名并简短描述,然后导入新的 .kml 文件。 仅此而已。
历史
- 版本 1.0。