Hosting A GeoRSS Feed

by Gong Liu April 29, 2009 18:17

A Brief Description of RSS 

RSS (Really Simple Syndication) is a Web content syndication format. It's a dialect of XML. All RSS files must conform to the XML 1.0 specification. RSS is standardized by RSS Advisory Board. The current RSS version is 2.0.1.

The following diagram illustrates how RSS works.

     How RSS Works

On the server side there must be a RSS document (which is called a "feed", "web feed", or "channel"). It usually has the name rss.xml, but it can be any name you choose. It includes one or more items, each of which describes a document (an article, a piece of news, a blog entry, etc.) on the website in such properties as title, summary, link to the document, authorship, publication date, etc. As new documents are added to the website, the RSS document is updated accordingly. The following is a sample RSS document.

sample RSS document

On the client side there is a RSS reader or aggregator, which is a piece of software that understands RSS format. The RSS reader can be a stand-alone application or a built-in feature of a web browser such as IE 7.0+ or Firefox. A user subscribes a RSS feed by telling the reader the URL of the feed. This is usually done by clicking a feed subscription link identified by the icon RSS or RSS. The user may subscribes multiple feeds from different websites. The RSS reader checks the user's subscribed feeds regularly for updates, and downloads them if any. When reading the feeds, the user has a number of options. He can choose to display all items or unread items only. He can sort items by date, title or author. He can filter items by categories.

In short, the main benefit of RSS is that a user can automatically get timely updates of multiple websites and view them in a centralized place.

From RSS to GeoRSS

GeoRSS is an extension of regular RSS. It adds geographic information, such as points, lines and polygons, to items. For example, if an item is about a set of photos you took on a trip and the locations of the photos are important, then you can add a latitude/longitude point to each photo. Or if an item is about a hiking trail and you want to show it on a map, then you need to add a geographic line to the item. Since GeoRSS is all about locations, it's only logical to show its content on an online map. Fortunately, all popular online maps, such as Google Maps, Virtual Earth and Yahoo Maps, support GeoRSS.    

The following diagram shows how GeoRSS works:

    How GeoRSS Works

Like RSS you will need a RSS document (rss.xml) on your website. However, at least some items in the rss.xml file must point to GeoRSS documents (e.g. Trip1.xml, Trip2.xml, etc), instead of regular HTML documents. If you use Google Maps to display geographic content, an item link will have this format:

http://maps.google.com/maps?q=full_url_of_your_georsss_doc

This tells Google Maps where the GeoRSS document is on your site for a particular item.

The flow of communications among the client, your website and Google Maps is as follows:

  1. The client requests the rss.xml file
  2. Your website returns the rss.xml file
  3. When the client clicks an item link, he is taken to Google Maps with the URL of corresponding GeoRSS document as a query string
  4. Google Maps fetches the GeoRSS document from your website
  5. Google Maps draws the geographic content on a map and returns it to the client.

For performance purpose, Google Maps will cache your feed and update the cache approximately once an hour. So if you change anything in your GeoRSS document, don't expect it reflectes on the map right away.

Currently, there are two primary GeoRSS encoding methods, GeoRSS GML and GeoRSS Simple. Please refer to georss.org for more information. If your feed only has a few points, you can probably create your GeoRSS document by hand. But if there are a lot of points involved, you will definitely need a GPS logger of some kind to record the points, and a software program to write the points to a GeoRSS document. In the following example. I used Pharos GPS Logger to record location data and generate GeoRSS (Simple) documents.  

An Example 

Let's say you have a website Fun*tastic Trips, dedicated to various trips you made, hiking trips, biking trips, boating trips, etc. Since the site is going to be updated frequently with new trips, you want to provide a GeoRSS feed for your site users. A user can subscribe the GeoRSS feed by clicking the link identified by the iconGeoRSS. The rss.xml file that the subscription link points to may look like this:

sample RSS document

In this particular rss.xml file, there are only two items. One item is a simple annocement (non-GeoRSS). The other item is about a trip and photos taken during the trip. The photo locations and trip route are described in the GeoRSS document trips0711011644-0711021015.xml, a portion of which is shown below:

sample GeoRSS document

Like a RSS document, a GeoRSS document also consists of one or more items. In this particular GeoRSS document, the first item represents the trip route. The latitude/longitude points that make up the route are enclosed in the georss:line tag. The rest of items represent photos taken during the trip. Each photo's location is given by the georss:point tag. The description tag of a photo item contains a HTML snip that shows thumbnail, caption, date/time, etc. of the photo. In Google Maps, each photo item is shown as a balloon icon and if the icon is clicked, a balloon window pops up showing the HTML snip in the description tag. 

Whenever you have a new trip, you need to do two things:

  1. Copy its GeoRSS document and associated files such as photos to your site (e.g. at http://twinsquares.com/apps/GeoRSS/content/)
  2. Add a new item to the rss.xml file with the item link pointing to the new GeoRSS document via Google Maps (like so http://maps.google.com/maps?q=full_url_of_your_georsss_doc ).

Subscribing and configuring a GeoRSS feed have no difference from subscribing and configuring a RSS feed. This article show how to subscribe and configure a RSS feed using the RSS reader built in IE 7.0+.

Viewing a GeoRSS feed is also as easy as viewing a RSS feed. The following set of screenshots illustrates the process for IE 7.0 RSS reader.

select GeoRSS feed
1) Select Fun*tastic Trips GeoRSS feed from a list of feeds subscribed

select GeoRSS item
2) Select a GeoRSS item to view on Google Maps (click the green arrow)

view GeoRSS feed on Google Maps
3) Feed content is shown on Google Maps. Notice the URL of the GeoRSS document in the search box.

Links and Downloads from the Example 

Using Formatting Functions with GridView/Template Field

by Gong Liu February 05, 2009 15:32

This article is also published on The Code Project

A TemplateField of a GridView control offers certain level of flexibility to combine data fields and format them for display. For example, we can use a TemplateField to display FirstName and LastName in a single GridView column, and even add a link to the combined column. However, if the formatting is too complex, using a formatting function with a TemplateField is the way to go.

Let's explore the ways to use formatting functions in the following example, where our data source is a table of POIs (points of interest) resulted from a spatial search, and the table includes these data fields:

  • POIName
  • Address
  • City
  • County
  • State
  • Zip
  • Country
  • Phone
  • CatCode (Category Code)
  • Latitude
  • Longitude
  • Distance (Distance from search center)

What we want to display to a user is (see screenshot at the end of this post):

  • The POIName field with a link to show the POI on Google Maps based on the POI's Latitude and Longitude fields
  • A single Address field which combines Address, City, County, State, Zip, and Country fields
  • The Phone field
  • The CatCode field
  • The Distance field

The first two fields are of particular interest. To display the POIName field with a link to Google Maps, we can use the following TemplateField:

<asp:GridView ID="gvwResults" runat="server" AutoGenerateColumns="False"
  EmptyDataText="No result found." CellPadding="2" EnableViewState="False">
  <Columns>
    <asp:TemplateField HeaderText="POI Name">
      <itemtemplate>
        <asp:LinkButton ID="LinkButton1" runat="server" title="map it"
          PostBackUrl="<%# GoGoogleMaps(Eval(&quot;Latitude&quot;),
          Eval(&quot;Longitude&quot;)) %>">
          <%# Eval("POIName") %>
        </asp:LinkButton>
      </itemtemplate>
    </asp:TemplateField>
    ......
  </Columns>
</asp:GridView>

The TemplateField contains a LinkButton server control. The LinkButton control's text is the POIName field, and its PostBackUrl attribute is bound to the formatting function GoGoogleMaps with Latitude and Longitude fields as input parameters. Notice that we have to use the xml entity &quot; to surround a data field name because we can't have double quotes within double quotes. The formatting function GoGoogleMaps looks like this in C#:

protected string GoGoogleMaps(object lat, object lon)
{
    if (Convert.IsDBNull(lat) || Convert.IsDBNull(lon))
        return null;
    else
        return string.Format(
            "http://maps.google.com/maps?f=q&hl=en&geocode=&q={0},{1}&z=15", lat, lon);
}

The Eval method of DataBinder class always evaluates a data field to an object and that's why we declare so for all parameters of the formatting function. The latitude and longitude fields of a POI could be null, and if so, we simply don't link it to Google Maps. Formatting rules like this would be hard to implement without a formatting function.

Instead of using a LinkButton control, we can also use a Literal control and construct the link ourselves within the formatting function. This way we have more control over the link's target and other aspects. 

<asp:TemplateField HeaderText="POI Name">
  <itemtemplate>
    <asp:Literal ID="Literal1" runat="server" Text=
      "<%# GetGoogleMapsLink(Eval(&quot;POIName&quot;),
      Eval(&quot;Latitude&quot;),
      Eval(&quot;Longitude&quot;)) %>">
    </asp:Literal>
  </itemtemplate>
</asp:TemplateField>

The corresponding formatting function GetGoogleMapsLink looks like:

protected string GetGoogleMapsLink(object poiName, object lat, object lon)
{
    string poi = (Convert.IsDBNull(poiName)) ? "Unknown POI" : (string)poiName;
    if (Convert.IsDBNull(lat) || Convert.IsDBNull(lon))
        return poi;
    else
        return string.Format(
            "<a href=\"#\" title=\"map it\" onclick=\"window.open(
            'http://maps.google.com/maps?f=q&hl=en&geocode=&q={0},{1}&z=15', 'GM')\">
            {2}</a>", lat, lon, poi);
}

The formatting function creates and returns a link that opens Google Maps in a separate browser window. It also handles the possibility of a null POIName field. If we compare the server generated pages from the above two ways (in a browser, right click the page and select View Source), we will see that the result of the second way is much more readable and less clustered.

Now let's see how we do about the combined Address field. The traditional way is to have a TemplateField with several Label controls, one for each address element, such as:

<asp:TemplateField HeaderText="Address">
  <itemtemplate>
    <asp:Label ID="Label1" runat="server" Text='<%# Bind("Address") %>'></asp:Label>,
    <asp:Label ID="Label2" runat="server" Text='<%# Bind("City") %>'></asp:Label>,
    <asp:Label ID="Label3" runat="server" Text='<%# Bind("County") %>'></asp:Label>,
    <asp:Label ID="Label4" runat="server" Text='<%# Bind("State") %>'></asp:Label>,
    <asp:Label ID="Label5" runat="server" Text='<%# Bind("Zip") %>'></asp:Label>,
    <asp:Label ID="Label6" runat="server" Text='<%# Bind("Country") %>'></asp:Label>
  </itemtemplate>
</asp:TemplateField>

Notice that we use commas to separate address elements from each other. This is all fine until we want a little bit formatting logic - we want to trim off any excess commas at both ends of the combined address string due to possible missing address elements. However, if an address element in the middle is missing, we'll still keep the extra comma. To do this we use a single Label control and bind its Text attribute to a formatting function that takes all the address fields as input parameters:

<asp:TemplateField HeaderText="Address">
  <itemtemplate>
    <asp:Label ID="Label1" runat="server" Text="<%# FormatAddress(
      Eval(&quot;Address&quot;),
      Eval(&quot;City&quot;),
      Eval(&quot;County&quot;),
      Eval(&quot;State&quot;),
      Eval(&quot;Zip&quot;),
      Eval(&quot;Country&quot;)) %>">
    </asp:Label>
  </itemtemplate>
</asp:TemplateField> 

where, the formatting function FormatAddress is:

protected string FormatAddress(object address, object city, object county,
    object state, object zip, object country)
{
    string addr = string.Format("{0},{1},{2},{3},{4},{5}", address,
        city, county, state, zip, country);
    return addr.Trim(",".ToCharArray());

An improvement over the above use of a formatting function with a TemplateField is that we can pass the entire data row to the formatting function in stead of individual data fields, especially when more than one or two data fields are involved. For instance, instead of passing 6 data fields in the above case, we can pass the current data row to FormatAddress:

<asp:TemplateField HeaderText="Address">
  <itemtemplate>
    <asp:Label ID="Label1" runat="server"
      Text="<%# FormatAddress(((System.Data.DataRowView)Container.DataItem).Row) %>">
    </asp:Label>
  </itemtemplate>
</asp:TemplateField>

Here, Container.DataItem returns a DataRowView object corresponding to the DataSource record bound to the GridViewRow. Its Row property returns a DataRow object. The new formatting function FormatAddress now looks like:

protected string FormatAddress(DataRow dr)
{
    string addr = string.Format("{0},{1},{2},{3},{4},{5}",
        dr["Address"], dr["City"], dr["County"], dr["State"], dr["Zip"], dr["Country"]);
    return addr.Trim(",".ToCharArray());

This is obviously a much cleaner way than passing multiple data fields. The following screenshot shows the GridView with search result of some airports and airport terminals near Los Angeles.

In conclusion, a formatting function is a great way to extent the power of TemplateField. It allows developers to implement complex formatting rules that usually involve multiple data fields and their interrelationships.

IE Context Menu Extension

by Gong Liu January 31, 2009 05:11

Years ago I stumbled upon the concept of IE Context Menu Extension. I created a menu extension to help me to lookup an online dictionary for any highlighted word. Here is how I use it. Wheneve I encounter an unfamiliar word while browsing the web, I just highlight the word, right click on it, and select a custom context menu item "Dictionary Lookup". This will launch a new browser window and take me straight to the online dictionary with the word already looked up. Without the extension I would have to do all this menually - highlight the word, right click, copy it, launch a new browser window, type in the URL of the online dictionary, paste the word, and press a Lookup button. So by comparison my little extension came in really handy. I have been using it ever since.

Over the years I added a few more items that I thought were also very useful. These include:

  • Google highlighted word or words
  • Map highlighted address
  • Lookup highlighted word in Wikipedia
  • Translate highlighted word in a different language
  • Share a web page on Facebook, Digg, etc.   

Now let's take a look at how to implement these extensions.

Google Highlighted Word or Words

We first need to create a HTML page and save it as, say, C:\MyScripts\IE_MenuExt\goto_google.htm. The HTML page contains just this javscript:

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var text = doc.selection.createRange().text;
    var url = "http://www.google.com/search?hl=en&q=" + escape(text);
    var w = window.open(url, "newwin");
    w.focus();
</script>

This script simply gets the highlighted text, creates a Google search URL out of it, and opens the URL in a new browser window. Another version of the script is to quote the highlighted text, which instructs the Google search engine to search the exact phrase:

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var text = doc.selection.createRange().text;
    var url = "http://www.google.com/search?hl=en&q=\"" + escape(trim(text)) + "\"";
    var w = window.open(url, "newwin");
    w.focus();
</script>

<script language="javascript">
//source: http://blog.stevenlevithan.com/archives/faster-trim-javascript
function trim(str) {
    var str = str.replace(/^\s\s*/, ''),
    ws = /\s/,
    i = str.length;
    while (ws.test(str.charAt(--i)));
        return str.slice(0, i + 1);
}
</script>

The only difference in this script from the first one is that the highlighted text is trimmed and quoted. The trim function is taken from Flagrant Badassery's blog.

The second step is to create the following registry key and save it to a .reg file, such as C:\MyScripts\IE_MenuExt\install.reg:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Google It]
@="file://C:\\MyScripts\\IE_MenuExt\\goto_google.htm"
"Contexts"=dword:00000010

The "Contexts" value 0x00000010 indicates that the context menu item "Google It" appears when you right click a highlighted (or selected) text in IE browser.

Map Highlighted Address

The script (C:\MyScripts\IE_MenuExt\goto_google_maps.htm):

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var text = doc.selection.createRange().text;
    text = trim(text).replace(/\n/, ", ");
    var url = "http://maps.google.com/maps?f=q&source=s_q&hl=en&q=" + escape(text);
    var w = window.open(url, "newwin");
    w.focus();
</script>

Since the highlighted address may be in multiple lines, the above script will replace any new line characters with commas to make it a single liner, and then feed it to Google Maps.

The registry key:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Map It]
@="file://C:\\MyScripts\\IE_MenuExt\\goto_google_maps.htm"
"Contexts"=dword:00000010

Note: when you use the "Map It" menu extension, make sure you only highlight the address part, not anything more. Otherwise, you may confuse the Goggle Maps geocoder.

Lookup Highlighted Word in Wikipedia

The script (C:\MyScripts\IE_MenuExt\goto_wikipedia.htm):

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var text = doc.selection.createRange().text;
    text = trim(text).replace(/ /, "_");
    var url = "http://en.wikipedia.org/wiki/" + text;
    var w = window.open(url, "newwin");
    w.focus();
</script>

The key point here is that if multiple words are highlighted, they need to be concatenated with an underscore "_". On Wikipedia site if an article is not found with the extact words, you will be presented with a link to search the words. So you don't need a separate menu item to search Wikipedia.  

The registry key:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Go Wikipedia]
@="file://C:\\MyScripts\\IE_MenuExt\\goto_wikipedia.htm"
"Contexts"=dword:00000010

Translate Highlighted Word in a Different Language

I have been teaching myself Spanish recently, and I find this Spanish online dictionary is very useful. It translates both ways, Spanish -> English and English -> Spanish. Now it becomes a permanent part of my menu extension collection.

The script (C:\MyScripts\IE_MenuExt\goto_spanish.htm):

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var theWord = doc.selection.createRange().text;
    var url = "http://www.spanishdict.com/translate/" + theWord;
    var w = window.open(url, "newwin");
    w.focus();
</script>

The registry key:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Spanish Lookup]
@="file://C:\\MyScripts\\IE_MenuExt\\goto_spanish.htm"
"Contexts"=dword:00000010

Share a Web Page on Facebook

If you find a web page interesting and want to share it on Facebook, Digg, Reddit, or whatever online community you belong to, you only need to click an approprate sharing icon (similar to those found at the end of this post) - if the page offers one. However, if the page does not have a sharing icon, you can use the following menu extension to do the trick.  

The script (C:\MyScripts\IE_MenuExt\goto_facebook.htm):

<script language="javascript" defer>
    var doc = external.menuArguments.document;
    var u = doc.URL;
    var t = doc.title;
    var url= "http://www.facebook.com/sharer.php?u=" + escape(u) + "&amp;t=" + escape(t);
    var w = window.open(url, "newwin");
    w.focus();
</script>

Note: here I only use Facebook as an example. If you are into other online communities, simply change the URL in the script. 

The registry key:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Share on Facebook]
@="file://C:\\MyScripts\\IE_MenuExt\\goto_facebook.htm"
"Contexts"=dword:00000001

The "Contexts" value 0x00000001 means the default context. I.e. the "Share on Facebook" context menu item appears when you right click anywhere on the page (except links, images, etc.). No highlighting text is necessary.

More Complex Example - Hook up a Sudoku Solver

The above menu extensions are really simple ones. In fact, we can hook up any program logic we like with a menu extension. For example, I like to go to my favorite Sudoku wbsite to get my brain teased. However, at times I got frustrated with some harder games and hoped to see them solved right away. So I hooked up a Sodoku solver I found here with a menu extension. Now whenever I have the urge to see the solution of a game, I just right click and select the solver (see screenshots below).

  

  

Install and Uninstall Menu Extensions

You can download all the javascript and registry key files discussed in this post below.

IE_MenuExt.zip (6.33 kb)

To install all the menu extensions, just copy the IE_MenuExt folder to C:\MyScripts\ and double click the install.reg file. Note: if you prefer a different installation location, you need to edit the install.reg file before running it.

To uninstall all the menu extensions, double click the uninstall.reg file. The uninstall.reg file looks like this:

REGEDIT4
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Dictionary Lookup]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Thesaurus Lookup]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Spanish Lookup]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Google It]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Google It quoted]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Go Wikipedia]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Map It]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Search Images]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Share on Facebook]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Digg It]
[-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\Sudoku Solver]

About

A seasoned computer professional. A tofu culture evangelist...
more >>

Tag Cloud

Calendar

<<  April 2017  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar
Copyright © 2008-2011 Gong Liu. All rights reserved. | credits | contact me
The content on this site represents my own personal opinions, and does not reflect those of my employer in any way.