XML已經成爲了新一代網絡計算的世界語,這一點已經在各大軟件公司的產品中逐步體現出來。XML本身並不是一種計算語言,而更多表現爲一種數據描述的格式。相對於HTML,它更多具有數據定義的特性,而相對於數據庫,它又更加靈活和適於在網絡上傳輸。圍繞XML的相關技術也層出不窮,如XSL, XSLT等,它們的配合讓我們能夠真正在XML上開始完成一些有趣的任務。
本文就是以一個XML初學者的角度在網頁上實現一個動態彈出式菜單。對於同樣希望瞭解XML與表現無關的特性的讀者應當有所幫助。
應用情景
我們經常在一些網站看到形形色色的菜單形式,大部分的菜單都借用了DHTML的一些特性實現,但是想好好地利用這些已有的菜單實現一些自己的菜單並不容易。首先是必須從它們的整個頁面中把一些代碼“分析”,其次要分析其中的顯示方式與顯示內容的關係,如果自己的菜單結構和顯示方式不同於其它網站的設計,就得花更多的功夫去研究新的顯示方法。
而我們希望實現一個可以動態調整的菜單結構,這種菜單應當可以適用於我們所要完成的整個一個網站。一旦我們的網頁頁面設計發生了變化,我們可以靈活地把菜單顯示方式改變,適應新的網頁整體風格。
我們所希望實現的菜單首先可以表現爲以下樣子:
圖1:我們想實現的彈出式菜單的一種外觀
實現方法
在大量接觸HTML後,今天的網頁程序設計中我們更多地願意直接把一個頁面的樣子用所見即所得的編輯工具(如Frontpage, Dreamweaver等)“畫”出來,而不再習慣於利用數據結構的方式設計能夠通用的模塊。爲了能夠達到我們的目的,我們又一次地開始重新考慮如何定義一個通用的菜單數據結構來描述一個菜單的信息,然後再使用一個顯示模塊表現這些數據信息,如果改變顯示模塊的一些參數,就可以實現相同菜單內容的不同外觀和行爲。
在瞭解了XML的基本定義方法之後,我們定義瞭如下的示範數據:
列表1: 一個示範性菜單數據結構XML
<?xml version="1.0" encoding="gb2312" ?> <?xml:stylesheet type="text/xsl" href="menus.xsl"?>
<TOPICLIST TYPE="動態菜單">
<TOPICS TYPE="網絡好去處"> <TOPIC> <TITLE>中國XML聯盟</TITLE> <URL>http://www.xml.org.cn</URL> </TOPIC> <TOPIC> <TITLE>易方軟件公司</TITLE> <URL>http://www.tangram.com.cn</URL> </TOPIC> <TOPIC> <TITLE>微軟MSDN</TITLE> <URL>http://msdn.microsoft.com</URL> </TOPIC> </TOPICS>
<TOPICS TYPE="XML的應用實例"> <TOPIC> <TITLE>biztalk</TITLE> <URL>http://www.biztalk.org</URL> </TOPIC> </TOPICS>
<TOPICS TYPE="XML特性"> <TOPIC> <TITLE>精簡</TITLE> <URL>express.htm</URL> </TOPIC> <TOPIC> <TITLE>自解釋</TITLE> <URL>description.htm</URL> </TOPIC> <TOPIC> <TITLE>可交換</TITLE> <URL>exchange.htm</URL> </TOPIC> <TOPIC> <TITLE>與顯示無關</TITLE> <URL>nopresentation.htm</URL> </TOPIC> <TOPIC> <TITLE>精簡</TITLE> <URL>express.htm</URL> </TOPIC> <TOPIC> <TITLE>自解釋</TITLE> <URL>description.htm</URL> </TOPIC> <TOPIC> <TITLE>可交換</TITLE> <URL>exchange.htm</URL> </TOPIC> <TOPIC> <TITLE>與顯示無關</TITLE> <URL>nopresentation.htm</URL> </TOPIC> </TOPICS>
<TOPICS TYPE="聯繫作者"> <TOPIC> <TITLE>Isaac M.</TITLE> <URL>mailto: [email protected]</URL> </TOPIC> </TOPICS> <TOPICS TYPE="小試牛刀"> <TOPIC> <TITLE>紅色牛刀</TITLE> <URL>red.htm</URL> </TOPIC> <TOPIC> <TITLE>白色牛刀</TITLE> <URL>white.htm</URL> </TOPIC> <TOPIC> <TITLE>褐色牛刀</TITLE> <URL>brown.htm</URL> </TOPIC> </TOPICS> </TOPICLIST>
在這段數據中,菜單的主要項目和子項分別使用<TOPICS>和<TOPIC>元素表示,一目瞭然。同時你也可以看到,我們已經爲這段數據指定了一段外部的轉化爲DHTML的XSL代碼:
<?xml:stylesheet type="text/xsl" href="menus.xsl"?>
這行信息能夠讓IE自動把菜單的數據結構與一個特定的XSL結合在一起並轉化爲DHTML進行解釋。另外,爲了在IE中正確解釋中文內容,在這段數據結構的第一個部分加入了encoding="gb2312" 的描述。
學習定義XSL是一個稍微麻煩的事情,因爲XSL既像一段DHTML的描述,由好像有可執行程序的功能。假如你比較熟悉DHTML,應當很容易掌握XSL的要領,但是自己定義的過程,應當配合XML一起,一邊測試一邊定義是一個不錯的方法。我們在自己的菜單中,採用了<DIV>把菜單的項目逐個解析成爲DHTML的元素。
列表2:能夠表現我們所定義的菜單數據的一種XSL (Menus.xsl)
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<!-- MENUS.XSL -->
<xsl:template match="/"> <HTML> <HEAD> <TITLE><xsl:value-of select="TOPICLIST/@TYPE" /></TITLE> <LINK REL="stylesheet" TYPE="text/css" HREF="menus.css" /> <SCRIPT LANGUAGE="JScript" SRC="menus.js"></SCRIPT> </HEAD> <BODY> <H1><xsl:value-of select="TOPICLIST/@TYPE" /></H1>
<!-- BUILD MENUBAR -->
<DIV ID="divMenuBar"> <TABLE ID="tblMenuBar" BORDER="0"> <TR> <xsl:for-each select="//TOPICS[TOPIC]"> <TD CLASS="clsMenuBarItem"> <xsl:attribute name="ID">tdMenuBarItem<xsl:value-of select="@TYPE" /></xsl:attribute> <xsl:value-of select="@TYPE" /> </TD> <xsl:if test="context()[not(end())]"> <TD>|</TD> </xsl:if> </xsl:for-each> </TR> </TABLE> </DIV>
<!-- BUILD INDIVIDUAL MENUS -->
<xsl:for-each select="//TOPICS[TOPIC]"> <DIV CLASS="clsMenu"> <xsl:attribute name="ID">divMenu<xsl:value-of select="@TYPE" /></xsl:attribute> <DIV CLASS="clsMenuSpacer"></DIV> <xsl:for-each select="TOPIC"> <DIV> <A TARGET="main"> <xsl:attribute name="HREF"><xsl:value-of select="URL" /></xsl:attribute> <xsl:value-of select="TITLE" /> </A> </DIV> </xsl:for-each> </DIV> </xsl:for-each>
</BODY> </HTML> </xsl:template> </xsl:stylesheet>
在最早的Menu.xsl定義中,我們把菜單的交互方式(即如何響應鼠標的動作),以及顏色和字體等風格元素都與XSL結合在一起。但是我們發現還可以分離,一邊保留更大的靈活性。所以我們又定義了Menus.css和Menus.js文件,單獨定義了菜單主項和子項的外觀等特性,以及如何響應用戶的動作,這樣我們又獲得了進一步的靈活性。
列表3:在XSL中可以調整的格式表StyleSheet (Menus.css)
/* MENUS.CSS */
BODY { font-family:verdana; font-size:60%; background-color:ffffff; } H1 { font-size:120%; font-style:italic; }
DIV#divMenuBar { background-color:#6699cc; } TABLE#tblMenuBar TD { font-size:60%; color:white; padding:0px 5px 0px 5px; cursor:default; } TABLE#tblMenuBar TD.clsMenuBarItem { font-weight:bold; cursor:hand; }
DIV.clsMenu { font-size:100%; background-color:#000000; position:absolute; visibility:hidden; width:130px; padding:5px 5px 5px 8px; border-top:1 white solid; } DIV.clsMenu A { text-decoration:none; color:white; font-weight:bold; } DIV.clsMenu A:hover { color:blue; }
菜單的解析代碼Menus.xsl中還包含了一個外部的Javascript代碼文件,這樣我們的動態菜單的各個模塊就可以協同工作了。
列表4:實現Menu的交互方式的代碼 (Menus.js)
/* MENUS.JS */
var eOpenMenu = null;
function OpenMenu(eSrc,eMenu) { eMenu.style.left = eSrc.offsetLeft + divMenuBar.offsetLeft; eMenu.style.top = divMenuBar.offsetHeight + divMenuBar.offsetTop; eMenu.style.visibility = "visible"; eOpenMenu = eMenu; }
function CloseMenu(eMenu) { eMenu.style.visibility = "hidden"; eOpenMenu = null; }
function document.onmouseover() { var eSrc = window.event.srcElement; if ("clsMenuBarItem" == eSrc.className) { eSrc.style.color = "moccasin"; var eMenu = document.all[eSrc.id.replace("tdMenuBarItem","divMenu")]; if (eOpenMenu && eOpenMenu != eMenu) { CloseMenu(eOpenMenu); } if (eMenu) { OpenMenu(eSrc,eMenu); } } else if (eOpenMenu && !eOpenMenu.contains(eSrc) && !divMenuBar.contains(eSrc)) { CloseMenu(eOpenMenu); } }
function document.onmouseout() { var eSrc = window.event.srcElement; if ("clsMenuBarItem" == eSrc.className) { eSrc.style.color = ""; } }
下面我們只要對以上與數據、交互方式和風格相關的各種文件進行一些參數修改就能夠改變這個菜單模塊的行爲和表現了。修改Menu.xml能夠動態增加菜單的內容信息,修改menu.xsl能夠改變菜單的格局,修改menus.js能夠改變菜單的交互方式,修改menus.css能夠改變菜單的顏色、字體等外觀。
例如,只是在Menu.xsl和menu.js修改很少代碼,就能夠讓以上的菜單信息表現出完全不同的一種交互風格,成爲垂直型的彈出菜單。如果你有興趣,就在示例的代碼中自己修改一下,變成自己的菜單代碼吧(在我們提供的下載代碼中,menus2.xsl和menus2.js等都是修改後的實例)。
圖2:改變XSL文件參數後彈出式菜單的另一種外觀
總結
通過這樣一個簡單卻很有趣的編程經歷,我們發現XML確實是一種非常靈活的網絡信息表現語言,它的與顯示無關的特性能夠讓我們在這個初步探索的基礎上爲它增加更多的特性。例如,我們的下一步目標就是把menus.xml用一段ASP程序所替代,在我們的網站數據庫中動態提取當前頁面所需要的菜單內容,然後再結合增強的XSL和Javascript編寫更加複雜的菜單模塊。
|