<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)論

    讓你的 XSLT 如虎添翼 -- 淺談 XSLT 擴(kuò)展

    馬晨 , 軟件開(kāi)發(fā)專家

    2006 年 1 月 16 日

    其實(shí) XSLT 能夠做的事情很多,絕對(duì)超乎你的想象。除了格式轉(zhuǎn)換,XSLT 還能完成一些看起來(lái)和格式轉(zhuǎn)換完全無(wú)關(guān)的工作。比如說(shuō)文件訪問(wèn)或者是數(shù)據(jù)庫(kù)查詢等等。而這一切都要?dú)w功于 XSLT 擴(kuò)展(XSLT Extension)。

    XSLT 是一種基于規(guī)則的格式轉(zhuǎn)換語(yǔ)言。在許多人眼里,它的功能就是將一種格式的 xml 文件轉(zhuǎn)換成另外一種格式的 xml 文件,僅此而已。不過(guò),事實(shí)真是這樣嗎?

    其實(shí) XSLT 能夠做的事情很多,絕對(duì)超乎你的想象。除了格式轉(zhuǎn)換,XSLT 還能完成一些看起來(lái)和格式轉(zhuǎn)換完全無(wú)關(guān)的工作。比如說(shuō)文件訪問(wèn)或者是數(shù)據(jù)庫(kù)查詢等等。而這一切都要?dú)w功于 XSLT 擴(kuò)展(XSLT Extension)。

    根 據(jù) XSLT 1.0 的規(guī)范,符合標(biāo)準(zhǔn)的 XSLT 引擎應(yīng)該支持 XSLT 擴(kuò)展。也就是允許用戶自定義 XSLT 的擴(kuò)展元素(extension elements)和函數(shù)(extension functions)。今天我們所看到的主流 XSLT 引擎都按照國(guó)際標(biāo)準(zhǔn),提供了自己的擴(kuò)展方式。而開(kāi)源軟件中的 saxaon 和 xalan,在這方面走得更遠(yuǎn)。

    Saxon 和 xalan 都是基于 java 開(kāi)發(fā)的 XSLT 引擎,為它們編寫擴(kuò)展自然也基于 java。一般只要以下 3 步就可以完成一個(gè)擴(kuò)展了。

    1. 編寫一個(gè) java 類,在這個(gè)類里面設(shè)計(jì)好擴(kuò)展功能,并以靜態(tài)方法的形式提供給XSLT 引擎調(diào)用。

    2. 在 XSLT 文件中,聲明一個(gè)自定義的命名空間(namespace),該命名空間指出了類的位置

    3. 在 XSLT 文件中,在適當(dāng)?shù)牡胤剑{(diào)用擴(kuò)展即可。

    接下來(lái)讓我們看個(gè)具體的例子。

    foo_txt.xml 是一個(gè)待處理的 XML 文件,其中包含了<filename>和<content>兩個(gè)元素。現(xiàn)在希望通過(guò) XSLT 處理后,能將 <content> 的內(nèi)容寫入名稱為 <filename> 的文件中。


    圖表 1:foo_txt.xml
    												
    														
    <?xml version="1.0"?>
    <document>
    <filename>foo.txt</filename>
    <content>Hello,World!</content>
    </document>

    由于這里牽涉到針對(duì)文件的操作,因此這個(gè)任務(wù)必須通過(guò)功能擴(kuò)展來(lái)完成。讓我們對(duì)照著前文提到的 3 步法,來(lái)看看 saxon 是怎么來(lái)做的。


    圖表 2:foo_txt_saxon.xsl
    												
    														
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:user="java:com.pear.utils.FileUtil">

    <xsl:template match="document">
    <xsl:value-of select="user:output(string(filename),string(content))"/>
    </xsl:template>

    </xsl:stylesheet>

    圖表 2

    第一步,應(yīng)該是提供用戶編寫的自定義java類。由于篇幅關(guān)系,這里不再給出源碼,請(qǐng)看本文的參考部分,在那里提供了源碼下載。

    第二步,在XSLT文件開(kāi)始,通過(guò)"xmlns:user='java:com.pear.utils.FileUtil'"命令,我們定義了一個(gè)命名空間。

    最后,在處理XML節(jié)點(diǎn)的過(guò)程中,我們通過(guò)"user:output"成功地調(diào)用了用戶自定義擴(kuò)展函數(shù)。從而在XSLT中實(shí)現(xiàn)了文件寫入功能。

    看了saxon的做法之后,如果依樣畫葫蘆的對(duì)xalan也來(lái)一遍,那么就太沒(méi)意思了。幸虧xalan提供了一套更有趣的方法。

    先直接看看xalan版本的處理文件吧。


    圖表 3:foo_txt_xalan.xsl


    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xalan="http://xml.apache.org/xalan"
    xmlns:user="http://www.mac.home">

    <xalan:component prefix="user" functions="output">
    <xalan:script lang="javascript">

    function output(filename,content)
    {
    var a=new java.io.PrintWriter(filename);
    a.print(content);
    a.close();
    return "Finished!";
    }

    </xalan:script>
    </xalan:component>

    <xsl:template match="document">
    <xsl:value-of select="user:output(string(filename),string(content))"/>
    </xsl:template>

    </xsl:stylesheet>

    注意到它和saxon的版本有什么不同嗎?對(duì)了,很明顯,用戶自定義的函數(shù)直接在處理文件中就實(shí)現(xiàn)了。而且是用javascript來(lái)完成的。那么好處在哪兒呢?答案很簡(jiǎn)單,就是開(kāi)發(fā)人員可以拋開(kāi)java的編譯環(huán)境,直接設(shè)計(jì)自己的 XSLT 功能擴(kuò)展了。

    除了開(kāi)發(fā)語(yǔ)言換成了javascript 外,其它流程和 saxon 的版本還是挺像的。所以就不再詳細(xì)解釋了。

    不 過(guò)值得一提的是,光有javascript還是不夠的。在 xalan 版本中,細(xì)心的人一定會(huì)發(fā)現(xiàn),真正起作用的部分,實(shí)際上是一個(gè)名字為 PrintWriter 的 java 類。也就是說(shuō) javascript 實(shí)際上只是一個(gè)流程控制者,正是依靠著 java sdk 強(qiáng)大的類庫(kù),XSLT 才能如虎添翼,去完成不可能的任務(wù)。

    那么是不是只有自己寫擴(kuò)展才能解決問(wèn)題呢?答案當(dāng)然是否定的。saxon和xalan早就為我們預(yù)制了很多公用的擴(kuò)展功能。我們只要采用拿來(lái)主義就可以了。下面我以數(shù)據(jù)庫(kù)擴(kuò)展為例,進(jìn)一步向你展示XSLT擴(kuò)展的魅力。

    采用 saxon 引擎時(shí),我們引入了幾個(gè)新的 XSLT 擴(kuò)展元素,例如 sql:connect,sql:query。通過(guò)這些擴(kuò)展元素,我們可以連接數(shù)據(jù)庫(kù),并執(zhí)行查詢。

    比如在下例中,我們可以利用 saxon 提供的 sql 擴(kuò)展去訪問(wèn) Informix 數(shù)據(jù)庫(kù)。步驟如下:首先我們利用sql:connect建立和數(shù)據(jù)庫(kù)的連接,連接使用的參數(shù)預(yù)先已經(jīng)定義好了。

    其次,我們用sql:query進(jìn)行查詢。查詢的字段和查詢的條件,均以參數(shù)的形式出現(xiàn)。

    查詢成功之后,利用標(biāo)準(zhǔn)的XSLT元素進(jìn)行格式解析,并生成HTML格式的表格。

    最后,通過(guò)sql:close關(guān)閉連接。至此整個(gè)處理結(jié)束。


    foo_sql_query.xml

    <?xml version="1.0"?>
    <query>
    <table>FOO</table>
    <columns>username,birthdate</columns>
    <condition/>
    </query>


    foo_sql_saxon_query.xsl
    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"
    xmlns:sql="java:/net.sf.saxon.sql.SQLElementFactory"
    xmlns:saxon="http://saxon.sf.net/"
    extension-element-prefixes="saxon sql">

    <xsl:param name="driver" select="'com.informix.jdbc.IfxDriver'"/>
    <xsl:param name="database"
    select="'jdbc:informix-sqli://192.168.0.1:5000/testDB:
    INFORMIXSERVER=pcsnet;user=pcs;password=abc'"/>
    <xsl:param name="user" select="'pcs'"/>
    <xsl:param name="password" select="'abc'"/>


    <xsl:template match="/">
    <xsl:variable name="connection" as="java:java.sql.Connection"
    xmlns:java="http://saxon.sf.net/java-type">
    <sql:connect driver="{$driver}" database="{$database}" user="{$user}"
    password="{$password}"/>
    </xsl:variable>
    <HTML>
    <HEAD>
    Table of <xsl:value-of select="/query/table"/>
    </HEAD>
    <BODY>
    <TABLE border="1">
    <xsl:variable name="dbtable">
    <sql:query connection="$connection" table="{/query/table}"
    column="{/query/columns}"/>
    </xsl:variable>
    <TR>
    <xsl:if test="string-length(/query/columns)>0">
    <xsl:call-template name="getcolumns">
    <xsl:with-param name="columns" select="/query/columns"/>
    </xsl:call-template>
    </xsl:if>
    </TR>
    <xsl:apply-templates select="$dbtable/row"/>
    <xsl:text>
    </xsl:text>
    </TABLE>
    </BODY>
    </HTML>
    <sql:close connection="$connection"/>
    </xsl:template>

    <xsl:template name="getcolumns">
    <xsl:param name="columns"/>
    <xsl:if test="string-length($columns)>0">
    <TH>
    <xsl:choose>
    <xsl:when test="contains($columns,',')">
    <xsl:value-of select="substring-before($columns,',')"/>
    </xsl:when>
    <xsl:otherwise>
    <xsl:value-of select="$columns"/>
    </xsl:otherwise>
    </xsl:choose>
    </TH>
    <xsl:call-template name="getcolumns">
    <xsl:with-param name="columns" select="substring-after($columns,',')"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>

    <xsl:template match="row-set">
    <xsl:apply-templates select="row"/>
    </xsl:template>

    <xsl:template match="row">
    <TR>
    <xsl:apply-templates select="col"/>
    </TR>
    </xsl:template>

    <xsl:template match="col">
    <TD>
    <xsl:value-of select="text()"/>
    </TD>
    </xsl:template>
    </xsl:stylesheet>

    采用xalan引擎時(shí),流程和saxon差不多,不過(guò)它還是使用擴(kuò)展函數(shù)來(lái)完成數(shù)據(jù)連接和查詢的功能。


    foo_sql_xalan_query.xsl


    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"
    xmlns:sql="org.apache.xalan.lib.sql.XConnection"
    extension-element-prefixes="sql">

    <xsl:param name="driver" select="'com.informix.jdbc.IfxDriver'"/>
    <xsl:param name="database" select=
    "'jdbc:informix-sqli://192.168.0.1:5000/testDB:INFORMIXSERVER=pcsnet;user=pcs;password=abc'"/>


    <xsl:variable name="query">
    select <xsl:value-of select="/query/columns"/> from <xsl:value-of select="/query/table"/>
    </xsl:variable>

    <xsl:template match="/">
    <xsl:variable name="connection" select="sql:new($driver,$database)"/>
    <HTML>
    <HEAD>
    Table of <xsl:value-of select="/query/table"/>
    </HEAD>
    <BODY>
    <TABLE border="1">
    <xsl:variable name="table" select='sql:query($connection, $query)'/>
    <TR>
    <xsl:for-each select="$table/sql/metadata/column-header">
    <TH><xsl:value-of select="@column-label"/></TH>
    </xsl:for-each>
    </TR>

    <xsl:apply-templates select="$table/sql/row-set"/>

    <xsl:text>
    </xsl:text>
    </TABLE>
    </BODY>
    </HTML>
    <xsl:variable name="close" select="sql:close($connection)"/>
    </xsl:template>

    <xsl:template match="row-set">
    <xsl:apply-templates select="row"/>
    </xsl:template>

    <xsl:template match="row">
    <TR>
    <xsl:apply-templates select="col"/>
    </TR>
    </xsl:template>

    <xsl:template match="col">
    <TD>
    <xsl:value-of select="text()"/>
    </TD>
    </xsl:template>
    </xsl:stylesheet>

    saxon和xalan都是通過(guò)jdbc連接數(shù)據(jù)庫(kù)的,所以讀者如果手頭沒(méi)有informix,只要更換不同的數(shù)據(jù)庫(kù)驅(qū)動(dòng),以及對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接參數(shù),就可以在自己的機(jī)器上檢驗(yàn)效果了。

    以上的這些案例只是揭開(kāi)了XSLT擴(kuò)展的神秘面紗,至于怎么去發(fā)掘它的潛力,就留給富有創(chuàng)造力的讀者去完成吧。





    回頁(yè)首


    參考資料

    1. 關(guān)于saxon 的相關(guān)資料,請(qǐng)參閱Saxonic(http://www.saxonica.com
    2. 關(guān)于xalan 的相關(guān)資料,請(qǐng)參閱 Apache.org (http://xml.apache.org/xalan-j)
    3. 關(guān)于在xalan中增加對(duì)于javascript的支持,請(qǐng)參閱Bean Scripting Framework (http://jakarta.apache.org/bsf/index.html) 和 Rhino (http://www.mozilla.org/rhino
    4. 關(guān)于XSLT的相關(guān)資料,請(qǐng)參閱W3C.org(http://www.w3.org/Style/XSL/)
    5. 程序清單下載:samplecode.rar




    回頁(yè)首


    關(guān)于作者


    馬晨是上海浦東發(fā)展銀行溫州支行的軟件開(kāi)發(fā)專家。自 2000 年來(lái)已經(jīng)在多個(gè)平臺(tái)上開(kāi)發(fā)過(guò)不同的應(yīng)用。目前的工作方向主要側(cè)重于基于 xml 和 javascript 的應(yīng)用開(kāi)發(fā)。在業(yè)余時(shí)間喜歡各種運(yùn)動(dòng),尤其喜歡和朋友在周末打打羽毛球。你可以通過(guò)電子郵件(pearma@gmail.com)和他聯(lián)系。

    posted on 2006-03-18 20:45 Vincent.Chen 閱讀(385) 評(píng)論(0)  編輯  收藏 所屬分類: AJAX

    主站蜘蛛池模板: 九一在线完整视频免费观看| 免费观看激色视频网站bd| 日本亚洲视频在线| 免免费国产AAAAA片| 特级毛片免费播放| 久久精品a亚洲国产v高清不卡| 毛片a级毛片免费观看品善网| 成年免费a级毛片| 亚洲日本国产精华液| 亚洲国产午夜福利在线播放| 麻花传媒剧在线mv免费观看| 亚洲日韩在线中文字幕综合 | 成人性做爰aaa片免费看| 亚洲一线产区二线产区精华| 亚洲精品无码AV中文字幕电影网站| 亚洲免费在线视频| 狠狠热精品免费观看| 亚洲精品不卡视频| 色噜噜AV亚洲色一区二区| 成年男女男精品免费视频网站| a毛片免费在线观看| 精品久久久久久亚洲综合网| 亚洲成aⅴ人在线观看| 亚洲中文字幕无码久久精品1| 在线播放免费播放av片 | 亚洲中文字幕无码久久2017| 女人张开腿等男人桶免费视频| 久久aa毛片免费播放嗯啊| 一级看片免费视频| 亚洲日本VA中文字幕久久道具| 亚洲图片一区二区| 亚洲乱码中文字幕综合| 又黄又爽的视频免费看| 操美女视频免费网站| 1000部免费啪啪十八未年禁止观看| 国产日韩一区二区三免费高清| 成人一级免费视频| 另类专区另类专区亚洲| 亚洲国产精品无码中文lv| 亚洲av永久无码嘿嘿嘿| 亚洲综合激情九月婷婷|