<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統(tǒng)計(jì)

    積分與排名

    網(wǎng)站

    最新評(píng)論

    抽取界面::用 XML 和 XSL 構(gòu)建有良好適應(yīng)性的 Web 應(yīng)用前端

    級(jí)別: 初級(jí)

    Martin Gerlach, 軟件工程師, IBM Almaden 研究中心

    2000 年 12 月 03 日

    使 用 XML 描述 Web 應(yīng)用用戶界面的部件可以使通過(guò) XSL 樣式表轉(zhuǎn)換用于多種設(shè)備的用戶界面變得簡(jiǎn)單。本文描述了使用 XML 數(shù)據(jù)和 XSL 樣式表來(lái)構(gòu)建復(fù)雜 Web 應(yīng)用的用戶界面。Web 日歷樣本應(yīng)用將演示基本的技術(shù)和概念。本文還包括超過(guò) 24 個(gè)的代碼樣本,您可以輕易擴(kuò)展這些樣本,以滿足特定需求。

    要充分理解本文,您應(yīng)該熟悉基于 HTTP 協(xié)議的 Web 應(yīng)用和 HTTP 請(qǐng)求-應(yīng)答機(jī)制。還應(yīng)該了解 Java 編程語(yǔ)言以及如何使用 Java Servlet 作為 Web 應(yīng)用的訪問(wèn)點(diǎn)。

    問(wèn)題

    比如,對(duì)于復(fù)雜的 Web 應(yīng)用,您已經(jīng)有一個(gè)想法(甚至曾經(jīng)設(shè)計(jì)過(guò))。您知道,如果既可以從標(biāo)準(zhǔn)的 Web 瀏覽器,又可以通過(guò)無(wú)線訪問(wèn)協(xié)議 (WAP) 設(shè)備甚至可能是聲音來(lái)訪問(wèn) Web 應(yīng)用,那么就可以獲得更多的利潤(rùn)。您將把 XML 用于核心應(yīng)用和處理用戶交互的服務(wù)器進(jìn)程之間的通信。對(duì)于每種支持的客戶機(jī)格式,用戶界面將由所有可能的用戶操作的很多視圖組成,但是所有這些視圖將共享一個(gè)公共設(shè)計(jì)(即公司設(shè)計(jì))和某些公共的隱藏信息。

    在如 HTML 這樣更復(fù)雜的輸出格式中,瀏覽器窗口中的大部分將始終或多或少地顯示相同的信息(如鏈接、圖像等)。既然計(jì)劃要使用 XSLT 來(lái)將由核心系統(tǒng)產(chǎn)生的 XML 變換成不同的客戶機(jī)格式,那么,可以認(rèn)識(shí)到,對(duì)每種支持的客戶機(jī)格式只使用一個(gè) XSL 樣式表是不切實(shí)際的。這將使維護(hù)工作繁重而困難。簡(jiǎn)而言之,您需要一個(gè)有效的方式來(lái)組織 XML 數(shù)據(jù)和所有這些 XSL 樣式表。





    回頁(yè)首


    樣本應(yīng)用

    為說(shuō)明和演示解決這個(gè)問(wèn)題的框架,我編寫了一個(gè)簡(jiǎn)單的、基于 Web 的日歷應(yīng)用,名為 WebCal。它維護(hù)多個(gè)用戶的日歷,并提供以下特性:

    • 新用戶可以通過(guò)注冊(cè)頁(yè)面注冊(cè)日歷。用戶提供個(gè)人信息,然后被分配系統(tǒng)用戶名和口令。
    • 已注冊(cè)用戶可以使用登錄頁(yè)面登錄到系統(tǒng)。
    • 登錄之后,用戶可以在其日歷(日歷視圖)的日、月和年視圖之間切換。
    • 用戶可以創(chuàng)建、查看、修改和刪除活動(dòng)。
    • 活動(dòng)有一個(gè)摘要、描述、開(kāi)始時(shí)間和結(jié)束時(shí)間。開(kāi)始時(shí)間、結(jié)束時(shí)間和摘要都顯示在日歷視圖中。

    圖 1 顯示登錄頁(yè)面的屏幕快照:


    圖 1. WebCal 登錄頁(yè)面
    性能圖像

    一旦成功登錄,用戶即可使用其日歷。典型的日歷視圖如 圖 2 所示。它顯示從 2001 年 2 月 11 日到 2001 年 2 月 17 日之間的那個(gè)星期。


    圖 2. WebCal 星期視圖
    性能圖像

    所有視圖都在藍(lán)框中顯示,該框架包含應(yīng)用標(biāo)題和徽標(biāo)、一些鏈接、主導(dǎo)航欄和一個(gè)子導(dǎo)航欄。

    框架支持多個(gè)外部鏈接、內(nèi)部視圖和內(nèi)部操作的導(dǎo)航欄。主導(dǎo)航(位于徽標(biāo)之下)提供從除登錄和注冊(cè)頁(yè)面之外的所有視圖至日歷視圖的鏈接。子導(dǎo)航欄允許內(nèi)部操作,例如,在日歷視圖中創(chuàng)建活動(dòng)以及在活動(dòng)視圖中編輯或刪除活動(dòng)。

    由于使用標(biāo)準(zhǔn)顯示尺寸(1024 x 768 或更大)的標(biāo)準(zhǔn) Web 瀏覽器的 HTML 通常是最復(fù)雜的輸出,所以,WebCal 應(yīng)用只演示用于 HTML 輸出的 XSL 樣式表。所有原則對(duì)其它基于 HTTP 的格式都相同。出于與用作 Web 服務(wù)器和 Servlet 引擎的 WebSphere 3.0 兼容的原因,WebCal 用 Java 1.1.7 編寫(請(qǐng)參閱 參考資料 )。它使用可以在任何 Servlet 引擎中運(yùn)行的 Servlet。該 Servlet 使用瀏覽器 cookie(所有普通的基于 HTTP 的瀏覽器,包括 WAP 電話在內(nèi),都可以接受)來(lái)跟蹤用戶會(huì)話。

    WebCal 理解一系列請(qǐng)求類型,這些請(qǐng)求類型都使用自己的 HTTP 參數(shù)集。在樣本應(yīng)用中,通過(guò) Servlet 做所有的事:

    • 分析請(qǐng)求的 HTTP 參數(shù)
    • 執(zhí)行必需的操作
    • 生成應(yīng)答 XML
    • 將 XML 變換成 HTML(或任何其它格式)
    • 將應(yīng)答發(fā)回客戶機(jī)

    清單 1. HTTP 請(qǐng)求示例
    												
    														
    http://localhost/webcal/WebCalServlet?action=ShowDay&date=2001-02-17





    回頁(yè)首


    第 1 步. 基本 XML/XSL 框架

    首先,我們討論如何構(gòu)造和生成應(yīng)用所用的 XML 數(shù)據(jù)。然后,顯示 XSL 樣式表的通用結(jié)構(gòu),樣式表用來(lái)將 XML 數(shù)據(jù)變換成任何期望的輸出格式。

    構(gòu)造 XML 數(shù)據(jù)
    從 XML 到任何期望格式的 XSL 變換通過(guò)一系列對(duì) XML 數(shù)據(jù)中模式的匹配嘗試來(lái)進(jìn)行。應(yīng)該構(gòu)造 XML 數(shù)據(jù),使模式匹配盡可能簡(jiǎn)單。

    從應(yīng)用核心發(fā)送到前端的 XML 數(shù)據(jù)應(yīng)該只包含顯示和進(jìn)一步處理所必需的信息。首先,需要一個(gè)根元素,如清單 2 中所示。它應(yīng)該對(duì)所有視圖都是相同的,因?yàn)槟承╋@示部分也對(duì)所有視圖相同。如我們將看到的,通過(guò)匹配根元素,XSL 處理器可以最輕易地找到該信息。


    清單 2. 文檔頭和根元素
    												
    														
    <?xml version="1.0"?>
    <!DOCTYPE webcal>
    <webcal>
    <!--general stuff-->
    <!--view specific-->
    </webcal>

    既然頁(yè)面只是表單輸入的模板而且它們看起來(lái)總是相同的,所以,幾乎不需要任何其它處理或 XML 數(shù)據(jù)來(lái)顯示注冊(cè)和登錄頁(yè)面。

    對(duì)于日歷視圖,需要包括有關(guān)要顯示時(shí)期的信息。其中包括這些天的名稱和確切日期,以及那段時(shí)期內(nèi)的所有活動(dòng)。既然該樣本演示應(yīng)用不在日歷視圖中顯示活動(dòng)描述,所以不需要在 XML 中包括它。因?yàn)橐獎(jiǎng)?chuàng)建至那些活動(dòng)的更詳細(xì)視圖的鏈接,所以,在 XML 中存儲(chǔ)每個(gè)活動(dòng)的活動(dòng)標(biāo)識(shí)。


    清單 3. 天的表示
    												
    														
    <webcal>
    ...
    <day date="2001-02-17">
    <event id="..." start="2001-02-17T20:00" end="2001-02-18T06:00">
    <summary>Martin's birthday party</summary>
    </event>
    </day>
    ...
    </webcal>

    顯示超過(guò)一天的視圖有幾個(gè) <day> 元素。可以對(duì)這些元素排序,或以其出現(xiàn)的順序處理它們。為了排序,可以使用 date 屬性(以 ISO8601 的格式)。對(duì)于月視圖,可以將 <day> 元素組合成 <week> 標(biāo)記。這在 XML 生成過(guò)程中不需要太多計(jì)算,并且可以簡(jiǎn)化 XSL 處理。有關(guān)詳細(xì)信息,請(qǐng)查看 用 Java 代碼還是 XSL 進(jìn)行計(jì)算?側(cè)欄。

    用 Java 代碼還是 XSL 進(jìn)行計(jì)算?

    必須權(quán)衡用 XML 生成代碼和通過(guò) XSL 生成代碼之間的利弊。通常,當(dāng) XSL 計(jì)算過(guò)于復(fù)雜(例如將天組合成星期,以及生成用于在天、星期和月之間導(dǎo)航的 <next><previous> 元素)時(shí),最好用 Java 處理,并用 XML 反映結(jié)果。另外,即使在某些天中沒(méi)有活動(dòng),最好也為月份中的每一天生成一個(gè)標(biāo)記,而不要試著在 XSL 中實(shí)現(xiàn)循環(huán)(這很重要)。有關(guān) XSL 的詳細(xì)信息,請(qǐng)參閱 第 2 步

    在細(xì)節(jié)視圖中顯示活動(dòng)需要所有可用的活動(dòng)信息。對(duì)于 WebCal,這將與 清單 3 基本相同,只是添加了要以 <description> 元素出現(xiàn)的活動(dòng)描述。

    顯示要?jiǎng)?chuàng)建活動(dòng)的視圖不一定需要任何 XML 數(shù)據(jù),但是可以包括一個(gè) <event> 元素來(lái)提供缺省值。修改活動(dòng)再一次需要所有活動(dòng)數(shù)據(jù),以便用當(dāng)前值填充編輯表單的字段。

    當(dāng)用戶登錄時(shí),將需要所有視圖的某些信息(如框架的不同部分、鏈接和導(dǎo)航欄)。子導(dǎo)航根據(jù)視圖類型的不同而不同,但是,對(duì)于同一類型的兩個(gè)視圖,其子導(dǎo)航 是相同的(例如,顯示不同天的兩個(gè)天視圖)。用戶登錄之后,可能還要包括一些個(gè)人數(shù)據(jù)。示例應(yīng)用只用到了名稱和用戶名稱。事實(shí)證明,包括當(dāng)前視圖的 HTTP 參數(shù)也十分有用,這樣可以在 XSL 樣式表中使用它們。

    以下代碼樣本顯示為從星期天開(kāi)始的、在“Martin 的生日聚會(huì)”之前的那個(gè)星期生成的完整 XML。它已準(zhǔn)備好變換成客戶機(jī)所喜愛(ài)的格式。


    清單 4. 表示視圖的完整 XML
    												
    														
    <webcal>
    <http-params>
    <param name="action" value="ShowWeek"/>
    <param name="date" value="2001-02-11"/>
    </http-params>
    <user>
    <login>martin</login>
    <firstname>Martin</firstname>
    <middlename/>
    <lastname>Gerlach</lastname>
    </user>
    <navigation>
    <global>
    <main-nav>
    <link type="internal" text="Day" href="ShowDay">
    <pass-param name="date"/>
    </link>
    <link type="internal" text="Day" href="ShowWeek">
    <pass-param name="date"/>
    </link>
    <link type="internal" text="Day" href="ShowMonth">
    <pass-param name="date"/>
    </link>
    </main-nav>
    <links>
    <link type="internal" text="Logout" href="Logout"/>
    <link type="external" text="Home" />
    </links>
    </global>
    <actions>
    ...
    <action name="ShowWeek">
    <sub-nav>
    <link type="internal" text="New Event" href="ShowNewEvent">
    <pass-param name="date"/>
    </link>
    </sub-nav>
    </action>
    ...
    </actions>
    </navigation>
    <now date="2000-11-07T15:30"/>
    <week date="2001-02-11" previous="2001-02-04" next="2001-02-18">
    <day date="2001-02-11"/>
    <day date="2001-02-12"/>
    <day date="2001-02-13"/>
    <day date="2001-02-14"/>
    <day date="2001-02-15">
    <event id="(id1)" start="2001-02-15T18:00" end="2001-02-15T20:00">
    <summary>Shopping for Martin's birthday party</summary>
    </event>
    </day>
    <day date="2001-02-16"/>
    <day date="2001-02-17">
    <event id="(id2)" start="2001-02-17T20:00" end="2001-02-18T06:00">
    <summary>Martin's birthday party</summary>
    </event>
    </day>
    </week>
    </webcal>

    對(duì)星期視圖只特別生成了 <week> 元素,其余所有內(nèi)容都在所有視圖中相同,并可以保存在文件系統(tǒng)或數(shù)據(jù)庫(kù)中。

    圖 2 顯示了清單 4 在屏幕上的顯示結(jié)果。(將在 第 2 步 中討論必要的 XSL 變換)。如果正在運(yùn)行樣本應(yīng)用,可以將 "&format=xml" 附加在當(dāng)前 URL 之后,然后重新裝入該頁(yè)面,以查看當(dāng)前視圖的應(yīng)答 XML。

    用 Java 生成 XML
    要處理的數(shù)據(jù)駐留在服務(wù)器上。訪問(wèn)之后,需要將其格式化 XML。可以使用任何可用的 Java XML 包來(lái)生成包含應(yīng)答 XML 的 DOM 樹(shù)。下例引用 XML4J(請(qǐng)參閱 參考資源)。

    可以用 org.w3c.dom.Documentorg.w3c.dom.Element 實(shí)例的方式在 Java 中傳遞 XML 數(shù)據(jù)。在提供幾種有用的方法來(lái)分析所包含元素的語(yǔ)法方面,文檔接口具有一定的優(yōu)勢(shì)。


    清單 5. 用根節(jié)點(diǎn)創(chuàng)建文檔。
    												
    														
    import org.w3c.dom.*; // DOM interfaces
    import org.apache.xerces.dom.*; // DOM implementation for XML4J

    ...
    Document responseXML = createDocument("webcal");

    public Document createDocument(String rootName)
    {
    Document doc = new DocumentImpl();
    doc.appendChild(doc.createElement(rootName));
    return doc;
    }



    清單 6. 獲得文檔根元素
    												
    														
    Element root = doc.getDocumentElement();



    清單 7. 將 <day date="2001-02-17"/>附加到元素之后
    												
    														
    Element dayElem = doc.createElement("day");
    dayElem.setAttribute("date","2001-02-17");
    someElement.appendChild(dayElem);



    清單 8. 將文本附加到元素 summaryElem: <summary>This is a summary</summary> 之后
    												
    														
    org.w3c.dom.Text textNode = doc.createTextNode("This is a summary");
    summaryElem.appendChild(textNode);

    您可能要編寫自己的實(shí)用程序方法來(lái)構(gòu)建應(yīng)用的 XML 文檔。可以使用可用的 XML 包中的語(yǔ)法分析器,以從流(包括文件)讀取 XML 或?qū)⑵鋵懭搿T谠创a中,查看 ShowAction.displayResult() 或任何其它 ShowAction 的 generateXML() 方法,以了解這是如何完成的。

    您可能還想?yún)⒖计渌? developerWorks 中關(guān)于 XML 和 Java 的文章,以獲得其它觀點(diǎn)(請(qǐng)參閱 參考資料)。

    構(gòu)造 XSL 樣式表
    XSL 樣式表包含從一種 XML 格式到另一種 XML 格式(例如,任何有良好格式的標(biāo)記語(yǔ)言)的變換規(guī)則。這些規(guī)則被編寫成所謂的模板,可以用兩種方式將它們應(yīng)用到源 XML。一種是通過(guò)名稱從其它模板調(diào)用它們,另一種是自動(dòng)將它們匹配到源 XML 的各個(gè)部分。轉(zhuǎn)換由 XSL 處理器完成。

    通常以對(duì)源 XML 的引用和對(duì)要使用的樣式表的引用來(lái)初始化 XSL 處理器。作為變換的第一步,應(yīng)該給 XSL 處理器一個(gè)明確匹配源 XML 某一部分的模板。然后,將從那個(gè)通常匹配根節(jié)點(diǎn)的模板調(diào)用所有其它模板。這與調(diào)用所有其它子程序的“主例程”類似。


    清單 9. ShowWeek.xsl (V.1):用于 WebCal 星期視圖的 HTML 輸出的 XSL 模板
    												
    														
    <xsl:style sheet>
    <xsl:template match="webcal">
    <html>
    <head>
    <title>WebCal - Week</title>
    </head>
    <body>
    <!-- week view content -->
    </body>
    </html>
    </xsl:template>
    </xsl:style sheet>

    包括樣式表和通過(guò)名稱調(diào)用模板
    每個(gè)視圖都需要這樣的一個(gè)模板,但是,所有視圖的 <html><head><body> 元素都將相同。因此,如果抽取這些元素并將其放入公共模板,則可以從所有視圖調(diào)用該模板(通過(guò)名稱)。


    清單 10. ShowWeek.xsl (V.2):包括和調(diào)用生成框架的樣式表
    												
    														
    <xsl:style sheet>
    <xsl:include href="http://localhost/webcal/html/Frame.xsl"/>
    <xsl:template match="webcal">
    <xsl:call-template name="frame"/>
    </xsl:template>
    </xsl:style sheet>

    假設(shè)現(xiàn)在已經(jīng)由所包括的樣式表生成了內(nèi)容,那么,對(duì)每個(gè)視圖,還需要樣式表嗎?實(shí)際的視圖內(nèi)容(在框架中)又在哪里生成呢?生成框架的模板需要調(diào)用另一個(gè)模板,即生成內(nèi)容的模板。但是,框架如何知道應(yīng)該是 哪個(gè) 模板(例如,生成的框架用于哪個(gè)視圖)呢?事實(shí)上,框架模板無(wú)需知道,它只需調(diào)用一個(gè)名為 "main" 的模板即可。"main" 模板在樣式表中定義。在包含與 "webcal" 匹配的模板的樣式表中包括該樣式表。這就是為什么需要對(duì)每個(gè)視圖使用一個(gè)樣式表的原因。以下是星期視圖的完整結(jié)構(gòu):


    清單 11. ShowWeek.xsl (V.3)
    												
    														
    <xsl:style sheet>
    <xsl:output method="html"/> <!-- for XT -->
    <xsl:include href="http://localhost/webcal/html/Frame.xsl"/>
    <xsl:include href="http://localhost/webcal/html/ShowWeekMain.xsl"/>
    <xsl:template match="webcal">
    <xsl:call-template name="frame"/>
    </xsl:template>
    </xsl:style sheet>



    清單 12. Frame.xsl
    												
    														
    <xsl:style sheet>
    <xsl:template name="frame">
    <html>
    <head>
    <title>
    WebCal -
    <xsl:value-of select="/webcal/http-params/param[@name='action']/@value"/>
    </title>
    </head>
    <body>
    <!-- do the frame -->
    <table>
    <xsl:comment>frame content</xsl:comment>
    ...
    <td>
    <div style="width: ...; height: ...; ...>
    <xsl:call-template name="main">
    <xsl:with-param name="width">?lt;/xsl:with-param>
    <xsl:with-param name="height">?lt;/xsl:with-param>
    </xsl:call-template>
    </div>
    </td>
    <xsl:comment>frame content continued</xsl:comment>
    ?
    </table>
    </body>
    </html>
    </xsl:template>
    </xsl:style sheet>



    清單 13. ShowWeekMain.xsl
    												
    														
    <xsl:style sheet>
    <xsl:template match="main">
    <xsl:param name="width"/>
    <xsl:param name="height"/>
    <xsl:comment>Week view content</xsl:comment>
    <!-- produce week view content here. Keep in mind this is called from
    inside a <div> element with the given width and height -->
    </xsl:template>
    </xsl:style sheet>

    清單 4 所示,所有這些從 XML 數(shù)據(jù)產(chǎn)生以下 HTML。


    清單 14. 星期視圖的 HTML
    												
    														
    <html>
    <head>
    <title>WebCal - ShowWeek</title>
    </head>
    <body>
    <table>
    <!--frame content-->
    ...
    <td>
    <div style="width: ...; height: ...; ...>
    <!--week view content-->
    ...
    </div>
    </td>
    <!--frame content continued-->
    ...
    </table>
    </body>
    </html>

    選擇必要的樣式表
    如果輸出格式?jīng)]有 HTML 那樣復(fù)雜(例如 WML),則通常沒(méi)有必要對(duì)框架使用額外的樣式表。另外,如果視圖顯示非常類似的內(nèi)容,則它們可以共享樣式表。在 WebCal 中,雖然源 XML 略有不同,但是,用于創(chuàng)建和編輯活動(dòng)的視圖使用同一個(gè)樣式表。(有關(guān)代碼,請(qǐng)參閱 第 3 步)。

    但通常,當(dāng)使用這個(gè)框架時(shí),需要以下樣式表:

    • 每個(gè)視圖和格式都需要一個(gè)根樣式表(如上面的 ShowWeek.xsl)
    • 每一種格式都需要一個(gè)框架樣式表
    • 每個(gè)視圖和格式都需要一個(gè)視圖內(nèi)容樣式表,包含由 "frame" 模板調(diào)用的命名的模板。

    每個(gè)樣式表都位于自己的文件中。一個(gè)樣式表中可以有多個(gè)模板,這樣,"frame" 和 "main" 模板可以使用 <xsl:call-template><xsl:apply-templates> 將其它模板應(yīng)用到應(yīng)答 XML 的某些部分中。

    要想使用 HTTP 來(lái)包括如上所示的樣式表,所有樣式表都要位于本地 Web 服務(wù)器文檔目錄之下,如清單 15 中所示:


    清單 15. 本地 Web 服務(wù)器目錄
    												
    														
    /
    webcal/
    html/
    Frame.xsl
    LoginView.xsl
    LoginViewMain.xsl
    DayView.xsl
    DayViewMain.xsl
    WeekView.xsl
    WeekViewMain.xsl
    ...
    wml/
    Frame.xsl
    LoginView.xsl
    LoginViewMain.xsl
    ...

    用 Java 執(zhí)行變換
    WebCal 使用 James Clark 的 XT(請(qǐng)參閱 參考資料 )來(lái)將樣式表應(yīng)用到應(yīng)答 XML。如下所示,變換涉及到某些對(duì) XT 包的調(diào)用。其它象 LotusXSL 這樣的 XSL 處理器(請(qǐng)參閱 參考資料)以不同的方式對(duì)此進(jìn)行處理。

    WebCal 從 HTTP 請(qǐng)求檢索:

    • 瀏覽器類型
    • 瀏覽器理解的格式
    • 它所設(shè)置成的語(yǔ)言
    • 請(qǐng)求的操作

    從所有這些信息,可以找到視圖的正確根 XSL 樣式表。請(qǐng)參閱 清單 16. 用 Java 進(jìn)行 XSL 變換

    總結(jié)第 1 步:得到的教訓(xùn)
    對(duì)于 XML 設(shè)計(jì)和 XML 生成:

    • 確定視圖所需的信息
    • 把為公共所需的信息而編寫的 XML 生成代碼與為視圖特別所需的信息而編寫的 XML 生成代碼分開(kāi)。
    • 在生成 XML 之前或在其過(guò)程中,用 Java 代碼執(zhí)行復(fù)雜計(jì)算,然后用 XML 反映結(jié)果(如果可能并且每種應(yīng)答格式都需要的話)。
    • 使整個(gè)結(jié)構(gòu)保持靈活。

    對(duì)于 XSL 樣式表的通用結(jié)構(gòu):

    • XSL 樣式表應(yīng)該位于 Web 服務(wù)器的文檔目錄中,以允許用 <xsl:include> 將其裝入。




    回頁(yè)首


    第 2 步:用 XSLT 生成輸出

    前一節(jié)已經(jīng)講了輸出的基本部分,即 <html><head><body> 標(biāo)記。本節(jié)討論在 <body> 標(biāo)記內(nèi)部的 HTML 生成,哪一部分用框架的 XSL 完成,哪一部分用不同的 "main" 樣式表完成。

    框架
    表格是用來(lái)布置 HTML 頁(yè)面的好方式。WebCal 對(duì)框架使用一個(gè)表格,主要部分位于框架中間最大的表單元中。 圖 3 中的紅線顯示在 Frame.xsl 中用來(lái)繪制框架的表。除了中間的主要部分之外,所有事都由 Frame.xsl 完成。三個(gè)導(dǎo)航面板上的鏈接在每個(gè)視圖的 XML 數(shù)據(jù)中定義。


    圖 3. WebCal 用戶界面布局中的表格單元
    性能圖像

    使用 <xsl:apply-templates> 和 <xsl:for-each> 來(lái)處理 XML 元素
    知道框架的 XSL 樣式表如何訪問(wèn) XML 數(shù)據(jù)這一點(diǎn)很重要。對(duì)于左邊和頂部導(dǎo)航欄上的鏈接,可以使用 <xsl:apply-templates> 指令。請(qǐng)參閱 清單 17. 生成導(dǎo)航欄

    <xsl:apply-templates> 將對(duì) XML 節(jié)點(diǎn)應(yīng)用模板。這意味著:XSL 處理器查找與 <xsl:apply-tempates> 的 "select" 屬性定義的表達(dá)式相匹配的 XML 元素。對(duì)于邊鏈接的情況,將匹配導(dǎo)航部分中 <global> 元素下的所有 <links> 元素。如 清單 4 中星期視圖中的 XML 代碼所示,只有一個(gè)這樣的元素。它可以有任意數(shù)量的作為其子代的 <link> 元素。可以使用 <xsl:with-param> 來(lái)將任意數(shù)量的已命名的參數(shù)傳遞到匹配的模板。在本例中,它傳遞應(yīng)該用于該鏈接的樣式名稱。

    本文不具體討論樣式、圖像以及其它這些可以改進(jìn) Web 應(yīng)用的外觀和感覺(jué)的技術(shù)。看一下樣本應(yīng)用中的源代碼,以了解如何在 XSL 中定義和使用 CSS 樣式。

    在 Frame.xsl 中還定義了與 <links> 元素匹配的模板。它使用 <xsl:for-each> 來(lái)迭代 <links><link> 子代。在該循環(huán)中,它應(yīng)用與當(dāng)前 <link> 元素(由 "." 表示當(dāng)前元素)相匹配的模板,并傳遞 "css" 參數(shù)。在每個(gè)鏈接之后,它插入一個(gè) <br/> 元素,以便在左邊,每行只有一個(gè)鏈接。


    清單 18. 鏈接
    												
    														
    <xsl:template match="links">
    <xsl:param name="css"/>

    <xsl:for-each select="link">
    <xsl:apply-templates select=".">
    <xsl:with-param name="css" select="$css"/>
    </xsl:apply-templates>
    <br/>
    </xsl:for-each>
    </xsl:template>


    可以有兩種類型的鏈接,即內(nèi)部鏈接和外部鏈接(如星期視圖的 XML 中所示(請(qǐng)參閱 清單 4 ))。 <link> 元素的 "type" 屬性定義類型。對(duì)于每一種鏈接類型,可以定義成自動(dòng)與正確的鏈接節(jié)點(diǎn)相匹配的模板。XML 屬性由 "@" 后面加上屬性名引用。必須求出 <xsl:template> 的 "match" 屬性中方括號(hào)中表達(dá)式的布兒值,以確定該模板是否與節(jié)點(diǎn)匹配。可以輕易生成外部鏈接,如下面的 "home" 鏈接所示:


    清單 19. XML 中的外部鏈接
    												
    														
    <link type="
    external" text="Home"/>




    清單 20. 與外部鏈接匹配的 XSL 模板
    												
    														
    <xsl:template match="link
    [@type='external']">
    <xsl:param name="css"/>
    <a class="{$css}" href="{@href}"><xsl:value-of select="@text"/></a>
    </xsl:template>




    清單 21. 應(yīng)用外部鏈接模板之后的 HTML
    												
    														
    <a class="..." >Home</a>

    然而,內(nèi)部鏈接卻鏈接到 WebCalServet,并可以有任意數(shù)量的、必須轉(zhuǎn)換成 HTTP 參數(shù)的 <pass-param> 子代。這略為復(fù)雜,并要求在 XML 數(shù)據(jù)中進(jìn)行一些導(dǎo)航。以下鏈接從 XML 數(shù)據(jù)的 <main-nav> 部分獲得。它將顯示在頂部導(dǎo)航欄上,指向當(dāng)前日期的天視圖。( <main-nav> 元素由與 <links> 元素上所用模板類似的模板處理 。唯一區(qū)別是:該鏈接不由 <br/> 元素分開(kāi),而是由豎線分開(kāi))。已經(jīng)將該數(shù)據(jù)作為 HTTP 參數(shù)傳遞到 Servlet,并將其包括在 XML 的 <http-params> 部分。


    清單 22. 從 XML 數(shù)據(jù)的主導(dǎo)航部分開(kāi)始的外部鏈接
    												
    														
    <link type="
    internal" text="Day" href="ShowDay">

    <pass-param name="date"/>
    </link>


    清單 23. 與內(nèi)部鏈接匹配的 XSL 模板


    清單 24. 經(jīng)過(guò) XSL 處理之后的 HTML
    												
    														
    <a class="..." href="/webcal/WebCalServlet?action=ShowDay&date=...">Day</a>

    模板優(yōu)先

    在 XSL 中,具有更詳細(xì)匹配表達(dá)式的模板有優(yōu)先。XSL 規(guī)范(請(qǐng)參閱 參考資料)定義了所有的優(yōu)先規(guī)則。

    <link> 元素匹配的模板使用一個(gè) <xsl:variable> ,后者使用 <xsl:apply-templates> ,將與 <pass-param> 元素匹配的兩個(gè)模板中的一個(gè)應(yīng)用到當(dāng)前 <link> 元素的所有現(xiàn)有 <pass-param> 子代。然后,名為 "params" 的變量將包含那些模板應(yīng)用的結(jié)果。第一個(gè)與 <pass-param> 匹配的模板與所有 <pass-param> 元素匹配,第二個(gè)只與那些具有 "value" 屬性的 <pass-param> 元素匹配。在 XSL 中,規(guī)則越詳細(xì),其優(yōu)先越高,所以,第二個(gè)模板與具有 "value" 屬性的 <pass-param> 元素相匹配。

    有關(guān) XSL 如何處理優(yōu)先的提示,請(qǐng)參閱側(cè)欄 模板優(yōu)先

    復(fù)雜的 XPath 表達(dá)式
    第一個(gè)模板使用 XPath 表達(dá)式從 <http-params> 部分查詢值。可以將表達(dá)式 "/webcal/http-params/param[@name=$pname]/@value" 解釋成:“獲得 'name' 屬性值為變量 'pname' 中所定義值的 <webcal> 元素之下的 <http-params> 元素的 <param> 元素的名為 'value' 的屬性值。有了該值之后,模板構(gòu)建一個(gè)如 "&name=value" 這樣的字符串。必須象 HTML 那樣,用 & 實(shí)體將 & 符號(hào)轉(zhuǎn)義。使用類似的表達(dá)式來(lái)從 <head> 部分中的 action HTTP 參數(shù)生成頁(yè)面標(biāo)題。(請(qǐng)參閱 清單 12)。

    第二個(gè)模板只使用表達(dá)式 @value 來(lái)引用當(dāng)前元素的 "value" 屬性,其中,當(dāng)前指的是與模板匹配的 <pass-param> 元素。然后,模板再次從這個(gè)值和 "name" 屬性生成一個(gè)字符串 "&name=value"

    變量和 XPath 表達(dá)式

    可以在 XSL 元素的屬性中(例如,在 <xsl:template> 的 "match" 屬性中,或者在 <xsl:value-of><xsl:apply-templates> 等的 "select" 屬性中)使用 XPath 表達(dá)式和對(duì) XSL 變量的引用。也可以在非 XSL 元素的屬性(如 <a> 的 "href" 屬性)中使用它們。在這種情況下,需要將表達(dá)式放在花括號(hào)中: "{/webcal/now}" <now> 元素的值)。

    在與外部鏈接匹配的模板中,變量 "params" 包含從 <pass-param> 元素生成的所有字符串的并置。然后將該并置包括在生成的 <a> element ( href="...{$params}" 的 "href" 屬性中)。

    將 XPath 表達(dá)式結(jié)果保存在 XSL 變量中的更多內(nèi)容
    框架的底部導(dǎo)航欄包含一些不固定的鏈接,它們依賴于當(dāng)前視圖。日歷視圖的底部導(dǎo)航欄包含一個(gè)導(dǎo)向用戶可以創(chuàng)建新活動(dòng)的頁(yè)面的鏈接。創(chuàng)建活動(dòng)之后,將該活動(dòng) 作為到活動(dòng)細(xì)節(jié)視圖的鏈接顯示在日歷中。在那個(gè)視圖中,子導(dǎo)航欄包含后退、編輯活動(dòng)和刪除活動(dòng)的鏈接。但是,子導(dǎo)航欄的外觀和感覺(jué)是一致的,所以,不在框 架樣式表中創(chuàng)建它。

    XML 數(shù)據(jù)的 <navigation> 部分以 <link> 元素的形式包含有關(guān)每個(gè)視圖的導(dǎo)航欄內(nèi)容的信息。要訪問(wèn)該信息,"frame" 模板需要知道顯示的是哪一個(gè)視圖。XML 數(shù)據(jù)的 <http-params> 部分包含 action 參數(shù)的值。清單 25 顯示了如何保存當(dāng)前操作以及到兩個(gè) XSL 變量的相應(yīng) <action> 元素的引用。然后,使用到 <action> 元素的引用來(lái)生成子導(dǎo)航欄。

    有關(guān)一些詳細(xì)信息,請(qǐng)參閱 變量和 XPath 表達(dá)式側(cè)欄。


    清單 25. 將當(dāng)前操作和對(duì)其元素的引用保存到 XML 變量
    												
    														
    <webcal>
    <http-params>
    <param name="action" value="ShowWeek"/>
    ...
    <navigation>
    ...
    <actions>
    ...
    <action name="ShowWeek">
    <link type="
    internal" text="New Event" href="ShowNewEvent">

    <pass-param name="date"/>
    </link>
    </sub-nav>
    </action>
    ...
    </webcal>


    清單 26. 獲得當(dāng)前操作名稱和相應(yīng) <action> 元素的 XSL

    生成子導(dǎo)航的部分將與 <sub-nav> 元素相匹配的模板應(yīng)用到與當(dāng)前操作相對(duì)應(yīng)的導(dǎo)航節(jié)點(diǎn)的 <sub-nav> 子代。對(duì)于 WebCal,該模板看起來(lái)與生成主導(dǎo)航欄的模板完全相同。

    主面板
    主面板由名為 "main" 的、且對(duì)每個(gè)視圖都不相同的模板生成。它從 HTML <div> 標(biāo)記中調(diào)用,該標(biāo)記限制主面板的尺寸,并且,如果需要的話,將顯示滾動(dòng)欄。將喜愛(ài)的尺寸作為命名的參數(shù)傳遞到 "main" 模板。

    在以下部分中,以星期視圖為例,演示如何將 XML 應(yīng)用數(shù)據(jù)變換成 HTML。


    圖 4. 使用嵌套表格來(lái)布置星期視圖
    性能圖像

    清單 27. 調(diào)用 "main" 模板
    												
    														
    <xsl:template name="frame">
    ...
    <td class="main" align="left" valign="top"
    width="{$main_width}" height="{$main_height}">
    <div style="...
    width:{$main_width}px; height:{$main_height}px; overflow: auto; ...">
    <xsl:call-template name="main">

    <xsl:with-param name="width" select="$main_width"/>
    <xsl:with-param name="height" select="$main_height"/>
    </xsl:call-template>
    </div>
    </td>
    ...
    </xsl:tempate>


    在 "frame" 模板中計(jì)算變量 main_widthmain_height 。寬度取決于標(biāo)志圖像的大小,而高度可以隨意按像素大小設(shè)置。

    在 "main" 模板中,使用與框架中所用的類似的技巧來(lái)顯示內(nèi)容。首先,看一下 Show...Main.xsl 文件,以了解如何布置頁(yè)面。雖然有幾個(gè)特殊的 XSL 特性,但是,我將在下一節(jié)中解釋。

    使用數(shù)字
    在星期視圖中,將星期分成兩行。既然這只用于 HTML(您可能不想在其它設(shè)備中使用類似的顯示),所以在 XSL 樣式表中分成兩行。您可能很想如清單 28 那樣將 <xsl:for-each><xsl:if>position() 函數(shù)一起使用。從 1 開(kāi)始, position() 返回 for-each 迭代的順序號(hào)。


    清單 28. 將星期分成兩行,嘗試 1
    												
    														
    <xsl:template name="main">
    ...
    <table>
    <tr>
    <!-- title --> ...
    </tr>
    <tr>
    <xsl:for-each select="webcal/week/day">
    <!-- do the day --> ...
    <xsl:if test="position()=4">
    <!-- next row -->

    </tr>
    <tr>
    </xsl:if>
    </xsl:for-each>
    </tr>
    </table>
    </xsl:tempate>


    這在 XSL 中不管用,因?yàn)?XSL 樣式表必須有良好的格式。這意味著:每個(gè)打開(kāi)的標(biāo)記必須有一個(gè)相應(yīng)的結(jié)束標(biāo)記,而且不能部分嵌套元素(錯(cuò)誤: <a><b></a></b> )。紅色的 </tr> 標(biāo)記本想用作 <xsl:for-each> 之前的 <tr> 標(biāo)記的結(jié)束標(biāo)記。但是這可能意味著: <xsl:for-each><xsl:if> 元素與 <tr> 元素部分嵌套。XML 規(guī)范強(qiáng)制 XSL 處理器將最后一個(gè) </tr> 標(biāo)記解釋成 <xsl:for-each> 之前的 <tr> 標(biāo)記的結(jié)束標(biāo)記,并將兩個(gè)紅色標(biāo)記解釋成錯(cuò)誤(結(jié)束標(biāo)記沒(méi)有開(kāi)始標(biāo)記,以及開(kāi)始標(biāo)記沒(méi)有結(jié)束標(biāo)記)。

    對(duì)這個(gè)問(wèn)題的解決方案是在 XML 中枚舉天,然后使用匹配的表達(dá)式。在 WebCal 中,一星期中的每一天都有一個(gè)名為 "num" 、從 "1" 到 "7"的附加屬性。XSL 支持用布爾表達(dá)式比較數(shù)字,因此,可以使用 <xsl:apply-templates> 在兩個(gè) <tr> 元素內(nèi)實(shí)現(xiàn)兩個(gè)循環(huán),如清單 29 所示:


    清單 29. 將星期分成兩行,嘗試 2
    												
    														
    <xsl:template name="main">
    <table>
    <tr>
    <!-- title --> ...
    </tr>
    <tr valign="top">
    <xsl:apply-templates select="/webcal/week/day
    [@num<=4]"/>
    </tr>
    <tr valign="top">
    <xsl:apply-templates select="/webcal/week/day
    [@num>=5]"/>
    </tr>
    </table>
    </xsl:tempate>

    <xsl:tamplate match="day">
    <!-- this matches all day elements -->
    <!-- do the day here --> ...
    </xsl:template>


    <xsl:apply-templates> 的紅色選擇標(biāo)準(zhǔn)為 @num<=4@num>=5 。在 XSL 中,應(yīng)該始終轉(zhuǎn)義 <> 字符。然后,由 "day" 模板處理(也就是匹配)所有的 day 元素,(無(wú)論在第一個(gè)循環(huán)還是第二個(gè)循環(huán)中)。

    另一個(gè)問(wèn)題是為每一天生成標(biāo)題。XML 的 day 元素有一個(gè)名為 "date" 的屬性。其格式為 "yyyy-mm-dd"(ISO 標(biāo)準(zhǔn)化的格式)。那么,怎樣才能將它變換成 "day mm-dd" 的格式呢?對(duì)于 "mm-dd" 部分,XSL 提供字符串操作。通過(guò)使用 substring-after()substring-before() 或二者的組合,可以分析字符串的語(yǔ)法。

    對(duì)于星期中天的名稱,可以將 "num" 屬性與 <xsl:choose> 語(yǔ)句一起使用,如清單 30 所示。


    清單 30. <xsl:choose> 和字符串操作
    												
    														
    <xsl:template match="day">
    <table>
    <tr>
    <td class="maininverse"...>

    <xsl:choose>
    <xsl:when test="@num=1">Sun
    </xsl:when>
    <xsl:when test="@num=2">Mon</xsl:when>
    ...

    </xsl:choose>
    <xsl:value-of select="' '"/><!-- this generates a space -->
    <a class="maininverse" href="/webcal/WebCalServlet?action=ShowDay&date={@date}">
    <xsl:value-of select="
    substring-after(@date,'-')"/>
    </a>
    </td>
    </tr>
    <!-- process events here --> ...
    </table>
    </xsl:template>


    該字符串操作還從 <event> 元素的 "start" 和 "end" 屬性抽取活動(dòng)開(kāi)始和結(jié)束時(shí)間。

    總結(jié)第 2 步

    第 2 步下了顯示了如何將 XML 變換成 HTML。通過(guò)使用上面顯示的技巧,還可以將 XML 變換成任何其它有良好形式的標(biāo)記語(yǔ)言,以支持多種設(shè)備。有一個(gè)對(duì)所有支持的客戶機(jī)格式都相同的中間格式,對(duì)把應(yīng)用邏輯從顯示邏輯分開(kāi)會(huì)有所幫助。

    如需更詳細(xì)的說(shuō)明, XML Bible(請(qǐng)參閱 參考資料 )會(huì)給您有關(guān) XSL 和 XPath 的極好概述,包括數(shù)字轉(zhuǎn)換、比較和字符串操作。





    回頁(yè)首


    第 3 步:使用表單

    這一步解釋如何在第 1 步和第 2 步所描述的 XSL 框架中使用表單。當(dāng)然,前提是客戶機(jī)要支持表單,但是幾乎所有可用的基于 HTTP 的瀏覽器都支持表單。本節(jié)顯示如何在 WebCal 中使用 XSL 來(lái)生成 HTML 表單來(lái)編輯和創(chuàng)建日歷活動(dòng)(例如,會(huì)議和約會(huì))。示例還顯示了該操作如何共享一個(gè)公共樣式表。

    表單元素
    與所有其它 HTML 元素類似,可以通過(guò) XSL 模板生成表單元素,包括 <form> 元素,和說(shuō)明到應(yīng)用 Servlet 的哪個(gè)點(diǎn)的 "action" 屬性。每個(gè)表單都應(yīng)該有一個(gè)內(nèi)部操作,以在用戶提交表單之后處理表單。使用一個(gè)隱藏字段來(lái)調(diào)用特定的內(nèi)部操作,如清單 21 所示:


    清單 31. ShowEventFormMain.xsl - 用來(lái)顯示 new event 或 edit event 表單
    												
    														
    <xsl:template name="main">
    ...
    <form method="post"
    action="/webcal/WebCalServlet">
    <!-- 'edit' is an XSL variable. It is set to 'true' if the action was 'ShowEditEvent'.-->
    <xsl:if test="
    $edit='true'">

    <input type="hidden" name="action" value="ProcessEditEvent"/>
    <input type="hidden" name="id" value="{/webcal/event/@id}"/>
    </xsl:if>
    <xsl:if test="
    $edit='false'">

    <input type="hidden" name="action" value="ProcessNewEvent"/>
    </xsl:if>
    ...
    <!-- build the form -->
    ...
    </form>
    </xsl:template>


    表單處理

    使用常見(jiàn) Web 瀏覽器的“后退”和“重新裝入”功能可能會(huì)導(dǎo)致某些表單處理混亂。要避免這種問(wèn)題,WebCal 使用兩種類型的操作: ShowActions (請(qǐng)參閱 ShowAction.java )使用 第 2 步 中所描述的 XSL 變換顯示視圖。 ProcessActions (請(qǐng)參閱 ProcessAction.java)在提交之時(shí)被調(diào)用,并且不顯示任何內(nèi)容,但使用 Java API HttpServletResponse.sendRedirect(String) 將客戶機(jī)瀏覽器 重定向"ShowAction"

    在表單中,可以使用客戶機(jī)格式中的所有輸入元素。WebCal 正好在登錄、注冊(cè)和顯示/編輯活動(dòng)表單上使用文本輸入字段。輸入字段的名稱將是在提交表單時(shí)調(diào)用的 POST 操作的 HTTP 參數(shù)。Servlet 可以通過(guò) Java API HttpServletRequest.getParameter(String) 獲得它們。

    有關(guān)如何避免表單處理與瀏覽器“后退”和“重新裝入”按鈕沖突這個(gè)問(wèn)題的技巧,請(qǐng)參閱 表單處理側(cè)欄。

    清單 32. 生成表單元素 顯示了 XSL 模板如何生成 HTML 輸入字段和提交按鈕。





    回頁(yè)首


    結(jié)束語(yǔ)

    本文顯示了使用 XML 和 XSL 變換來(lái)創(chuàng)建可擴(kuò)展的 Web 應(yīng)用的一種方式。對(duì)應(yīng)用數(shù)據(jù)使用一種中間格式(從而將應(yīng)用邏輯與用戶界面分開(kāi))以及不將鏈接和其它導(dǎo)航信息硬編碼,可以實(shí)現(xiàn)高度可維護(hù)性。集成新功能性的新視圖只需對(duì)導(dǎo)航 XML 進(jìn)行一些更新,以及新建該視圖的 "main" 樣式表(每種支持的格式都需要一個(gè))即可。





    回頁(yè)首


    參考資料





    回頁(yè)首


    關(guān)于作者

    Martin Gerlach 目前在 IBM Almaden 研究中心的計(jì)算機(jī)科學(xué)部門進(jìn)行畢業(yè)后的研究工作。他持有漢堡應(yīng)用科學(xué)大學(xué)的計(jì)算機(jī)科學(xué)學(xué)位。可以通過(guò) mgerlac@almaden.ibm.com 與 Martin 聯(lián)系。

    posted on 2006-03-21 23:28 Vincent.Chen 閱讀(338) 評(píng)論(0)  編輯  收藏 所屬分類: XML

    主站蜘蛛池模板: 亚洲成AV人网址| 免费萌白酱国产一区二区三区 | 免费v片在线观看视频网站| 中文字幕成人免费高清在线视频| 免费看一级高潮毛片| 美女免费精品高清毛片在线视| 精品国产亚洲AV麻豆| 亚洲色成人网站WWW永久四虎 | 久久99国产综合精品免费| 伊人免费在线观看| 亚洲入口无毒网址你懂的| 亚洲精品永久www忘忧草| 亚洲美女在线观看播放| 亚洲精品无码久久久久久久 | 免费鲁丝片一级观看| 蜜桃精品免费久久久久影院| 成人在线视频免费| 免费一级毛片在播放视频| mm1313亚洲精品无码又大又粗| 大胆亚洲人体视频| 亚洲毛片不卡av在线播放一区| 免费国产成人高清在线观看麻豆| 香蕉视频在线观看免费国产婷婷| 97国产免费全部免费观看| fc2免费人成在线视频| 欧亚一级毛片免费看| 亚洲av成人片在线观看| 亚洲乱人伦中文字幕无码| 亚洲午夜无码毛片av久久京东热| 国产精品高清视亚洲一区二区 | 亚洲国产精品人人做人人爽| 亚洲AV无码乱码在线观看牲色 | 美女隐私免费视频看| 国产精品无码免费专区午夜| 国产免费牲交视频免费播放| 中国好声音第二季免费播放| 国产婷婷成人久久Av免费高清| 久久久久国产精品免费看| 精品久久8x国产免费观看| 无码永久免费AV网站| 在线看片韩国免费人成视频|