Plotting Your Data Using Virtual Earth

Jon  Hello SharePoint Designer users,

My name is Jon Campbell – I’m a developer for the SharePoint Designer team. My main job is to work on all things data oriented in SharePoint Designer. Today I thought I would share a tip on how to take your data views to the next level by combining some custom XSL transforms on the server with JavaScript on the client. Specifically, this post will go through the steps of how to make a data view that will show a set of points stored in a data source, such as a SharePoint list, on a map using Virtual Earth.

We have an XML file that contains the data that we want to plot as pushpins on the Virtual Earth map. The data can come from any data source, but for the sake of simplicity an XML file will do the job. The most important aspect of the data is that it must have both latitude and longitude so that it can be plotted. Without a latitude and longitude we would need to use an address and geocode it to the equivalent coordinates, which is outside the scope of this post. Create an XML file called locations.xml and set the contents as follows:

<?xml version="1.0" encoding="utf-8" ?>


      <Location lat="47.760101" long="-122.205141" name="place 1" description="A nifty place." />

      <Location lat="47.255436" long="-122.51739" name="place 2" description="A place for fun!" />

      <Location lat="47.831876" long="-122.277658" name="place 3" description="More fun!" />


Next, we need to be able to show the Virtual Earth map on the page. The basic requirements for doing so are including the Virtual Earth map control, creating a div tag to show the content, and then adding a basic script to use the map control to place the map into the div tag. Create a new ASPX page and switch to code view. Put the following code inside the form tag:

<script src=""> </script>

    <script type="text/javascript">

      var map = null;

// Loads the Virtual Earth map control

      function GetMap()


      map = new VEMap('myMap');

      map.LoadMap(new VELatLong(47.6, -122.2), 8,'r' ,false);

      AddPin(47.7,-122.2,null,'place 1','A nifty place to be.');



// Places a pushpin on the map using the parameters given, iconurl is ignored

      function AddPin(lat, lon, iconurl, title, desc)


      var shape =

new VEShape(VEShapeType.Pushpin,

new VELatLong(lat,lon));





// Programmatically adds func as a handler for the onload event

// This method has been used by many developers, but the code is

// via the ViaVirtualEarth Wiki


      function addLoadEvent(func)


      var oldonload = window.onload;

      if (typeof window.onload != 'function')

      { window.onload = func; }


      { window.onload = function()

      { oldonload(); func(); }





    <div id='myMap' style="position:relative; width:400px; height:400px;"></div>

The last function, addLoadEvent(func), is used to run the map control’s code when the page is loaded without having to set the body tag’s onload event handler. This can be useful in situations where a master page is being used. If you preview the page, you should end up with a map like the one to the right.

Next you should insert a DataFormWebPart view of the locations.xml file that you created earlier. There are many methods for doing this, but the easiest way for what needs to be done is switch to design view and then drag it from the folders list and drop it onto the page. You can then switch back to code view. You should be able to find the XSL property of the DataFormWebPart that was created. Before the dvt_1 template, add the following XSLT:

<xsl:template name="AddMapPins">

    <xsl:param name="Rows"/>

    <xsl:text disable-output-escaping="yes"><![CDATA[

            <script type="text/javascript">

            function AddPins()



    <xsl:for-each select="$Rows">

      <xsl:if test="not(normalize-space(@lat) = '' and normalize-space(@long) = '')">

        AddPin(<xsl:value-of select="@lat" />,

        <xsl:value-of select="@long" />,


        '<xsl:value-of select="@name" />',

        '<xsl:value-of select="@description"/>');



    <xsl:text disable-output-escaping="yes"><![CDATA[





That XSLT code will iterate over each of the rows in the dataset and create individual calls to AddPin() inside the AddPins() function. The AddPin() function uses the latitude and longitude from the row in the dataset as well as the name and the description attributes.

There are a couple things which need to be done in order to hook up the DataFormWebPart to the JavaScript code. The first is that the AddMapPins template won’t get called yet. To ensure that it gets called, add the following lines inside the dvt_1 template immediately after the Rows variable.

<xsl:call-template name="AddMapPins">

  <xsl:with-param name="Rows" select="$Rows"/>


Next, change the AddPin(…) call in GetMap() to be a call to AddPins() . The resulting GetMap() function should look like this:

function GetMap()


      map = new VEMap('myMap');

      map.LoadMap(new VELatLong(47.6, -122.2), 8,'r' ,false);



If everything is correct then you should be able to preview the page and end up with the results shown in the screenshot to the right. This method demonstrates how client side script can be generated based on server side data using XSLT. Though JavaScript was used in this example, it is not unreasonable to imagine using this to drive other client side technologies like SilverLight. This won’t replace custom web parts, but it definitely opens up some interesting scenarios – especially for those in hosting scenarios or with limited posting privileges.