綜述
可擴展標注語言(eXtensible Markup Language
XML)正被迅速的運用於業界
它已作為與平台
語言和協議無關的格式描述和交換數據的廣泛應用標准
XML和它的輔助規范可用於描述數據的文檔表現
描述XML文檔類型的限制
描述XML文檔和資源之間的鏈接
描述XML文檔的自動轉換和格式化
如何開發自定義標簽庫? 我使用JSP和ASP編程已經有一段頗長的時間了
在兩種服務器端的編程方式中
我越來越覺得JSP的功能要強大得多
不提別的
其中JSP的標簽庫就是我選擇JSP作為首選服務器端Web應用開發工具的原因
為什麼?因為
維護和開發的速度
在一個單一的服務器頁面中
你可以混合使用各種不同的腳本方法和對象
就?quot;混凝土
一樣
這種混合可令服務器端的腳本變得強大
並且讓服務器端的編程者設計出非常靈活和動態的Web頁面
不過這種自由的混合也有其缺點
那就是維護起來非常麻煩
特別是當項目逐漸變大時
由於最終的產品是經由一個傳統的Web設計者來維護的
因此會帶來問題
更糟糕的是
隨著代碼的復雜性增加
開發的速度就會變慢
不利於開發中等和大型的Web應用
一旦開發完
站點還要找合格的編程者來維護這些頗為復雜的代碼
幸好
JSP提供了一個很好解決的辦法
標簽庫提供了一個簡單的方法來建立一個可重用的代碼塊
一旦標簽庫設計好
它就可以在許多項目中再次使用
更方便的是
與COM和J
EE不同
你無需學習任何其它的技巧就可以建立一個標簽庫!只要你懂得寫JSP
你就可以建立一個標簽庫
標簽庫還可以改善Web應用的維護
這個是得益於JSP頁面自定義標簽的簡單XML接口
這樣
Web設計者甚至可以做到無需知道任何JSP的知識
就可以建立JSP的Web應用
這個開放式的Web開發對於團隊運作是非常有效的
JSP編程者可以建立自定義的標簽和後台的代碼模塊
而Web設計者可以使用自定義的標簽來建立Web應用
並且將精力集中在Web設計上
標簽庫的定義 JSP標簽庫(也稱自定義庫)可看成是一套產生基於XML腳本的方法
它經由JavaBeans來支持
在概念上說
標簽庫是非常簡單和可以重用的代碼構造
執行XML/XSL轉換的標簽范例和HTML頁面
<%@ taglib uri=
/jspkit/JAXP
prefix=
JAXP
%>
c:/xml/example
xml
c:/xml/example
xsl
在這個例子中
通過使用簡單的標簽來訪問後台更為強大的代碼
一個XML被裝載
並且通過一個XSL文件來產生一個結果
並發送給客戶端
全部通過使用一個簡單的標簽調用就做到了
自定義標簽為在JSP項目中創建易於重用的代碼打開了一扇大門
你所需要的只是標簽庫和它的文檔說明
標簽的組件 雖然標簽庫非常易於使用
不過要建立一個內裡的設計來支持標簽庫是頗復雜的
起碼要比建立一個簡單的JavaBean復雜
這個復雜是來自於標簽庫是由幾部分構成的
不過
你只需要知道Java和JSP的知識就夠了
一個簡單的標簽由下面的元素構成
⑴ JavaBeans
為了得到Java與生具來的面向對象的好處
可重用的代碼應該放到一個獨立的代碼容器中
這些JavaBeans並不是標簽庫的一部分
不過它是你的代碼庫用來執行相關任務的基本代碼塊
⑵ 標簽處理
這是標簽庫的真正核心
一個標簽處理器將引用它需要的任何資源(你的JavaBeans)和訪問你的JSP頁面的全部信息(pageContext對象)
JSP頁面也會將所有已經被設置的標簽屬性和JSP頁面上的標簽體中的內容傳送給標簽處理器
在標簽處理器處理完畢後
它將發回輸出到你的JSP頁面進行處理
⑶ 標簽庫的描述(tld文件)
這是一個簡單的XML文件
它記錄著標簽處理器的屬性
信息和位置
JSP容器通過這個文件來得知從哪裡及如何調用一個標簽庫
⑷ 網站的web
xml文件
這是你網站的初始化文件
在這個文件中
你定義了網站中用到的自定義標簽
以及哪個tld文件用來描述每個自定義的標簽
⑸ 分發文件(一個WAR或者JAR文件)
如果你想重用自定義標簽的話
你需要一個方法來將它由一個項目轉移到另一個項目中
將標簽庫打包為一個JAR文件是一個簡單而且有效的方式
⑹ 在你的JSP文件中作標簽庫聲明
很簡單
如果要用到該標簽的話
只要在頁面聲明一下就可以
其後
你就可以在該JSP頁面的任何地方使用它
看來要做的工作很多
不過其實並不是很難
它的要點並不在於編碼
而是在於如何將各部分正確地組織起來
不過
這樣的分層是很重要的
它可令標簽的使用靈活和更容易轉移
更重要的是
這些層的存在可讓處理建立標簽的工程通過一個JSP IDE(JSP的集成開發環境)自動完成
期望將來的JSP IDE可自動完成創建一個自定義標簽的大部分工作
這樣你只需要寫代碼和標簽處理就可以了
注意
一個標簽處理僅定義一個自定義標簽
一個標簽庫是幾個處理相同任務的標簽處理器的集合
建立自己的標簽 以下將一步一步地教你如何建立自定義的標簽
具體的例子是擴展JSP
令它擁有自己的HTML編碼功能
這個功能將所有的<和>字符用HTML代碼來代替
它可以很容易地擴展為做其它的編碼處理
為了簡化
這個例子只解釋了建立自定義標簽的基本要素
⑴ 創建一個JavaBean
你代碼中任何可重新使用的部分都應該放到一個JavaBean中
這個很重要
因為你要經常在項目的其它地方用到這些代碼
放在標簽處理器中的任何代碼在標簽外都是不可以重新使用的
因此將可重用的代碼部分獨立開來是很重要的
在這個例子總
為HTML編碼的邏輯是常用的
因此放到JavaBean中
⑵ HTML編碼JavaBean
/* HTML_Format
Java */
public class HTML_Format extends Object implements Java
io
Serializable {
/** 創建新的HTML_Format */
public HTML_Format() {}
/** 將一個字符串中所有的所有 < 和 > 字符用響應的HTML編碼代替 */
public String HTML_Encode(String as_data)
{
int li_len = as_data
length();
/*string buffer的長度要比原來的字符串長*/
StringBuffer lsb_encode = new StringBuffer(li_len + (li_len/
));
/* 循環替換全部的< 和 > 字符 */
for( int li_count =
; li_count < li_len ; li_count++)
{ String ls_next = String
valueOf(as_data
charAt(li_count));
if (ls_next
equals(
<
)) ls_next =
<
;
if (ls_next
equals(
>
)) ls_next =
>
;
lsb_encode
append( ls_next );
}
return( lsb_encode
toString() );
}
}
⑶ 創建一個標簽處理器
標簽處理器使用以下的代碼
HTML編碼標簽處理器
import Java
io
IOException;
import Javax
servlet
jsp
*;
import Javax
servlet
jsp
tagext
*;
public class HTML_FormatTag extends BodyTagSupport
{
/*
} 在標簽末將會調用這個函數 */
public int doEndTag() throws JspTagException
{
try
{ /*
}得到標簽中的文本 */
BodyContent l_tagbody = getBodyContent();
String ls_output =
;
/*
}如果標簽體有文本
就處理它 */
if(l_tagbody != null)
{ HTML_Format l_format = new HTML_Format();
/*
a} 將標簽體的內容轉換為一個字符串 */
String ls_html_text = l_tagbody
getString();
ls_output = l_format
HTML_Encode(ls_html_text);
}
/*
}將結果寫回到數據流中 */
pageContext
getOut()
write(ls_output
trim());
}
catch (IOException e)
{ throw new JspTagException(
Tag Error:
+ e
toString());
}
/* 讓JSP繼續處理以下頁面的內容 */
return EVAL_PAGE;
}
}
這個處理很簡單
它包括有
o 讀入標簽開始和結束間的文本
o 調用html編碼函數
o 返回結果到JSP頁面
⑷ 創建一個標簽描述器
需要描述自定義標簽以讓系統知道如何處理
該描述文件的後綴為
tld
通常它的名字和標簽處理器相同
並存放在
/WEB
INF/
目錄
HTML編碼標簽描述器
<?xml version=
encoding=
UTF
?>
<!DOCTYPE taglib
PUBLIC
//Sun Microsystems
Inc
//DTD JSP Tag Library
//EN
jsptaglibrary_
_
dtd
>
<TAGLIB>
<TLIBVERSION>
</TLIBVERSION>
<JSPVERSION>
</JSPVERSION>
<SHORTNAME>HTML_FormatTag</SHORTNAME>
<URI></URI>
<INFO>HTML Encoding Tag </INFO>
<TAG>
<NAME>HTMLEncode</NAME>
<TAGCLASS>HTML_FormatTag</TAGCLASS>
<INFO>Encode HTML</INFO>
</TAG>
</TAGLIB>
⑸ 更新Web XML文件
現在可告訴JSP容器使用標簽庫
為此要修改web
xml文件
具體說來是要在其中加入一個taglib的項目來注冊該標簽庫
最重要的是
要為tag分配一個URI
URI是一個唯一的引用
只應用在該網站的這個特別的標簽上
使用全長的URL或者包名是一個好的習慣
它可以確保唯一性
因為該標簽可以在不同的網站使用
這個例子是簡化了
修改web
xml文件
<?xml version=
encoding=
ISO
?>
<!DOCTYPE web
app
PUBLIC
//Sun Microsystems
Inc
//DTD Web Application
//EN
app_
dtd
>
<WEB
APP>
<TAGLIB>
<TAGLIB
URI>
HTMLEncode
</TAGLIB
URI>
<TAGLIB
LOCATION>
/WEB
INF/HTML_FormatTag
tld
</TAGLIB
LOCATION>
</TAGLIB>
</WEB
APP>
⑹ 使用新的標簽
自定義的標簽已經設置好
可以用在一個JSP頁面上
要做到這一點
只需在該頁面使用taglib指示命令聲明一下該標簽就可以了
該標簽通過它唯一的URI被引用
並且會被分配一個名字空間前綴
前綴可以任意
只要它不與其它的名字空間沖突便可
在一個JSP頁面上使用HTML編碼標簽
<%@ taglib uri=
HTMLEncode
prefix=
Examples
%>
<PRE>
<?XML:NAMESPACE PREFIX = Examples /><Examples:HTMLEncode>
< Hello
Simple sample >
</Examples:HTMLEncode>
</PRE>
范例代碼的輸出
< Hello
Simple sample >
which displays as:
< Hello
Simple sample >
通過這個標簽我就將該頁面的所有代碼編碼了有趣的是所有的自定義標簽都是在服務器上處理的這意味著你將不會在輸出的頁面上看到自定義的標簽
建立一個標簽不是很難吧最困難的部分是要學習標簽處理的所有細節這是一個很強大的功能我們只是提到了最基本的地方由於這個處理需要幾步新的JSP編程者在創建標簽時將會感到迷惑
如何利用JSP開發DOM應用?
DOM是Document Object Model的縮寫
即文檔對象模型
XML將數據組織為一顆樹
所以DOM就是對這顆樹的一個對象描敘
通俗的說
就是通過解析XML文檔
為XML文檔在邏輯上建立一個樹模型
樹的節點是一個個對象
我們通過存取這些對象就能夠存取XML文檔的內容
下面我們來看一個簡單的例子
看看在DOM中
我們是如何來操作一個XML文檔的
這是一個XML文檔
也是我們要操作的對象
<?xml version= encoding=UTF?>
<messages>
<message>Goodbye serialization hello Java!</message>
</messages>
下面我們需要把這個文檔的內容解析到一個個的Java對象中去供程序使用利用JAXP我們只需幾行代碼就能做到這一點首先我們需要建立一個解析器工廠以利用這個工廠來獲得一個具體的解析器對象
DocumentBuilderFactory dbf = DocumentBuilderFactorynewInstance();
我們在這裡使用DocumentBuilderFacotry的目的是為了創建與具體解析器無關的程序當DocumentBuilderFactory類的靜態方法newInstance()被調用時它根據一個系統變量來決定具體使用哪一個解析器又因為所有的解析器都服從於JAXP所定義的接口所以無論具體使用哪一個解析器代碼都是一樣的所以當在不同的解析器之間進行切換時只需要更改系統變量的值而不用更改任何代碼這就是工廠所帶來的好處
DocumentBuilder db = dbfnewDocumentBuilder();
當獲得一個工廠對象後使用它的靜態方法newDocumentBuilder()方法可以獲得一個DocumentBuilder對象這個對象代表了具體的DOM解析器但具體是哪一種解析器微軟的或者IBM的對於程序而言並不重要
然後我們就可以利用這個解析器來對XML文檔進行解析了
Document doc = dbparse(c:/xml/messagexml);
DocumentBuilder的parse()方法接受一個XML文檔名作為輸入參數返回一個Document對象這個Document對象就代表了一個XML文檔的樹模型以後所有的對XML文檔的操作都與解析器無關直接在這個Document對象上進行操作就可以了而具體對Document操作的方法就是由DOM所定義的了
從得到的Document對象開始我們就可以開始我們的DOM之旅了使用Document對象的getElementsByTagName()方法我們可以得到一個NodeList對象一個Node對象代表了一個XML文檔中的一個標簽元素而NodeList對象觀其名而知其意所代表的是一個Node對象的列表
NodeList nl = docgetElementsByTagName(message);
我們通過這樣一條語句所得到的是XML文檔中所有<message>標簽對應的Node對象的
一個列表然後我們可以使用NodeList對象的item()方法來得到列表中的每一個Node對象
Node my_node = em();
當一個Node對象被建立之後保存在XML文檔中的數據就被提取出來並封裝在這個Node中了在這個例子中要提取Message標簽內的內容我們通常會使用Node對象的getNodeValue()方法
String message = my_nodegetFirstChild()getNodeValue();
請注意這裡還使用了一個getFirstChild()方法來獲得message下面的第一個子Node對象雖然在message標簽下面除了文本外並沒有其它子標簽或者屬性但是我們堅持在這裡使用getFirseChild()方法這主要和WC對DOM的定義有關WC把標簽內的文本部分也定義成一個Node所以先要得到代表文本的那個Node我們才能夠使用getNodeValue()來獲取文本的內容現在既然我們已經能夠從XML文件中提取出數據了我們就可以把這些數據用在合適的地方來構築應用程序
DOM實例
先說說這個例子到底要做的是什麼吧我們在一個名為linkxml文件中保存了一些URL地址我們希望可以通過DOM把這些URL讀出並顯示出來也可以反過來向這個XML文件中寫入加入的URL地址很簡單卻很實用也足夠來例示DOM的絕大部分用法了
第一個程序我們稱為xmldisplayJava主要的功能就是讀取這個XML文件中各個節點的內容然後在格式化輸出在Systemout上我們來看看這個程序
import Javaxxmlparsers*;
import orgwcdom*;
這是引入必要的類因為在這裡使用的是Sun所提供的XML解析器因而需要引入Javaxmlparsers包其中包含了有DOM解析器和SAX解析器的具體實現orgwcdom包中定義了wc所制定的DOM接口
DocumentBuilderFactory factory = DocumentBuilderFactorynewInstance();
DocumentBuilder builder=factorynewDocumentBuilder();
Document doc=builderparse(linksxml);
docnormalize();
除了上面講到的還有一個小技巧對Document對象調用normalize()可以去掉XML文檔中作為格式化內容的空白而映射在DOM樹中的不必要的Text Node對象否則你得到的DOM樹可能並不如你所想象的那樣特別是在輸出的時候這個normalize()更為有用
NodeList links =docgetElementsByTagName(link);
剛才說過XML文檔中的空白符也會被作為對象映射在DOM樹中因而直接調用Node方法的getChildNodes方法有時候會有些問題有時不能夠返回所期望的NodeList對象解決的辦法是使用Element的getElementByTagName(String)返回的NodeLise就是所期待的對象了然後可以用item()方法提取想要的元素
for (int i=;i<linksgetLength();i++){
Element link=(Element) em(i);
Systemoutprint(Content: );
Systemoutprintln(linkgetElementsByTagName(textem()getFirstChild();
getNodeValue());
……
上面的代碼片斷就完成了對XML文檔內容的格式化輸出只要注意到一些細節的問題比如getFirstChile()方法和getElementsByTagName()方法的使用這些還是比較容易的
下面的內容就是在修改了DOM樹後重新寫入到XML文檔中去的問題了這個程序名為xmlwriteJava在JAXP版本中並沒有直接的類和方法能夠處理XML文檔的寫入問題需要借助其它包中的一些輔助類而在JAXP版本中引入了對XSLT的支持所謂XSLT就是對XML文檔進行變換(Translation)後得到一個新的文檔結構利用這個新加入的功能我們就能夠很方便的把新生成或者修改後的DOM樹從新寫回到XML文件中去了下面我們來看看代碼的實現這段代碼的主要功能是向linksxml文件中加入一個新的link節點
import Javaxxmlparsers*;
import Javaxxmltransform*;
import JavaxxmltransformdomDOMSource;
import JavaxxmltransformstreamStreamResult;
import orgwcdom*;
新引入的Javaxmltransform包中的幾個類就是用來處理XSLT變換的
我們希望在上面的XML文件中加入一個新的link節點因而首先還是要讀入linksxml文件構建一個DOM樹然後再對這個DOM樹進行修改(添加節點)最後把修改後的DOM寫回到linksxml文件中
DocumentBuilderFactory factory = DocumentBuilderFactorynewInstance();
DocumentBuilder builder=factorynewDocumentBuilder();
Document doc=builderparse(linksxml);
docnormalize();
//取得變量
String text=Hanzhongs Homepage;
String url=;
String author=Hzliu Liu;
String discription=A site from Hanzhong Liu give u lots of suprise!!!;
為了看清重點簡化程序我們把要加入的內容硬編碼到記憶String對象中而實際操作中往往利用一個界面來提取用戶輸入或者通過JDBC從數據庫中提取想要的內容
Text textseg;
Element link=doccreateElement(link);
首先應該明了的是無論什麼類型的NodeText型的也好Attr型的也好Element型的也好它們的創建都是通過Document對象中的createXXX()方法來創建的(XXX代表具體要創建的類型)因此我們要向XML文檔中添加一個link項目首先要創建一個link對象
Element linktext=doccreateElement(text);
textseg=doccreateTextNode(text);
linktextappendChild(textseg);
linkappendChild(linktext);
……
創建節點的過程可能有些千篇一律但需要注意的地方是對Element中所包含的text(在DOM中這些text也是代表了一個Node的因此也必須為它們創建相應的node)不能直接用Element對象的setNodeValue()方法來設置這些text的內容而需要用創建的Text對象的setNodeValue()方法來設置文本這樣才能夠把創建的Element和其文本內容添加到DOM樹中看看前面的代碼你會更好的理解這一點
docgetDocumentElement()appendChild(link);
最後不要忘記把創建好的節點添加到DOM樹中Document類的getDocumentElement()方法返回代表文檔根節點的Element對象在XML文檔中根節點一定是唯一的
TransformerFactory tFactory =TransformerFactorynewInstance();
Transformer transformer = tFactorynewTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new JavaioFile(linksxml));
transformertransform(source result);
然後就是用XSLT把DOM樹輸出了這裡的TransformerFactory也同樣應用了工廠模式使得具體的代碼同具體的變換器無關實現的方法和DocumentBuilderFactory相同這兒就不贅述了Transformer類的transfrom方法接受兩個參數一個數據源Source和一個輸出目標Result這裡分別使用的是DOMSource和StreamResult這樣就能夠把DOM的內容輸出到一個輸出流中當這個輸出流是一個文件的時候DOM的內容就被寫入到文件中去了
如何利用JSP開發SAX應用?
SAX是Simple API for XML的縮寫
它並不是由W
C官方所提出的標准
可以說是
民間
的事實標准
實際上
它是一種社區性質的討論產物
雖然如此
在XML中對SAX的應用絲毫不比DOM少
幾乎所有的XML解析器都會支持它
與DOM比較而言
SAX是一種輕量型的方法
我們知道
在處理DOM的時候
我們需要讀入整個的XML文檔
然後在內存中創建DOM樹
生成DOM樹上的每個Node對象
當文檔比較小的時候
這不會造成什麼問題
但是一旦文檔大起來
處理DOM就會變得相當費時費力
特別是其對於內存的需求
也將是成倍的增長
以至於在某些應用中使用DOM是一件很不劃算的事(比如在applet中)
這時候
一個較好的替代解決方法就是SAX
SAX在概念上與DOM完全不同
首先
不同於DOM的文檔驅動
它是事件驅動的
也就是說
它並不需要讀入整個文檔
而文檔的讀入過程也就是SAX的解析過程
所謂事件驅動
是指一種基於回調(callback)機制的程序運行方法
(如果你對Java新的代理事件模型比較清楚的話
就會很容易理解這種機制了)在XMLReader接受XML文檔
在讀入XML文檔的過程中就進行解析
也就是說讀入文檔的過程和解析的過程是同時進行的
這和DOM區別很大
解析開始之前
需要向XMLReader注冊一個ContentHandler
也就是相當於一個事件監聽器
在ContentHandler中定義了很多方法
比如startDocument()
它定制了當在解析過程中
遇到文檔開始時應該處理的事情
當XMLReader讀到合適的內容
就會拋出相應的事件
並把這個事件的處理權代理給ContentHandler
調用其相應的方法進行響應
這樣泛泛的說來或許有些不容易理解
別急
後面的例子會讓你明白SAX的解析過程
看看這個簡單XML文件
<POEM>
<AUTHOR>Ogden Nash</AUTHOR>
<TITLE>Fleas</TITLE>
<LINE>Adam</LINE>
</POEM>
當XMLReader讀到<POEM>標簽時
就會調用ContentHandler
startElement()方法
並把標簽名POEM作為參數傳遞過去
在你實現的startElement()方法中需要做相應的動作
以處理當<POEM>出現時應該做的事情
各個事件隨著解析的過程(也就是文檔讀入的過程)一個個順序的被拋出
相應的方法也會被順序的調用
最後
當解析完成
方法都被調用後
對文檔的處理也就完成了
下面的這個表
列出了在解析上面的那個XML文件的時候
順序被調用的方法
遇到的項目 方法回調
{文檔開始} startDocument()
<POEM> startElement(null
POEM
null
{Attributes})
\n
characters(
<POEM>\n
)
<AUTHOR> startElement(null
AUTHOR
null
{Attributes})
Ogden Nash
characters(
<POEM>\n
)
</AUTHOR> endElement(null
AUTHOR
null)
\n
characters(
<POEM>\n
)
<TITLE> startElement(null
TITLE
null
{Attributes})
Fleas
characters(
<POEM>\n
)
</TITLE> endElement(null
TITLE
null)
\n
characters(
<POEM>\n
)
<LINE> startElement(null
LINE
null
{Attributes})
Adam
characters(
<POEM>\n
)
</LINE> endElement(null
LINE
null)
\n
characters(
<POEM>\n
)
</POEM> endElement(null
POEM
null)
{文檔結束} endDocument()
ContentHandler實際上是一個接口
當處理特定的XML文件的時候
就需要為其創建一個實現了ContentHandler的類來處理特定的事件
可以說
這個實際上就是SAX處理XML文件的核心
下面我們來看看定義在其中的一些方法
void characters(char[] ch
int start
int length)
這個方法用來處理在XML文件中讀到字符串
它的參數是一個字符數組
以及讀到的這個字符串在這個數組中的起始位置和長度
我們可以很容易的用String類的一個構造方法來獲得這個字符串的String類
String charEncontered=new String(ch
start
length)
void startDocument()
當遇到文檔的開頭的時候
調用這個方法
可以在其中做一些預處理的工作
void endDocument()
和上面的方法相對應
當文檔結束的時候
調用這個方法
可以在其中做一些善後的工作
void startElement(String namespaceURI
String localName
String qName
Attributes atts)
當讀到一個開始標簽的時候
會觸發這個方法
在SAX
版本中並不支持名域
而在新的
版本中提供了對名域的支持
這兒參數中的namespaceURI就是名域
localName是標簽名
qName是標簽的修飾前綴
當沒有使用名域的時候
這兩個參數都未null
而atts是這個標簽所包含的屬性列表
通過atts
可以得到所有的屬性名和相應的值
要注意的是SAX中一個重要的特點就是它的流式處理
在遇到一個標簽的時候
它並不會紀錄下以前所碰到的標簽
也就是說
在startElement()方法中
所有你所知道的信息
就是標簽的名字和屬性
至於標簽的嵌套結構
上層標簽的名字
是否有子元屬等等其它與結構相關的信息
都是不得而知的
都需要你的程序來完成
這使得SAX在編程處理上沒有DOM來得那麼方便
void endElement(String namespaceURI
String localName
String qName)
這個方法和上面的方法相對應
在遇到結束標簽的時候
調用這個方法
我們還是沿用講DOM的時候使用的那個文檔例子
但首先
我們先看一個簡單一些的應用
我們希望能夠統計一下XML文件中各個標簽出現的次數
這個例子很簡單
但是足以闡述SAX編程的基本思路了
一開始當然還是import語句了
import org
xml
sax
helpers
DefaultHandler;
import Javax
xml
parsers
*;
import org
xml
sax
*;
import org
xml
sax
helpers
*;
import Java
util
*;
import Java
io
*;
然後
我們創建一個繼承於DefaultHandler的類
具體的程序邏輯在這兒可以暫且放在一邊
要注意的是程序的結構
public class SAXCounter extends DefaultHandler {
private Hashtable tags; //這個Hashtable用來記錄tag出現的次數
// 處理文檔前的工作
public void startDocument() throws SAXException {
tags = new Hashtable();//初始化Hashtable
}
//對每一個開始元屬進行處理
public void startElement(String namespaceURI
String localName
String rawName
Attributes atts)
throws SAXException
{
String key = localName;
……
我們來看看這段程序作了些什麼
在main()方法中
主要做的就是創建解析器
然後解析文檔
實際上
在這兒創建SAXParser對象的時候
為了使程序代碼於具體的解析器無關
使用了同DOM中一樣的設計技巧
通過一個SAXParserFactory類來創建具體的SAXParser對象
這樣
當需要使用不同的解析器的時候
要改變的
只是一個環境變量的值
而程序的代碼可以保持不變
這就是FactoryMethod模式的思想
在這兒不再具體講了
如果還有不明白的
可以參看上面DOM中的解釋
原理是一樣的
不過在這兒還有一點點要注意的地方
就是SAXParser類和XMLReader類之間的關系
你可能有些迷糊了吧
實際上SAXParser是JAXP中對XMLReader的一個封裝類
而XMLReader是定義在SAX
種的一個用來解析文檔的接口
你可以同樣的調用SAXParser或者XMLReader中的parser()方法來解析文檔
效果是完全一樣的
不過在SAXParser中的parser()方法接受更多的參數
可以對不同的XML文檔數據源進行解析
因而使用起來要比XMLReader要方便一些
這個例子僅僅涉及了SAX的一點皮毛
而下面的這個
可就要高級一些了
下面我們要實現的功能
在DOM的例子中已經有實現了
就是從XML文檔中讀出內容並格式化輸出
雖然程序邏輯看起來還是很簡單
但是SAX可不比DOM哦
看著吧
前面說過
當遇到一個開始標簽的時候
在startElement()方法中
我們並不能夠得到這個標簽在XML文檔中所處的位置
這在處理XML文檔的時候是個大麻煩
因為在XML中標簽的語義
有一部分是由其所處的位置所決定的
而且在一些需要驗證文檔結構的程序中
這更是一個問題
當然
沒有解決不了的問題了
我們可以使用一個棧來實現對文檔結構的紀錄
棧的特點是先進先出
我們現在的想法是
在startElemnt()方法中用push將這個標簽的名字添加到棧中
在endElement()方法中在把它pop出來
我們知道對一個結構良好的XML而言
其嵌套結構是完備的
每一個開始標簽總會對應一個結束標簽
而且不會出現標簽嵌套之間的錯位
因而
每一次startElement()方法的調用
必然會對應一個endElement()方法的調用
這樣push和pop也是成對出現的
我們只需要分析棧的結構
就可以很容易的知道當前標簽所處在文檔結構中的位置了
public class SAXReader extends DefaultHandler {
Java
util
Stack tags=new Java
util
Stack();
……
在這兒雖然沒有使用到棧的分析
但實際上棧的分析是一件很容易的事情
應為Java
util
Stack繼承了Java
util
Vector類
而且Stack中的元素是按棧的結構由底至上排列的
因個
我們可以使用Vector類的size()方法來得到Stack的元素個數
還可以使用Vector的get(int)方法來得到具體的每一個元屬
實際上
如果把Stack的元素從底向上逐一排列出來
我們就得到了從XML根節點到當前節點的一條唯一的路徑
有了這條路徑的信息
文檔的結構就在清楚不過了
到目前為止
我們已經掌握了對於XML編程的兩大利器
DOM和SAX
也知道了該如何在一個Java程序中使用它們
DOM編程相對簡單
但是速度比較慢
占用內存多
而S AX編程復雜一些
但是速度快
占用內存少
所以
我們應該根據不同的環境選擇使用不同的方法
大部分的XML應用基本都可以用它們來解決
需要特別說明的是
DOM和SAX其實都是語言無關的
並非Java所獨有
也就是說
只要有相應的語言實現
DOM和SAX可以應用在任何面向對象的語言中
From:http://tw.wingwit.com/Article/program/Java/Javascript/201311/25312.html