|
|
October 2000Create a breadcrumb for navigating Web pages with server-side XMLby Ford JamesHave you ever wanted to incorporate breadcrumb navigation capabilities on your pages like those used on some of the most popular sites on the Web? Breadcrumbs provide an intuitive, context-oriented way of keeping track of where you are and how you got there and can significantly simplify page navigation for those sites that deal with hierarchical information. Users appreciate the ability to go back to a previous page with one click and to see where they are with respect to the first page (or any logical starting point) in the site. Using a combination of XML and ASP, we'll show you how to incorporate this capability into your own Web site in a browser-independent way, allowing users to navigate between pages while maintaining virtually any state information you may want to save.
Why XML?XML provides a flexible, scaleable tool for traversing and maintaining a breadcrumb trail with minimal resource overhead. Because XML documents can easily be converted to (and built from) ASCII strings, they can be stored just about anywhere. The simplest and fastest approach for small, single-server sites is to use a session variable to store the XML string (though these should be used with care to conserve server resources). For Web farms and larger sites using multiple servers, this isn't as practical as session variables are local to each server. For these cases, the XML can be stored in a database, or even on the client machine using cookies. The additional round trip to the server may be worth scalability and the conservation of server memory for sites with a lot of traffic.
How it worksWhen a user first visits the site, the home page is sent to the browser and a session variable is created on the IIS server to hold the XML string between calls. When the user clicks on a link from the home page, the URL and parameters of the requesting page are stored as a node in an XML document object and assigned a title for display in the breadcrumb. Before the page is sent to the client, this XML document object is converted to an ASCII string via the XML property of the object and stored to the session variable. As users navigate through the Web site, this XML string is recalled and transformed back into an XML document object via the loadXML method. This allows us to easily move to any node in the XML document and access any associated data we wish to store with that node when a user is returning to a previously viewed page. Figure A shows how the breadcrumb might look using our example, while Listing A shows the XML representation of this breadcrumb. Figure A: Breadcrumbs enhance Web site navigation.
Listing A: The XML representation of the sample breadcrumb <Breadcrumb> <Page Title="Music" Link="/BreadCrumb/CrumbFirstChild.asp?Category=Music"> <Page Title="Jazz" Link="/BreadCrumb/CrumbSecondChild.asp?Category=Jazz"> <Page Title="JazzVocal" Link="/BreadCrumb/CrumbThirdChild.asp?Category=JazzVocal"/> </Page> </Page> </Breadcrumb> In our examples, we'll be storing only the URL and QueryString parameters of the calling page, but thanks to the extensibility of XML, you can store virtually any data you want with each XML node. When a user returns to a given page via the breadcrumb, and then changes some state information on the page (like the sort order for a list, or a value in a text field), the associated XML node is updated with the new information.
The heart of the crumbThe writeBreadCrumb function shown in Listing B is responsible for maintaining the breadcrumb and performing the XML conversion. This is where most of the real work is done, so let's take a look at the code. Listing B: The writeBreadCrumb function
<%
function writeBreadCrumb(strCurrentCrumbTitle)
Dim strCrumb
Dim strXMLCrumb
Dim xmlDoc
Dim objCurrNode
Dim objAttrib
Dim objChild
Dim strLink
Dim strTitle
Dim strReqLink
set xmlDoc = server.createObject("Microsoft.XMLDOM")
strXMLCrumb = session("breadcrumbXML")
'Get currently requested page with variables
strReqLink = request.serverVariables("URL") & _
"?" & request.serverVariables("Query_String")
If strXMLCrumb = "" then
strCrumb = "<a href=""CrumbMain.asp"">Home</a>" & _
" > "
strCrumb = strCrumb + strCurrentCrumbTitle
strXMLCrumb = "<Breadcrumb> " & vbcrlf & _
"<Page " & "Title=""" & _
strCurrentCrumbTitle & """ " & _
"Link=""" & strReqLink & """></Page>" & _
vbcrlf & "</Breadcrumb>"
session("breadcrumbXML") = strXMLCrumb
else
mDummy = xmlDoc.loadXML(strXMLCrumb)
do
if strCrumb = "" then
strCrumb = _
"<a href=""CrumbMain.asp"">Home</a>" & _
" > "
Set objCurrNode = xmlDoc.FirstChild
end if
set objCurrNode = objCurrNode.firstChild
for each objAttrib in objCurrNode.attributes
if objAttrib.baseName = "Title" then
strTitle = objAttrib.text
end if
if objAttrib.baseName = "Link" then
strLink = objAttrib.text
end if
next
if strCurrentCrumbTitle = strTitle then
if objCurrNode.hasChildNodes() = true then
for each objChild in objCurrNode.childNodes
objCurrNode.removeChild objChild
next
end if
for each objAttrib in objCurrNode.attributes
if objAttrib.baseName = "Link" then
objAttrib.text = strReqLink
end if
next
strCrumb = strCrumb & strTitle
exit do
else
strCrumb = strCrumb & _
"<a href=""" & strLink & """>" & _
strTitle & "</a>" & " > "
if objCurrNode.hasChildNodes() = False then
set objChild = _
xmlDoc.createNode("element", "Page", "")
set objAttrib = _
xmlDoc.createAttribute("Title")
objAttrib.text = strCurrentCrumbTitle
set objAttrib = _
objChild.attributes.setNamedItem( _
objAttrib)
set objAttrib = xmlDoc.createAttribute( _
"Link")
objAttrib.text = strReqLink
set objAttrib = _
objChild.attributes.setNamedItem( _
objAttrib)
set objChild = objCurrNode.appendChild( _
objChild)
strCrumb = strCrumb & strCurrentCrumbTitle
exit do
else
'Do nothing
end if
end if
loop
session("breadcrumbXML") = xmldoc.xml
end if
response.write strCrumb
set xmlDoc = nothing
set objCurrNode = nothing
set objAttrib = nothing
set objChild = nothing
end function
%>
First, the function creates an XML document object to load/write the XML entries to. If there is nothing in the session variable, breadcrumbXML, when we call the function, we know we're at the home page moving to a child link. We always want to have a link to our home page, so we can conserve resources by generating it on the fly each time and leaving it out of the XML. Also, the current page doesn't need a link to itself, so we write it to the HTML crumb string without its link attributes (but we save those attributes to the XML in case the page is called later from the breadcrumb of another page). If there is something in the breadcrumbXML session variable when we call this function, we know we have an existing crumb. After loading the XML to the XML document object, we can easily traverse the document to look for the current page. Using the title attribute we've associated with each entry, we simply use the hasChildNodes function of each XML node to move down the hierarchy until we find the desired page (if it's already in the hierarchy), or until we reach the end of the XML document. If we find the page, we stop building the crumb there and truncate the XML to remove subordinate pages (we don't want to link to child pages of the current page). Otherwise, we add the new page node as a child of the last node. The whole XML string is then saved back to the session variable via the XML property of the XML document object, and the function returns the breadcrumb HTML.
Displaying the trailTypically, you'll display the breadcrumb near the top of the page in a format that helps it stand out from the rest of the page content. For our example in Figure A, the underlying code in the top portion of the Web page looks like Listing C: Listing C:HTML code for the breadcrumb trail
<!doctype html public
"-//w3c//dtd html 4.0 transitional//en">
<!-- File: CrumbThirdChild.asp
Descr: Third Child page for Breadcrumb
example.
Author: Ford James 5/22/2000
-->
<!-- #include file="breadcrumb.inc" -->
<html>
<head>
<title>Breadcrumb Example -- ThirdChild</title>
</head>
<body>
<%
dim strCategory
dim strCrumbTitle
'determine what category is requested
strCategory = request.queryString("Category")
'Use the category name as title for the crumb
strCrumbTitle = strCategory
%>
<b>Breadcrumb Example</b>
<hr size="1">
<%= writeBreadCrumb(strCrumbTitle) %>
<hr>
You'll need to make the function available to all your pages, and the easiest way is to keep the function in a separate file (in our example breadcrumb.inc) and use the #include file directive to insert it at the top of each page, as shown in Listing C. Next, insert the following code in each page where you want the crumb to appear: <%= writeBreadCrumb(strCrumbTitle) %>In our case, we store a one word descriptive title to a variable and pass it to the function for use in the display of the crumb and as a key for finding the page in our XML document. Consistency across pagesYou can frame the crumb any way you like using horizontal rules (as in our example), as the top line in a table (using a <rowspan> tag), or in any other way that makes it stand out. If you use Cascading Style Sheets (CSS), you can provide a consistent look and feel for breadcrumbs across your entire site. Just insert the breadcrumb function statement between <div> tags and assign a CSS class (in our case, called breadCrumbStyle) to the tag like so: <div class=breadCrumbStyle> <%= writeBreadCrumb(strCrumbTitle) %> </div> ConclusionOur simple example is just a starting point. As you've seen, using breadcrumbs will afford you several benefits for intuitive Web site navigation. In addition, XML provides a flexible, scaleable, tool for storing and retrieving virtually any data you want to associate with each breadcrumb.
Privacy
Policy Questions?
Comments? |