My Maps from Google

Google provides some extremely useful online tools that many of us have come to rely on. From Sheets, Slides, and Docs, to Gmail, Maps, and Keep, the advertising giant tends to cover all the angles. The most recent Google tool that I have started using is an improvement over an old service called My Places that started out as a part of Google Maps. It is called My Maps and provides users with the means to build custom annotated maps. Any maps you create can then be embedded into websites or shared via email and social media1.

When first visiting the site, you are offered an option to either create a new map or open an existing map. Any places you had in My Places are already transferred to My Maps and available to open if you wish.

Initial view after creating a map
Initial view after creating a map

Creating a new map presents you with a familiar Google Maps-style view but with additional overlays for editing the map. These are together at the top-left in two distinct groups. The first is the map structure where you can view and edit the name of the map and its layers, as well as add new layers and adjust the appearance of the base map layer. When I tried this, there were nine different base maps available; from left to right, top to bottom these are Map, Satellite, Terrain, Light Political, Mono City, Simple Atlas, Light Landmass, Dark Landmass, and Whitewater.

Map structure with "Base map" menu opened
Map structure with "Base map" menu opened

To edit the map name, map description, or layer name, just click the text.

Dialog for editing the map title and description
Dialog for editing the map title and description

Below the description are options to add a new layer and to share the map. There is also a drop down that provides options to open or create a map, delete, export, embed, and print the current map. Below that, each layer is shown. The layer drop down can be used to rename or delete the layer as well as view a data table of items on that layer. The data table allows you to add additional information about various things that have been added to the map (two columns for name and description are provided by default, but more can be added).

The My Maps toolbox
The My Maps toolbox

Next to the map structure is the toolbox. The toolbox contains a search bar, allowing you to find the area of the map on which to base your customizations. Below the search bar are buttons to undo, redo, select and manipulate, add places, draw lines, add directions, and measure distances and areas. Using these tools, you can build up map layers. When building the Stonehenge map for my blog post on our trip there, I was able to not only search for add mark existing places, but also add custom places. Each item added goes into the selected map layer, which is indicated by a colored bar on the left edge of the layer in the map structure. Clicking a layer changes the layer being edited.

Adding and editing a layer, showing the layer selection bar on the left edge
Adding and editing a layer, showing the layer selection bar on the left edge

The appearance of each item in a layer can be modified, either as a group or individually, by manipulating the styles option at the top of the layer and clicking the paint can icon on an individual item. By editing the layer style, you can also choose which column in the data table for that layer provides text for the items in that layer, and style items based on data in the data table (useful for representing data on the map). There is a lot of scope in this area, so I recommend playing around with it and seeing what works for your specific use case.

Editing the appearance of items on a layer is easy
Editing the appearance of items on a layer is easy

Once you are happy with the map you have created, you can share it, export it to KML (for use in Google Earth and other apps that support KML), and embed into websites. The main share options are familiar to anyone who has shared a document from Sheets, Slides, or Docs, allowing you to share a link to the map as well as control who can edit and view it. If you want to embed the map in a website, an embed code is provided via the map menu, however, as the site will tell you, you need to make the map public before you can embed.

Assigning permissions is consistent with other Google apps
Assigning permissions is consistent with other Google apps

All in all, I found My Maps a pleasant discovery and really nice to use. The styling options and ability to add additional data allow for some impressive customization. I am certainly going to use this application more in the future. How about you? Leave a comment and let me know your experiences with this new addition to Google's collection of online applications, or perhaps add details of alternatives that are out there.

  1. Those planning to use Google My Maps for commercial use should review Google permissions and license terms before proceeding []

Resolving XML references from embedded resources

Recently, I wanted to validate some XML via an XSD schema. Due to some product constraints and intentions regarding versioning, the schema is an embedded resource and is referenced via the noNamespaceSchemaLocation attribute.

When loading XML in .NET, you can specify an XmlResolver via the XmlReaderSettings . As stated in MSDN, the default uses a new XmlUrlResolver without credentials. This works great when the file is local on disk, but not when it is squirreled away inside my resources.

What I needed was a special version of XmlResolver that understood how to find my embedded schemas. So I created a derivation, XmlEmbeddedResourceResolver, to do just that.

public class XmlEmbeddedResourceResolver : XmlUrlResolver
{
	public XmlEmbeddedResourceResolver( Assembly resourceAssembly )
	{
		_resourceAssembly = resourceAssembly;
	}

	public override object GetEntity( Uri absoluteUri, string role, Type ofObjectToReturn )
	{
		if ( absoluteUri == null ) throw new ArgumentNullException( "absoluteUri", "Must provide a URI" );

		if ( ShouldAttemptResourceLoad( absoluteUri, ofObjectToReturn ) )
		{
			var resourceStream = GetSchemaStreamFromEmbeddedResources( absoluteUri.AbsolutePath );
			if ( resourceStream != null )
			{
				return resourceStream;
			}
		}
		return base.GetEntity( absoluteUri, role, ofObjectToReturn );
	}

	public override async Task<object> GetEntityAsync( Uri absoluteUri, string role, Type ofObjectToReturn )
	{
		if ( absoluteUri == null ) throw new ArgumentNullException( "absoluteUri", "Must provide a URI" );

		if ( ShouldAttemptResourceLoad( absoluteUri, ofObjectToReturn ) )
		{
			var resourceStream = await GetSchemaStreamFromEmbeddedResourcesAsync( absoluteUri.AbsolutePath );
			if ( resourceStream != null )
			{
				return resourceStream;
			}
		}

		return await base.GetEntityAsync( absoluteUri, role, ofObjectToReturn );
	}

	private static bool ShouldAttemptResourceLoad( Uri absoluteUri, Type ofObjectToReturn )
	{
		return ( absoluteUri.Scheme == Uri.UriSchemeFile && ofObjectToReturn == null || ofObjectToReturn == typeof( Stream ) || ofObjectToReturn == typeof( object ) );
	}

	private Stream GetSchemaStreamFromEmbeddedResources( string uriPath )
	{
		var schemaFileName = Path.GetFileName( uriPath );
		var schemaResourceName = _resourceAssembly.GetManifestResourceNames().FirstOrDefault( n => n.EndsWith( schemaFileName ) );
		if ( schemaResourceName != null )
		{
			return _resourceAssembly.GetManifestResourceStream( schemaResourceName );
		}
		return null;
	}

	private Task<object> GetSchemaStreamFromEmbeddedResourcesAsync( string uriPath )
	{
		return Task.Run( () => (object)GetSchemaStreamFromEmbeddedResources( uriPath ) );
	}

	private readonly Assembly _resourceAssembly;
}

When asked to find a file-based reference, this steps in and looks in embedded resources first for a file of the same name. Since the file could be namespaced anywhere in the resources, I opted to look for any resource in any namespace with the same file name. If it is there, it loads it, otherwise it defers to the base implementation. This means there is no easy way to override the embedded file with a local one; however, that could be redressed by calling the base implementation first and then only searching embedded resources if that failed.

Note that I also implemented the async methods. I am certain my implementation is a little naive, but it generally works. Just be careful if you allow this to be used asynchronously as I discovered you can very easily create a deadlock when used in conjunction with locks. This is not necessarily a caveat of my implementation, but of asynchronous programming in general.

Hopefully, others will find this useful. Let me know in the comments if you use this or something similar.