How to create your own map on Google Maps
A simple way to create your own Google map from several locations.
Introduction
A few days ago I've got a task to create my own Google map with several points. It's very easy to create points step by step, but I'm a very lazy man. I thought that the simplest way would be to create an excel sheet with the POI -s (Point of Interests) and create a program, to get the POI's LAT-LON coordinates. This task is not so difficult. The Google API provide the possibility to get LAT-LON coordinates from post addresses, and that was what I needed.
What Problem Does this Solution Solve?
This program helps to create Your own Google Map, with .kml file. Not necessary to create own maps point by point, You can create a simple Excel file with POI-s, and postal addresses, and your own map is ready, after some clicks.
Background
First of all very useful to study the Google maps API here: https://developers.google.com/maps/documentation/geocoding/
But I hope the basics and main things can be understand from my code. Then good to have same experience to manipulate Microsoft Excel sheets, and some experience in xml files and Linq.
The simple excel file contains the POI's in this format: Name, zip, city, street, housenumber, country.
In this example I created an excel file, to try, and to see the format the source file of this process. Download the example, complie, and try it. Load my example (ownmap.xls) export the .kml file, and see the result. now You can import this kml file into Google Maps.
Important! You can read 2500 addresses per day from Google Api without license. If You want more, You have to buy the Google's Bussiness license.
What is the Edification?
In this simple code I demonstrate a web request and web response in C#. You can see an example to parse xml file in Linq. The POI's are in an Excel file, so this is a very simple example how to read and write Excel files via Office Interop. Last but not least this program creates a .kml file, which is really an xml, so there is an example how to create simple xml file like a textfile.
Keywords
- Read and write Microsoft Excel sheets via Office Interop
- Simple Web request and response
- Simple Linq for parse xml.
Using the code
First I made a struct mylocatinon
, to be a container for locations. GPS coordinates will be in decimal format, like 47,197484. So LAT and LON coordinates will be double
numbers.
/// <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;
}
After my experience was that Google API can work with our (Hungarian) national characters, like á, é but sometimes not. Beyond that I had to make a standard
URL from postal addresses, i.e change space to %20 etc. So
convuri
method converts any text to URL format without national characters.
/// <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;
}
Next thing deserving to emphasize the web request. I wrote a method, name is Getloc
. This method gives back the LAT LON coordinates, from postal address.
If some error is occured, getloc
method gives back -1,-1 coordinates.
In this example myuri
variable contains the converted (see below) URL
with postal address. The address must be in this format: number street zipcode city country. Spaces will be converted into URL format: %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());
The web requests answer will be an XML. This example shows how to parse an xml with linq. In this example ret
is a local variable typed
mylocation
(see below)
//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);
}
And last, but not least, how to manipulate MS Excel file with interop module:
//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>");
How to make own Google Map from generated .kml file?
After using this program (Start with excel, then export to .kml the result) You can make an own Google map. A Google account (gmail) is necessary to upload own map. Go to Google Maps site, choose own places. Create a new map. Give a name, and a short description, then import the new .kml file. Thats all.
History
- Version 1.0.