5,663,486 members and growing! (17,564 online)
Email Password   helpLost your password?
Web Development » ASP.NET » General     Advanced

Building and Consuming a Dynamic Sitemap in ASP.NET 2.0

By Thomas Kurek

You need to build a dynamic sitemap right from a dataset because you don't have static content on your website
Windows, .NET, Visual Studio, ASP.NET, Dev

Posted: 17 Sep 2006
Updated: 25 Sep 2006
Views: 51,921
Bookmarked: 52 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
10 votes for this Article.
Popularity: 3.38 Rating: 3.38 out of 5
1 vote, 10.0%
1
1 vote, 10.0%
2
4 votes, 40.0%
3
1 vote, 10.0%
4
3 votes, 30.0%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Sample Image - Breadcrumbs.jpg

Introduction

Sitemaps and breadcrumbs (SiteMapPath) are fantastic.  For a dynamic site, they can be crucial, since search engines are historically agnostic to QueryString driven content that is common for dynamic websites.  A sitemap can help search engines find this content and index it appropriately, expose breadcrumbs for users, and help users see in one place everything you have to offer them.

The out-of-the-box functionality for Sitemaps with ASP.NET 2.0 is fantastic.  Many of the complexities previously associated with them have been addressed; however, while implementing one for our system we faced a number of challenges which were not addressed by Microsoft.

My code and approach in this article will help you if you share any of the following motivations with me:

  • You are using a hierarchical DataSet to generate the tree for your dynamic content which would feed a sitemap
  • You want to generate the XML needed for the ASP.NET SiteMap datasource straight from the DataSet in a fast way that minimizes lines of code
  • Your content management system is large enough to vote against simply generating this DataSet on every web request (remember it feeds breadcrumbs on all your pages) or filling up your server cache with this huge object that represents all the content in your system - thus you want a static XML SiteMap file that is updated every day (or at a frequency that you define)
  • You want to backup your XML SiteMap files for maintenance or just safety
  • You have multiple content sections in your dynamic CMS that are different trees - meaning your pages are context sensitive and would feed off of separate sitemaps in the same web application
  • You want to learn how to do an XSLT in memory in .NET 2.0
  • You want to learn how to use embedded resource files in .NET 2.0
  • You just want to see the XSLT that can turn a hierarchical DataSet into a *.sitemap file
  • You want to see how to handle identical Urls in the sitemap (which is forbidden by the out-of-the-box SiteMapProvider)

 Step 1: Identify your naming convention

To begin, you must define your naming convention for your XML file.  As this is an automated process you want to shield the client from thinking of its inner workings.  In my case, I needed 3 components to uniquely identify my sitemaps:

ApplicationID (the ID for the web application of interest)
CultureName (the culture name for the current content i.e. en-US or en-GB)
SitemapType (the content tree that uniquely identifies groups of content for separation)

I have the following Fields in my Sitemap class:

#region Private Field Declarations

private Guid applicationId;

private string cultureName;

private DataSet dataSource;

private byte maxTiers;

private SitemapType type;

private string Id;

private string fileName;

//Can be modified for your data structure - recommend repeating the construct for Tables.Count - 1

private object[,] heirarchicalRelations = new object[,] { { new string[] { "ID" }, new string[] { "ParentID" } }, { new string[] { "ID" }, new string[] { "ParentID" } }, { new string[] { "ID" }, new string[] { "ParentID" } }, { new string[] { "ID" }, new string[] { "ParentID" } } };

#endregion

 The enumeration:

/// <summary>

/// This distinguishing property allows you to define multiple content areas within one

/// web application. Then you can call out the appropriate SiteMapProvider for different

/// path contexts in a single web application.

/// </summary>

public enum SitemapType

{

/// <summary>

/// A sitemap that lists all of the informational content in the system

/// </summary>

Content = 0,

/// <summary>

/// A sitemap that lists all of the properties and areas in the system

/// </summary>

Property = 1,

}


The constructor builds the ID and the file name (I don't need the application ID in the filename because the files are stored within directories in their own application anyway).  We use camel-cased naming conventions for private fields and Pascal cased naming conventions for public properties in our software.  I have omitted the public Properties, but you can see that below they correspond to the private fields.  ToString("G") formats to an enum's name.

/// <summary>

/// Generates a Sitemap from its Type, application ID, and requested culture

/// </summary>

/// <param name="appId">The unique ID for the application that the sitemap belongs to</param>

/// <param name="cName">Defines the culture that the client would like to view the sitemap in. The application must support that culture. The standard abbreviation string must be used.</param>

/// <param name="sType">The sitemap type that should be generated</param>

public CMSSitemap(Guid appId, string cName, SitemapType sType)

{

this.ApplicationID = appId;

this.CultureName = cName;

this.Type = sType;

StringBuilder pathBuilder = new StringBuilder(this.Type.ToString("G"));

pathBuilder.Append("_");

pathBuilder.Append(this.CultureName);

pathBuilder.Append(".sitemap");

this.FileName = pathBuilder.ToString();

StringBuilder IdBuilder = new StringBuilder(this.ApplicationID.ToString());

IdBuilder.Append("_");

IdBuilder.Append(this.Type.ToString("G"));

IdBuilder.Append("_");

IdBuilder.Append(this.CultureName);

this.ID = IdBuilder.ToString();

BSData helper = new BSData();

SqlParameter p_applicationId = new SqlParameter("@ApplicationID", SqlDbType.UniqueIdentifier, 16, ParameterDirection.Input, false, ((Byte)(18)), ((Byte)(0)), "", DataRowVersion.Current, appId);

SqlParameter p_cultureName = new SqlParameter("@CultureName", SqlDbType.VarChar, 10, ParameterDirection.Input, false, ((Byte)(18)), ((Byte)(0)), "", DataRowVersion.Current, cName);

SqlParameter p_sitemapType = new SqlParameter("@SitemapType", SqlDbType.TinyInt, 3, ParameterDirection.Input, false, ((Byte)(18)), ((Byte)(0)), "", DataRowVersion.Current, sType);

SqlParameter[] param = new SqlParameter[3] { p_applicationId, p_cultureName, p_sitemapType };

this.DataSource = helper.ReadOnlyHeirarchicalQuery(helper.BWEnterpriseReader,

"dbo.[proc_getSitemapData]", this.heirarchicalRelations, param);

this.modifyDuplicateUrls();

this.MaxTiers = (byte)this.DataSource.Tables.Count;

}

Step 2: Take Care of Your Hierarchical Data

About our data layer (most likely you have your own methods, so populating your dataset is up to you).  We use Stored Procedures exclusively to form the foundation of our Data Layer.  They are called through ADO.NET helper methods where connections to the DB are isolated and encapsulated.  They filter DataSets back to the business layer after building them.  The method above, "ReadOnlyHeirarchicalQuery" will build a Hierarchical DataSet with DataRelations.

This private field heiarchicalRelations is questionable right now.  In order to allow the client to call that method and define multiple parent-child columns, I used an object[,] (you can have multiple-column PKs & FKs).  This has the drawback of requiring the caller to know how many tiers will come back to form the DataRelations.  If I were to restrict the DataSet to have Parent and Children ID colums named the same thing exclusively, I could have a more confined but elegant solution, because I could generate the DataRelations on the fly based on how many DataTables came back from SQL.  In this new scenario, the caller does not need to know how many DataRelations must be built.  I will do this before release because our tiers are fluctuating now.

I know that you can manage your own hierarchical DataSets with your own methods, but I have provided this information to you as a proof of concept for my work.

Useful fact from a Microsoft conference - I did not give you the real name of my sproc up there, but notice that I prefix it with proc_.  You should not prefix your sprocs with sp_ because when you do so, you slow down your entire data layer because SQL will search all of the system stored procedures before finding your sproc.

The method I call in the constructor is shown below for your reference:

/// <summary>

/// Allows for execution of multiple-select statements with one sproc, and heirarchical datasets with auto-creation of relations

/// </summary>

/// <param name="comPathString">Connection string to the DB</param>

/// <param name="sprocName">Name of sproc to execute</param>

/// <param name="dataRelations">Each object must be a string[], with column 0 of the multi-dimensional object[] being the string[] of Parent Column Names, and column 1 being the string[] of Child Column Names.

/// This construct is required to support multi-column PK and FKs</param>

/// <param name="paramList">Parameter array for the stored procedure</param>

/// <returns>Heirarchical DataSet</returns>

internal DataSet ReadOnlyHeirarchicalQuery(string comPathString, string sprocName, object[,] dataRelations, SqlParameter[] paramList)

{

SqlConnection comPath = new SqlConnection(comPathString);

SqlCommand executeSproc = new SqlCommand(sprocName,comPath);

executeSproc.CommandType = CommandType.StoredProcedure;

foreach (SqlParameter p in paramList)

{

executeSproc.Parameters.Add(p);

}

DataSet finalResultSet = new DataSet("finalResultsDS");

try

{

comPath.Open();

SqlDataReader readSprocResults = executeSproc.ExecuteReader();

do

{

finalResultSet.Tables.Add();

foreach(DataRow r in readSprocResults.GetSchemaTable().Rows)

{

finalResultSet.Tables[finalResultSet.Tables.Count-1].Columns.Add(r[0].ToString(),Type.GetType(r[12].ToString()));

}

while (readSprocResults.Read())

{

addRow = finalResultSet.Tables[finalResultSet.Tables.Count-1].NewRow();

foreach (DataColumn c in finalResultSet.Tables[finalResultSet.Tables.Count-1].Columns)

{

addRow[c.Ordinal] = readSprocResults[c.Ordinal];

}

finalResultSet.Tables[finalResultSet.Tables.Count-1].Rows.Add(addRow);

}

}

while (readSprocResults.NextResult());

comPath.Close();

for (int i=0;i<=dataRelations.GetUpperBound(0);i++)

{

string[] parents = (string[])dataRelations[i,0];

string[] children = (string[])dataRelations[i,1];

DataColumn[] pc = new DataColumn[parents.Length];

DataColumn[] cc = new DataColumn[parents.Length];

for (int j=0;j<parents.Length;j++)

{

pc[j] = finalResultSet.Tables[i].Columns[parents[j]];

}

for (int j=0;j<children.Length;j++)

{

cc[j] = finalResultSet.Tables[i+1].Columns[children[j]];

}

DataRelation tempDR = new DataRelation("", pc, cc);

tempDR.Nested = true;

finalResultSet.Relations.Add(tempDR);

}

}

catch (Exception e)

{

comPath.Close();

throw new ApplicationException(e.Message);

}

return finalResultSet;

}

The only thing to note here if you are handling your own DataSet - the name of the DataSet is finalResultsDS.  Remember that for the XSLT.

Step 3: Handle Duplicate Urls

One last step to initialize the data of your class - this.modifyDuplicateUrls();

I have a problem in my site hierarchy - the business users want to be able to categorize content in multiple places at times.  This feeds the menu system as well.  You can handle this another way - when you generate the DataSet - only choose one path for the content.  In my case, this was not an option.  The users want to see the content show up in the hierarchy that they defined.

Why does this pose as a problem?  Think about what the SiteMap classes in the .NET framework must do to generate breadcrumbs - the HttpRequest defines a Url to hit, and now your SiteMapProvider has to figure out, well, "Where in the hierarchy does this Url correspond to."  If there is more than one option, how does it know which path you meant?  And then how does it generate breadcrumbs when your paths are not mutually exclusive?  Exactly.  It can't.  You would need to write your own SiteMapProvider which has logic that makes decisions in that instance.  I don't have time for that.  I just wanted to keep the SiteMap Data Hierarchy's integrity, as defined by the business users, but still use the built in Provider.  I did not want to forgo the optimizations and fine code given to me by Microsoft's built in provider.  I simply did not see the need to invest that much time.

I achieved my goal by tricking it with a QueryString parameter.  I keep the original Url the first time it is seen in the hierarchy.  For duplicates I add a dummy QueryString Parameter that can be used to distinguish them.  I do the same for my menuing system hierarchy so that the breadcrumbs match the menus.  Yet still, if a user externally linked one of our pages, my CMS can resolve the content they want to get without a problem by providing a fallback.  That is out of the scope of this article and begins to get into my custom CMS which is very powerful, multi-lingual system.  All you need to know is that this method will allow you to trick the default SiteMapProvider into behaving how I needed it to for my requirements.  The following method does the trick:

/// <summary>

/// SiteMap datasources cannot have duplicate Urls with the default provider.

/// This finds duplicate urls in your heirarchy and tricks the provider into treating

/// them correctly

/// </summary>

private void modifyDuplicateUrls()

{

StringCollection urls = new StringCollection();

string rowUrl = String.Empty;

uint duplicateCounter = 0;

string urlModifier = String.Empty;

foreach (DataTable dt in this.DataSource.Tables)

{

foreach (DataRow dr in dt.Rows)

{

rowUrl = (string)dr["Url"];

if (urls.Contains(rowUrl))

{

duplicateCounter++;

if (rowUrl.Contains("?"))

{

urlModifier = "&instance=" + duplicateCounter.ToString();

}

else

{

urlModifier = "?instance=" + duplicateCounter.ToString();

}

dr["Url"] = rowUrl + urlModifier;

}

else

{

urls.Add(rowUrl);

}

}

}

}

}


Step 4: Write your XSLT and Embed it in your Class Library

You need an XSLT to get your *.sitemap files into the right format straight from your DataSet.  I have shown you below example DataSet.GetXML() output, the XSLT to transform it, and the resulting *.sitemap file.  I have only included truncated snippets of the input and output for brevity.  If you have a different naming convention for your DataSets and DataTables you will have to modify the XSLT accordingly.  These files are included in the source code download.

Input XML generated from DataSet.GetXML()

 
 
<FINALRESULTSDS>
 <TABLE1>
  <ID>3efae161-e807-4419-98d5-162f69cca7da</ID> 
   
  <DESCRIPTION>Find and reserve corporate housing and serviced apartments anywhere in the world. - Find and Reserve</DESCRIPTION> 
  <URL>~/Apps/AdvancedPropertySearch.aspx?CM=2441358F-1E9D-4694-8E82-9E4FB4E6AD16</URL> 
  <ITEMORDER>0</ITEMORDER> 
 <TABLE2>
  <ID>8115e4ef-153b-4b11-85bd-5e0a10d16c59</ID> 
  <PARENTID>3efae161-e807-4419-98d5-162f69cca7da</PARENTID> 
   
  <DESCRIPTION>Reservation Request</DESCRIPTION> 
  <URL>~/Apps/ReservationRequest.aspx</URL> 
  <ITEMORDER>0</ITEMORDER> 
  </TABLE2>
  </TABLE1>
 <TABLE1>
  <ID>4d60e90d-8ede-4e52-88c9-65b9416ff02a</ID> 
   
  <DESCRIPTION>Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Accommodations Solutions</DESCRIPTION> 
  <URL>~/Apps/CMSTemplate.aspx?CM=4B042082-E8CB-4A34-A589-936F3642F7A1</URL> 
  <ITEMORDER>1</ITEMORDER> 
 <TABLE2>
  <ID>6e49589e-3743-4ded-a718-41a615a5c4f0</ID> 
  <PARENTID>4d60e90d-8ede-4e52-88c9-65b9416ff02a</PARENTID> 
   
  <DESCRIPTION>Temporary housing for extended stays and business travel by BridgeStreet Worldwide corporate housing and serviced apartments. - Business Travelers</DESCRIPTION> 
  <URL>~/Apps/CMSTemplate.aspx?CM=64DA181A-7A9E-4811-AC0D-7A0C89827F28</URL> 
  <ITEMORDER>0</ITEMORDER> 
  </TABLE2>
 <TABLE2>
  <ID>ce5614cb-c8b4-449c-a494-8c91b3bb3328</ID> 
  <PARENTID>4d60e90d-8ede-4e52-88c9-65b9416ff02a</PARENTID> 
   
  <DESCRIPTION>Extended stay accommodations for military personnel and government travelers through BridgeStreet Worldwide corporate housing and serviced apartments. - Government Travelers</DESCRIPTION> 
  <URL>~/Apps/CMSTemplate.aspx?CM=6EF08802-4023-4F81-8C1E-1C3D9B4CEA86</URL> 
  <ITEMORDER>1</ITEMORDER> 
  </TABLE2>


XSLT.  You can see that it supports 6 levels deep for your hierarchy.  You can add more if you need to.  Or I'm sure there's a better way to do this with recursion, but my strength is not XSLT so if someone out there can show a more elegant way to perform this, which does not require a limited level of nesting, please chime in on the comments.  In the meantime, this will do the job, and it does it well:

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:apply-templates />

</xsl:template>

<xsl:template match="/finalResultsDS">

<xsl:element name="siteMap" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<!-- First Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

<!-- Second Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

<!-- Third Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

<!-- Fourth Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

<!-- Fifth Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

<!-- Sixth Table in Heirarchy -->

<xsl:for-each select="./*[starts-with(local-name(), 'Table')]">

<xsl:element name="siteMapNode" namespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<xsl:call-template name="transformElementsToAttributes" />

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:for-each>

</xsl:element>

</xsl:template>

<xsl:template name="transformElementsToAttributes">

<xsl:attribute name="url">

<xsl:value-of select="Url"/>

</xsl:attribute>

<xsl:attribute name="title">

<xsl:value-of select="Title"/>

</xsl:attribute>

<xsl:attribute name="description">

<xsl:value-of select="Description"/>

</xsl:attribute>

</xsl:template>

</xsl:stylesheet>

Oh La la, I have shown you below the French Sitemap that is output from my fun class.  This is the end product:

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

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">

<siteMapNode url="/Default.aspx" title="Accueil" description="Accueil">

<siteMapNode url="~/Apps/AdvancedPropertySearch.aspx?CM=00CB5839-329F-4692-9A60-2D4A389DD6DB" title="Rechercher et R‚server" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Rechercher et R‚server">

<siteMapNode url="~/Apps/ReservationRequest.aspx" title="Demande de R‚servation" description="Demande de R‚servation" />

</siteMapNode>

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=1EBB6235-4174-437C-B23F-31B9E58E4FC0" title="Solutions de Logement" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Solutions de Logement">

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=09258BB3-66A3-4600-8ADF-4237E70CC0EA" title="R‚sidences H“teliŠres" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - R‚sidences H“teliŠres" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=B56EE30D-9168-4CE7-8968-AA395175DAD9" title="Locations" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Locations" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=A7C67AFF-89DB-4D1E-BDD4-E42E50A71AE5" title="Services D’assistance au D‚m‚nagement /Relocation" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Services D'assistance au D‚m‚nagement/Relocation" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=62DA6B92-D1E2-4AC3-A460-67C14086871C" title="Voyages de Loisirs" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Voyages de Loisirs" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=40ECF480-0ECA-4121-AB28-E1CC886E419E" title="Achat / Vente" description="Propositions d'appartements … vendre sur Paris - Achat / Vente" />

</siteMapNode>

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=3093CA21-5CB4-4EDF-9C46-F0E6C8ED922F" title="Pourquoi des R‚sidences H“teliŠres" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Pourquoi des R‚sidences H“teliŠres ?">

<siteMapNode url="~/Apps/FAQ.aspx" title="FAQ" description="FAQ" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=0F626C88-6ABC-4B7F-8F71-5055184F7030" title="Am‚nagements &amp; Services" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Am‚nagements &amp; Services" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=22D5A46E-9EEF-44F9-9B61-AD80E776186C" title="À Quoi Vous Attendre" description="Grand choix d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - À Quoi Vous Attendre" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=B1F35382-ED7C-400F-970C-B620D14590C5" title="T‚moignages" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - T‚moignages" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=8A2B0A11-74AD-4551-96EF-C13428E3E227" title="R“le Dans le Secteur" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - R“le Dans le Secteur" />

</siteMapNode>

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=25D55721-C606-4C42-8F98-7EDBABABA819" title="Qui Sommes-nous" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Qui Sommes-nous">

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=9D112AFA-7759-49FD-851D-51F1008ACF9F" title="Distinction Honorifique" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Distinction Honorifique" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=E3DB47D4-B255-4D98-BE18-75710EEDC265" title="Notre Culture" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Notre Culture">

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=62C3EE6C-535F-48B3-98D3-36C7005E563D" title="Valeurs/ Mission" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Valeurs &amp;amp; Mission" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=9F1FF39F-B1C2-4306-855E-EAE221FC74A9" title="Notre Promesse" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Notre Garantie de Satisfaction" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=6FCD4B03-718E-4D99-BE42-8623C86F639B" title="BridgeCare" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - BridgeCare" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=4401C4EC-0FF8-4FE5-9924-2251BA0DBFD6" title="Nos Collaborateurs" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Nos Collaborateurs" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=3237E7F6-F732-4F24-9E65-C761B0AE8800" title="CarriŠres" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - CarriŠres" />

</siteMapNode>

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=885399BD-44A4-4720-8C75-F6521ED3A2D4" title="Partenariat Mondial" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Partenariat Mondial">

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=2E1B9DAA-A2AC-48CD-8716-2EF113E71973" title="BridgeNet Login" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Bienvenue … Nos Partenaires Mondiaux" />

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=1B27D0CC-53C5-4A78-A5E0-BD4AA8A51C94" title="BridgeStreet Global Alliance" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - BridgeStreet Global Alliance" />

</siteMapNode>

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=ADAF636D-0481-4ECC-B918-4BBF1D11FD4E" title="Des Solutions Faciles Pour L’h‚bergement D’affaires" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Des Solutions Faciles Pour L’h‚bergement D’affaires">

<siteMapNode url="~/Apps/CMSTemplate.aspx?CM=5295303A-1EEA-4FF5-A913-2842540F0762" title="Programmes Tech" description="Solutions d'h‚bergement en appartements meubl‚s avec services h“teliers pour tous types de s‚jour : courts s‚jours, s‚jours professionnels, d‚menagement, relocation - Programmes Tech" />

</siteMapNode>

<siteMapNode url="~/Apps/Announcements.aspx?CM=50C83AAB-76F1-4BB9-88BA-720A116286BA" title="Actualit‚ de L’entreprise" description="Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Corporate News - September 7, 2006">

<siteMapNode url="~/Apps/ClientNewsletter.aspx?CM=814DD7F3-CE82-45E7-8CB0-1955E157F7A6" title="Newsletter de L’entreprise" description="Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Client Newsletter - Q3 2006">

<siteMapNode url="~/Apps/ClientNewsletter.aspx?CM=295E14E8-2B3C-A4E6-6534-19508E03700E" title="Q2 2006 Client Newsletter" description="Luxury serviced accommodations for both short term and extended stay letting periods throughout London and its surrounding areas in England, by BridgeStreet Serviced Apartments UK. - Client Newsletter - Q2 2006" />

<siteMapNode url="~/Apps/ClientNewsletter.aspx?CM=814DD7F3-CE82-45E7-8CB0-1955E157F7A6&amp;instance=5" title="Q3 2006 Client Newsletter" description="Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Client Newsletter - Q3 2006" />

<siteMapNode url="~/Apps/ClientNewsletter.aspx?CM=89B1D5B2-CECA-445E-99E7-31827CCA5D68" title="Fall/Winter 2005 Client Newsletter" description="Fall/Winter 2005 Client Newsletter - Client Newsletter - Fall/Winter 2005" />

<siteMapNode url="~/Apps/ClientNewsletter.aspx?CM=40753C0C-C80A-4FA9-B926-DC077C30EAD9" title="Q1 2006 Client Newsletter" description="Q1 2006 Client Newsletter - Client Newsletter - Q1 2006" />

</siteMapNode>

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B11F-2B3C-A4E6-6126-05FAD803B16D" title="BridgeStreet Worldwide's Global Partners Expand Company's West Coast Presence" description="BridgeStreet Worldwide's Global Partners Expand Company's West Coast Presence - Company Enters Pacific Northwest and San Francisco Markets - Corporate News - November 16, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B17D-2B3C-A4E6-6098-06F29E5EF2F3" title="BridgeStreet Worldwide Receives 2005 Technology ROI Award" description="BridgeStreet Worldwide Receives 2005 Technology ROI Award - Winners Use Technology Solutions to Achieve Positive Business and Financial Results - Corporate News - August 17, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B0E1-2B3C-A4E6-6183-0A4E10FFF887" title="BridgeStreet Worldwide Announces Corporate Housing Partnership With AMLI Residential" description="BridgeStreet Worldwide Announces Corporate Housing Partnership With AMLI Residential - - Corporate News - January 23, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B352-2B3C-A4E6-6EC6-0C181C2644D3" title="BridgeStreet's Licensed Global Partner Program Signs First Three Partners" description="BridgeStreet's Licensed Global Partner Program Signs First Three Partners - - Corporate News - March 17, 2003" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B19C-2B3C-A4E6-6C44-1198E3258BAA" title="BridgeStreet Worldwide and Global Partner Furnished Quarters Expand Florida Presence" description="BridgeStreet Worldwide and Global Partner Furnished Quarters Expand Florida Presence - Four New Locations Enlarge Florida Corporate Housing Inventory - Corporate News - July 20, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B333-2B3C-A4E6-61C3-174EAD2204B5" title="BridgeStreet Corporate Housing Acquires Circus Apartments in London's Canary Wharf" description="BridgeStreet Corporate Housing Acquires Circus Apartments in London's Canary Wharf - - Corporate News - March 25, 2003" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=485AE1BD-2B3C-A4E6-6C50-1BE7D65A9A0E" title="BridgeStreet Worldwide Launches Luxury SleepEasy&lt;sup&gt;sm&lt;/sup&gt; Bedding Package" description="BridgeStreet Worldwide Launches Luxury SleepEasy&lt;sup&gt;sm&lt;/sup&gt; Bedding Package - Homelike, High-Comfort Bedding Offered in Corporate Apartments Nationwide - Corporate News - April 19, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B1BC-2B3C-A4E6-6359-20EDB45507C7" title="BridgeStreet Worldwide Unveils Totally Revamped Web Site" description="BridgeStreet Worldwide Unveils Totally Revamped Web Site - Enhanced BridgeStreet.com Another Step in - Corporate News - June 21, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=485AE0F2-2B3C-A4E6-6836-2A26ECBEC7D6" title="BridgeStreet Worldwide Expands Locations Throughout Europe" description="BridgeStreet Worldwide Expands Locations Throughout Europe - Corporate Housing Leader Launches Global Alliance Program in Europe - Corporate News - May 18, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B313-2B3C-A4E6-69ED-303D12EF12E6" title="BridgeStreet Corporate Housing Names Lee Curtis President" description="BridgeStreet Corporate Housing Names Lee Curtis President - Thomas Vincent to Retire - Corporate News - August 21, 2003" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B2F4-2B3C-A4E6-6CE2-53F9F0068FD8" title="BridgeStreet Chicago Office Receives Second Consecutive “CAMME Award” From Chicagoland Apartment Association" description="BridgeStreet Chicago Office Receives Second Consecutive “CAMME Award” From Chicagoland Apartment Association - Company Cited for “Best Corporate Housing Program” - Corporate News - October 7, 2003" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B1FA-2B3C-A4E6-6ECC-5452707B7C2F" title="BridgeStreet Worldwide Sweeps Corporate Housing 'Tower of Excellence' Awards" description="BridgeStreet Worldwide Sweeps Corporate Housing 'Tower of Excellence' Awards - Named Corporate Housing Provider of the Year-Company, Most Creative Marketing, Volunteer of the Year and Provider of the Year-Individual - Corporate News - February 24, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B3B0-2B3C-A4E6-6C80-5726A19B1D1A" title="BridgeStreet Announces Innovative Licensing Program, First in the Corporate Housing Industry" description="BridgeStreet Announces Innovative Licensing Program, First in the Corporate Housing Industry - Program Provides Regional Corporate Housing Companies with Global Reach - Corporate News - April 29, 2002" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B258-2B3C-A4E6-6E56-67E3945C46FC" title="BridgeStreet Worldwide Named to Manage Serviced Apartments at Heathrow Airport" description="BridgeStreet Worldwide Named to Manage Serviced Apartments at Heathrow Airport - Berkeley Park at Heathrow Airport Adds Key Location to BridgeStreet Inventory - Corporate News - October 6, 2004" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B239-2B3C-A4E6-6AA5-6F3B6EE62301" title="BridgeStreet Chicago Office Receives Third Consecutive " description="BridgeStreet Chicago Office Receives Third Consecutive - Company Cited for Best Corporate Housing Program - Corporate News - November 16, 2004" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=50C83AAB-76F1-4BB9-88BA-720A116286BA&amp;instance=4" title="BridgeStreet Worldwide Surpasses 100 Market Milestone" description="Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Corporate News - September 7, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B277-2B3C-A4E6-6EBF-7DFAAA9E6920" title="BridgeStreet Worldwide’s Global Partner Program Expands to Seven Additional Markets" description="BridgeStreet Worldwide’s Global Partner Program Expands to Seven Additional Markets - New Toronto-Based Partner Largest Corporate Housing Provider in Canada - Corporate News - September 9, 2004" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B2D5-2B3C-A4E6-619B-8D19BDADD24E" title="BridgeStreet Corporate Housing Adds Six Partners to Global Licensing Program" description="BridgeStreet Corporate Housing Adds Six Partners to Global Licensing Program - Program Now Has 14 Partners, Representing 16 Markets - Corporate News - December 9, 2003" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B1DB-2B3C-A4E6-6C72-91B88C499D7E" title="BridgeStreet Worldwide Announces Annual BridgeCare Award Winner" description="BridgeStreet Worldwide Announces Annual BridgeCare Award Winner - Exceptional Customer Service Programs Are The Foundation to 'Making Corporate Housing Easy' - Corporate News - May 3, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B0C2-2B3C-A4E6-649F-932C513A5FF0" title="BridgeStreet Worldwide Acquires Twelve Oaks Corporate Housing in Chicago" description="BridgeStreet Worldwide Acquires Twelve Oaks Corporate Housing in Chicago - BridgeStreet Becomes One of the Windy City's Largest Furnished Apartment Providers - Corporate News - February 23, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B100-2B3C-A4E6-68EE-98F88CA1AE79" title="Bridgestreet Worldwide expands into Leeds, England, with the addition of 'Residence 6'" description="Bridgestreet Worldwide expands into Leeds, England, with the addition of 'Residence 6' - Brand New Luxury Serviced Apartments Opening in Leeds City Centre in April 2006 - Corporate News - December 15, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=485AE18F-2B3C-A4E6-6051-A38982308707" title="BridgeStreet Worldwide and Global Partner, Furnished Quarters, Enter Boston Market " description="BridgeStreet Worldwide and Global Partner, Furnished Quarters, Enter Boston Market - Corporate Housing Available in Nine Boston Locations, Downtown and Suburbs - Corporate News - May 8, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B219-2B3C-A4E6-65C2-BA4CCFEB2F9C" title="BridgeStreet Takes Next Step in “Corporate Housing Made Easy” Mission" description="BridgeStreet Takes Next Step in “Corporate Housing Made Easy” Mission - Unveils New Global Affinity Program to Augment Global Partners - Corporate News - January 20, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B15E-2B3C-A4E6-66F2-BC69BEB0B1E3" title="BridgeStreet Worldwide Partners with Rebuilding Together to Help Less Fortunate" description="BridgeStreet Worldwide Partners with Rebuilding Together to Help Less Fortunate - BridgeStreet Associates, Global Partners, Vendor Partners Restore Home - Corporate News - October 13, 2005" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B371-2B3C-A4E6-6068-C1F3077D51ED" title="BridgeStreet Announces Strategic Alliance With Global Home Network" description="BridgeStreet Announces Strategic Alliance With Global Home Network - Combined Housing Inventory Extends to 135 Markets in More Than 40 Countries - Corporate News - June 18, 2002" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=75B64AC5-22AD-4DFF-A067-D630E949D723" title="New Orleans to be Flooded Again-Not with Water, But with Bedding and Housewares from BridgeStreet" description="Temporary housing for extended stays by BridgeStreet Worldwide corporate housing and serviced apartments. - Corporate News - August 28, 2006" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=D596B2B6-2B3C-A4E6-6219-DB3879E4083B" title="BridgeStreet Corporate Housing Adds Five Partners to Global Licensing Program" description="BridgeStreet Corporate Housing Adds Five Partners to Global Licensing Program - - Corporate News - January 30, 2004" />

<siteMapNode url="~/Apps/Announcements.aspx?CM=485AE1EC-2B3C-A4E6-61EE-E9BDC5C11807" title="BridgeStreet Worldwide Wins Pair of Corporate Housing Awards" description="BridgeStreet Worldwide Wins Pair of Corporate Housing - Lee Curtis, BridgeStreet President, Named Individual Provider Member of the Year - Corporate News - March 27, 2006" />

<siteMapNode