樣式表也能編寫樣式表:由 XSLT 組件制作 XSLT 樣式表
級(jí)別: 初級(jí)
Alan Knox, 軟件工程師, IBM
2001 年 6 月 01 日
XSLT 樣式表可用來動(dòng)態(tài)地將 XML 變換成復(fù)雜的瀏覽器顯示標(biāo)記 -- 但如果顯示復(fù)雜,樣式表也復(fù)雜。因此需要一種能夠從簡(jiǎn)單組件構(gòu)建復(fù)雜樣式表的工具。既然 XSLT 本身就是 XML,因此可以用 XSLT 操縱 XSLT;樣式表也能編寫樣式表。本文演示如何從 XSLT 組件構(gòu)建一個(gè)執(zhí)行某一特定運(yùn)行時(shí)變換的 XSLT 樣式表。
另一篇 developerWorks 文章 讓你的XML適合所有尺寸的屏幕 討論了編寫與管理那些在很多顯示設(shè)備上顯示同一 XML 籃球統(tǒng)計(jì)信息的樣式表的問題。該解決方案涉及到編寫一個(gè)參數(shù)化的樣式表,該樣式表生成具有不同等級(jí)的數(shù)據(jù)內(nèi)容的 HTML,然后使用 WebSphere Transcoding Publisher 將該樣式表產(chǎn)生的輸出轉(zhuǎn)換成適合于某個(gè)特定設(shè)備的代碼。雖然這對(duì)于很多情況來說是一種有效和簡(jiǎn)單的解決方案,但卻喪失了對(duì)出現(xiàn)在用戶屏幕上的內(nèi)容的某些控制。
如果要:
- 完全控制用戶所見的內(nèi)容
- 調(diào)整應(yīng)用程序的顯示,以便在每一種設(shè)備上實(shí)現(xiàn)最佳的可能的效果
- 利用設(shè)備的特定特性
那么,您必須解決生成無數(shù)復(fù)雜的樣式表的問題。本文演示了一個(gè)使用相同籃球 XML 數(shù)據(jù)的非折衷解決方案。
![]() |
|
樣式表主要有兩類問題:
- 復(fù)雜性 - 新的應(yīng)用程序顯示往往需要新的樣式表。隨著標(biāo)記語言和新設(shè)備的激增,所需的樣式表的數(shù)量也變得令人生畏。如果使用 XML/XSLT 以外的方法(例如 JavaServer Pages (JSP) 或 JavaBean 體系結(jié)構(gòu)),仍然存在同樣程度的復(fù)雜性。然而,生成 JSP 的可使用的工具支持目前比支持 XSLT 樣式表的工具支持要發(fā)達(dá)得多。
- 技能 - 除了理解 XML 數(shù)據(jù)之外,樣式表作者還必須深入理解多種顯示設(shè)備的標(biāo)記語言。另外,在瀏覽器中生成在外觀吸引人的顯示也需要設(shè)計(jì)技能。而這種技能組合并非輕易可以獲得。
![]() ![]() |
![]()
|
上述問題可以通過采用基于組件的方法開發(fā)樣式表來解決。XSLT
是一種聲明性語言,其中,構(gòu)成樣式表的模板彼此獨(dú)立。XSLT
樣式表可以使用
import
和
include
機(jī)制由其它樣式表構(gòu)成。只要適當(dāng)留意,您可以分別開發(fā)一些獨(dú)立的
組件樣式表,這些組件樣式表可以一起構(gòu)成將在運(yùn)行期間應(yīng)用于
XML
數(shù)據(jù)的
顯示樣式表。這些組件將大致分為三種類型,用于處理:
- 顯示動(dòng)態(tài) XML 數(shù)據(jù)(在我的示例中是籃球數(shù)據(jù))
- 可重用的顯示標(biāo)記部分,例如按鈕欄
- 頁面殘余部分
下例演示了這種解決方案。
您可能希望您的 Web 應(yīng)用程序看上去和感覺起來設(shè)計(jì)得更專業(yè)。布局美觀的 HTML 頁面往往意味著復(fù)雜標(biāo)記、具有各種嵌入式 HTML 表的安排以及精確的格式化和間距命令。在本文中,我假設(shè)已有某個(gè)表示下面所示 頁面設(shè)計(jì)的靜態(tài) HTML。任務(wù)是用一個(gè)顯示樣式表重新生成相同的外觀和感覺。
目標(biāo)外觀和感覺

雖然這只是一個(gè)簡(jiǎn)單的示例頁面,但它也有一些嵌入的 HTML 表。它將只是多個(gè)頁面中的一個(gè),這些頁面顯示的數(shù)據(jù)來自生成 XML 形式的籃球統(tǒng)計(jì)信息的應(yīng)用程序。我將用 籃球 XML 中的數(shù)據(jù)替換 "Dynamic data"(動(dòng)態(tài)數(shù)據(jù)),然后使用 "Navigation bar"(導(dǎo)航欄)列出從當(dāng)前頁開始的鏈接。
要生成顯示樣式表,需要:
- 從設(shè)計(jì) HTML 制作一個(gè)樣式表。
- 制作一個(gè)將籃球得分格式化成 HTML 的樣式表。
- 將二者合并。
- 制作一個(gè)生成“導(dǎo)航”欄的 XSLT“窗口小部件”。
- 具體化這個(gè)窗口小部件,以生成頁面的最終樣式表。
![]() ![]() |
![]()
|
我可以只制作一個(gè) XSLT 樣式表,然后將 HTML 粘貼到適當(dāng)位置。然而,當(dāng)用戶界面設(shè)計(jì)更改時(shí),我希望能相應(yīng)地快速而輕松地更新顯示樣式表。一種比較好的解決方案是發(fā)明一個(gè)可以自動(dòng)將設(shè)計(jì) HTML 轉(zhuǎn)換成樣式表的過程。如果設(shè)計(jì) HTML 和 XML 一樣是有效的(如果不是,可以將它清除),那我就可以用 XSLT 樣式表這樣做。
首先,在設(shè)計(jì) HTML 的
<HTML>
標(biāo)記周圍添加
<layout>
元素。
帶標(biāo)記的設(shè)計(jì) HTML - skeleton.xml
|
這不一定使 HTML 變成樣式表,但確實(shí)可以讓我使用
<layout>
元素的屬性來存儲(chǔ)那些有助于推動(dòng)此過程的信息。例如,
match="game"
指定了籃球 XML 中的某個(gè)元素,我將使用該元素來觸發(fā)此頁面 HTML
的生成。
<layout>
元素內(nèi)的 HTML
本質(zhì)上是目標(biāo)頁面的 HTML 模板。因?yàn)?
模板一詞在 XSLT
的上下文中有意義,所以,我稱它為目標(biāo)頁面的 HTML
骨架。
下面是將 skeleton.xml 中的頁面骨架轉(zhuǎn)換成樣式表的樣式表。
pre-process.xsl - 第 1 版
|
該樣式表有兩個(gè)模板:
- template 1 匹配頁面骨架中的
<layout>
元素,并輸出 XSLT 樣式表。 - template 2 匹配任何其它元素或文本節(jié)點(diǎn),并只將它匹配的內(nèi)容不加更改地復(fù)制到輸出中。
因?yàn)槲蚁M藰邮奖淼妮敵鍪且粋€(gè)樣式表,所以必須輸出 XSLT 語句。但是,XSLT 處理器如何區(qū)分要輸出的 XSLT 語句和要執(zhí)行的 XSLT 語句呢?答案是對(duì)要復(fù)制到輸出的 XSLT 語句使用另一個(gè) XML 名稱空間。
在上例中,我定義了一個(gè)新的名稱空間
(
"http://www.hursley.ibm.com/hsandt/et/compile"
),并將其與名稱空間前綴
out
關(guān)聯(lián)。因?yàn)閹в?
out
前綴的 XSLT
語句不在 XSLT (
"http://www.w3.org/1999/XSL/Transform"
)
名稱空間中,所以,XSLT
處理器將按我的需要輸出它們。但這還不夠。我希望輸出是正確的樣式表,XSLT
進(jìn)程無需作任何進(jìn)一步更改就可以執(zhí)行它。在示例的這一點(diǎn)處,我將獲得看起來類似于樣式表、而實(shí)際上卻不是的東西。
XSLT 用上面所用的
<xsl:namespace-alias>
元素提供了該問題的解決方案。這將獲取
"http://www.hursley.ibm.com/hsandt/et/compile"
(
out
) 名稱空間中的所有內(nèi)容,并在輸出時(shí)將它們移到
"http://www.w3.org/1999/XSL/Transform"
(
xsl
) 名稱空間中。
將
pre-process.xsl
應(yīng)用到頁面骨架的結(jié)果看起來類似于:
從 pre-process.xsl 得到的輸出 - skeleton.xsl
|
請(qǐng)注意,名稱空間前綴仍然是
out
。這并不重要。重要的是名稱空間前綴
out
現(xiàn)在被映射成 XSLT
名稱空間:
"http://www.w3.org/1999/XSL/Transform"
。(對(duì)
XML 語法分析器很重要的是名稱空間,而不是前綴。前綴是使 XML
便于閱讀的工具)。某些 XSLT
處理器可以在輸出時(shí)更改名稱空間前綴和名稱空間。本文示例所用的 Xalan
XSLT 處理器不更改。
現(xiàn)在,可以將
skeleton.xsl
樣式表應(yīng)用到籃球數(shù)據(jù)。結(jié)果由與數(shù)據(jù)中
<game>
元素的匹配所觸發(fā),它與原始
設(shè)計(jì) HTML 文件是同樣的
HTML。目前這還不是很有用,因?yàn)樵谖蚁M吹奖荣惖梅值牡胤饺匀伙@示字符串
"Dynamic data"。我需要讓
skeleton.xsl
樣式表觸發(fā)那些在適當(dāng)位置插入得分的模板。我通過找到寫著 "Dynamic
data" 的標(biāo)記,然后將它替換成
<xsl:apply-templates>
調(diào)用來實(shí)現(xiàn)。
skeleton.xml
文件中的以下標(biāo)記:
|
|
![]() ![]() |
![]()
|
為簡(jiǎn)便起見,我只生成一個(gè)在籃球數(shù)據(jù)的
<recap>
元素中找到的得分?jǐn)?shù)據(jù)表,如下所示。
recap.xsl
|
下面的樣式表挑選出 XML 片斷。
籃球 XML 中的 <recap> 元素
|
上面的樣式表產(chǎn)生以下輸出:
|
1st | 2nd | Total |
Georgia Tech | 21 | 39 | 60 |
North Carolina State | 24 | 48 | 72 |
![]() ![]() |
![]()
|
現(xiàn)在,我有兩個(gè)樣式表:
skeleton.xsl
和
recap.xsl
。我可以通過將這兩個(gè)樣式表導(dǎo)入到名為
runtime.xsl
的新樣式表非常方便地合并它們。結(jié)果如下所示。
runtime.xsl
|
可以在運(yùn)行期間將該樣式表作為 Web 應(yīng)用程序的一部分應(yīng)用到籃球 XML 數(shù)據(jù)。樣式表中通過不同 XSLT 模板的流程如下所示:
- 首先匹配籃球數(shù)據(jù)的根節(jié)點(diǎn)。
runtime.xsl
中具有match="/"
的模板具有較高的導(dǎo)入優(yōu)先權(quán),并覆蓋recap.xsl
中的等價(jià)模板。后者只是用于recap.xsl
的獨(dú)立測(cè)試中觸發(fā)其它模板,因此,這就是我想要的行為。XSLT 處理器應(yīng)用這些模板。 - 要匹配的下一個(gè)模板是
skeleton.xsl
中具有match="game"
的模板。它將持續(xù)輸出 HTML,直到到達(dá)要輸出得分?jǐn)?shù)據(jù)的<xsl:apply-templates>
元素為止。 - 接下來要觸發(fā)的模板是
recap.xsl
中具有match="recap"
的模板。它構(gòu)建得分表標(biāo)題行,然后應(yīng)用模板來匹配用于構(gòu)建表數(shù)據(jù)行的<recapTeam>
元素。 - 構(gòu)建得分表之后,就沒有更多要匹配的輸入 XML
節(jié)點(diǎn)了。此時(shí),控制返回到
match="game"
模板,該模板輸出 HTML 的其余部分。
現(xiàn)在,我已經(jīng)實(shí)現(xiàn)了具有目標(biāo)視覺和感覺效果的動(dòng)態(tài)數(shù)據(jù)部分。下一步是實(shí)現(xiàn)導(dǎo)航欄。
![]() ![]() |
![]()
|
假設(shè)在實(shí)際站點(diǎn)上,導(dǎo)航欄在站點(diǎn)上的所有頁面中出現(xiàn),并具有特定于當(dāng)前頁面的標(biāo)題。在導(dǎo)航欄上有一些從該頁出發(fā)的固定鏈接,對(duì)于該站點(diǎn)的不同頁面,這些鏈接可能相同,也可能不同。這些鏈接只取決于當(dāng)前頁面的內(nèi)容。導(dǎo)航欄不依賴于籃球 XML 數(shù)據(jù)。
這一功能的實(shí)現(xiàn)與我剛剛對(duì)動(dòng)態(tài)數(shù)據(jù)所執(zhí)行的操作類似:將
skeleton.xml
文件中 HTML 標(biāo)記的 "Navigation bar" 部分替換成觸發(fā) XSLT 代碼的某個(gè)標(biāo)記。然而這一次,XSLT 將不由籃球數(shù)據(jù)觸發(fā),并且我希望用于構(gòu)建導(dǎo)航欄的所有 XSLT 代碼在預(yù)處理階段執(zhí)行,而不要保留到運(yùn)行期間。
首先,我將在
skeleton.xml
文件中希望出現(xiàn)導(dǎo)航欄的位置上放一個(gè)標(biāo)記。我采用以下片斷:
|
并將它編輯成:
|
我在這里發(fā)明了
navbar
標(biāo)記,并在新的
widget
名稱空間中指定它。通常,當(dāng)發(fā)明標(biāo)記來以某種新方式標(biāo)記已有 XML
時(shí),最好將新標(biāo)記放在新的名稱空間中,以防止可能發(fā)生的名稱沖突。這樣做的更有利的原因是:可以通過在
XSLT 模板中指定
match="widget:*"
來以類的形式查找和操縱頁面骨架中的“窗口小部件”。
還要注意添加到
<layout>
元素的
id="Recap"
屬性。它標(biāo)識(shí)這個(gè)頁面骨架應(yīng)用于哪個(gè)特定頁面。此信息用于確定在那個(gè)頁面的導(dǎo)航欄上出現(xiàn)的內(nèi)容。
接下來,我編寫了一個(gè) XSLT 樣式表,該樣式表將由
<widget:navbar/>
標(biāo)記觸發(fā),并將該標(biāo)記替換成正確的 HTML,以形成所期望的頁面導(dǎo)航欄。這樣的樣式表看起來可能類似于下例。
navbar.xsl
|
此樣式表獲取在其中找到
<widget:navbar/>
標(biāo)記的
<layout>
元素的
id
屬性值,并在查表期間使用該屬性作為鍵,以發(fā)現(xiàn)導(dǎo)航欄應(yīng)該包含哪些源自該頁面的鏈接。然后,構(gòu)造并返回導(dǎo)航欄的
HTML。
最后一步是更新
pre-process.xsl
樣式表,以利用 navbar 窗口小部件。我需要添加 XSLT 代碼,如下所示:
pre-process.xsl - 第 2 版
|
現(xiàn)在,可以對(duì)
skeleton.xml
文件重新運(yùn)行
pre-process.xsl
樣式表,以創(chuàng)建新版的
skeleton.xsl
。
runtime.xsl
中的
<xsl:import>
獲得新的
skeleton.xsl
。對(duì)籃球數(shù)據(jù)應(yīng)用
runtime.xsl
后產(chǎn)生:
![]() ![]() |
![]()
|
runtime.xsl 樣式表由其它三個(gè)樣式表
skeleton.xsl
、
recap.xsl
和
navbar.xsl
得到。構(gòu)建這三個(gè)樣式表所需的技能如下:
- 通過對(duì)
skeleton.xml
文件應(yīng)用自動(dòng)過程來構(gòu)建skeleton.xsl
。從靜態(tài) HTML 構(gòu)建skeleton.xml
文件非常簡(jiǎn)單,無需任何特殊的 XML 或 XSLT 技能。HTML 需要 Web 設(shè)計(jì)技能。 -
recap.xsl
需要有關(guān)的 XSLT 和應(yīng)用 XML 的知識(shí)。它輸出一些 HTML 標(biāo)記,但不需要太多 HTML 技能,因?yàn)殪o態(tài) HTML 可能包括一個(gè)樣本數(shù)據(jù)表(它將全面指定表單元顏色、邊框?qū)挾鹊龋皇? "Dynamic data" 字符串。 -
navbar.xsl
需要 XSLT 知識(shí),并且在更現(xiàn)實(shí)的示例中,可能還需要深入了解目標(biāo)標(biāo)記語言。
可以仔細(xì)地說明、開發(fā)和單獨(dú)地測(cè)試樣式表。生成動(dòng)態(tài)數(shù)據(jù)的樣式表和生成顯示的樣式表之間是有區(qū)別的。雖然 XSLT 程序員們需要同時(shí)理解顯示標(biāo)記和基本的商業(yè) XML,但對(duì)于單獨(dú)的 XSLT 程序員來說,無需同時(shí)理解二者。在本例的三個(gè)樣式表中,技術(shù)要求最高的是
navbar.xsl
,但不管怎樣,編寫可重用的 XSLT 組件正是您施展才華的所在。
![]() |
|
pre-process.xsl
樣式表獨(dú)立于它所處理的頁面骨架文件中的標(biāo)記語言。在生成其它設(shè)備(例如,用于
WAP 電話的 WML
deck)的標(biāo)記時(shí),也可以應(yīng)用完全相同的技術(shù)。創(chuàng)建新的窗口小部件只需編寫一個(gè)適當(dāng)?shù)?
XSLT 樣式表,然后將一個(gè)
<import>
元素添加到
pre-process.xsl
即可。
隨著要支持的頁面骨架和窗口小部件數(shù)目的增加,管理和操縱所有這些組件的問題也隨之成倍增加,因此需要一些工具來管理這種復(fù)雜的局面。但是,因?yàn)槊總€(gè)組件都是 XML,所以,這些工具本身也可以使用 XML??梢詫㈨撁婀羌芎痛翱谛〔考鎯?chǔ)在關(guān)系數(shù)據(jù)庫(kù)中,并使用
document()
函數(shù)從 XSLT 訪問它們。在構(gòu)建這種開發(fā)工具方面,具有 Java API 的 XSLT 處理器(例如 Xalan)將特別有用。
![]() ![]() |
![]()
|
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的
英文原文.
- 要下載本文所討論的文件:
- HTML 頁面設(shè)計(jì): design.html、 WolfpackBasketball.png和 spacer.gif
- 頁面骨架: skeleton.xml
- 導(dǎo)航欄 XSLT 組件: navbar.xsl
- 預(yù)處理器 XSLT 樣式表: pre-process.xsl
- 對(duì)
skeleton.xml
運(yùn)行pre-process.xsl
得到的 XSLT 樣式表: skeleton.xsl - 籃球數(shù)據(jù)的源 XML 文件: gt-ncsu-box.xml
- 抽取籃球得分的 XSLT 樣式表: recap.xsl
- 將在運(yùn)行期間應(yīng)用到籃球數(shù)據(jù)的 XSLT 樣式表: runtime.xsl
runtime.xsl
的 HTML 輸出: runtime.html- 包含所有文件的包: files.zip
- 有關(guān)使用 XML 的信息,請(qǐng)參考 developerWorks
XML 專區(qū)和
W3C Architecture domain。
- 有關(guān)相關(guān)主題的其它 developerWorks 文章:
- Extending the reach of your applications: A simple example using IBM WebSphere Everyplace Suite
- 改進(jìn) XSLT 編碼的五種方法
- Generate dynamic XML using JavaServer Pages technology
- Spinning your XML for screens of all sizes
- XSLT 是什么類型的語言?
- Abstracting the Interface, 第 1 部分和 第 2 部分
- 更多的 開發(fā)者園地資源。
- 有關(guān) XSLT 的信息,請(qǐng)參閱:
- W3C User Interface domain。
- XSLT Programmer's Reference(Michael Kay 著, Wrox Press,2000)為程序員提供了非常有用的 XSLT 語言討論和參考信息。
- 有關(guān)開放源碼 Xalan XSLT 處理器的信息,請(qǐng)?jiān)煸L
Apache
開放源碼站點(diǎn)。
![]() ![]() |
![]()
|
![]() |
||
|
![]() |
Alan Knox 是英國(guó)漢普郡 Hursley Park 的一名 IBM 軟件工程師。Alan 于 1997 年從 Civil Service 跳槽到 IBM。從那時(shí)起,他參與了一些使現(xiàn)有 Web 應(yīng)用程序適用于交互式電視和 WAP 電話的項(xiàng)目??梢酝ㄟ^ knox@uk.ibm.com 與 Alan 聯(lián)系 |
posted on 2006-03-21 23:49 Vincent.Chen 閱讀(482) 評(píng)論(0) 編輯 收藏 所屬分類: XML