主頁(yè) > 知識(shí)庫(kù) > Java編程中更新XML文檔的常用方法

Java編程中更新XML文檔的常用方法

熱門標(biāo)簽:地圖標(biāo)注人員兼職 漯河辦理400電話 騰訊地圖標(biāo)注商戶改名注冊(cè)入駐 怎樣把地圖標(biāo)注出來 開封便宜外呼系統(tǒng)報(bào)價(jià) 電話機(jī)器人的特色和創(chuàng)新 商丘百應(yīng)電話機(jī)器人有沒有效果 黃石智能營(yíng)銷電銷機(jī)器人效果 淮南騰訊地圖標(biāo)注

   本文簡(jiǎn)要的討論了Java語言編程中更新XML文檔的四種常用方法,并且分析這四種方法的優(yōu)劣。其次,本文還對(duì)如何控制Java程序輸出的XML文檔的格式做了展開論述。

  JAXP是Java API for XML Processing的英文字頭縮寫,中文含義是:用于XML文檔處理的使用Java語言編寫的編程接口。JAXP支持DOM、SAX、XSLT等標(biāo)準(zhǔn)。為了增強(qiáng)JAXP使用上的靈活性,開發(fā)者特別為JAXP設(shè)計(jì)了一個(gè)Pluggability Layer,在Pluggability Layer的支持之下,JAXP既可以和具體實(shí)現(xiàn)DOM API、SAX API 的各種XML解析器(XML Parser,例如Apache Xerces)聯(lián)合工作,又可以和具體執(zhí)行XSLT標(biāo)準(zhǔn)的XSLT處理器(XSLT Processor,例如Apache Xalan)聯(lián)合工作。應(yīng)用Pluggability Layer的好處在于:我們只需要熟悉JAXP各個(gè)編程接口的定義即可,而不需要對(duì)所采用的具體的XML解析器、XSLT處理器有很深入的了解。比如在某個(gè)Java程序中,通過JAXP調(diào)用XML解析器Apache Crimson對(duì)XML文檔進(jìn)行處理,如果我們希望使用別的XML解析器(比如Apache Xerces),以便提高該程序的性能,那么原程序代碼可能不需要任何改變,直接就可以使用(你所需要做的事情只是將包含Apache Xerces代碼的jar文件加入到環(huán)境變量CLASSPATH中,而將包含Apache Crimson代碼的jar文件在環(huán)境變量CLASSPATH中刪除)。

  目前JAXP已經(jīng)應(yīng)用的十分普遍了,可以說是Java語言中處理XML文檔的標(biāo)準(zhǔn)API。有些初學(xué)者在學(xué)習(xí)使用JAXP的過程中,經(jīng)常會(huì)提出這樣的問題:我編寫的程序?qū)OM Tree做了更新,但是當(dāng)程序退出以后,原始的XML文檔并沒有改變,還是老樣子,如何實(shí)現(xiàn)對(duì)原始XML文檔和DOM Tree的同步更新呢?咋一看來,在JAXP中似乎沒有提供相應(yīng)的接口/方法/類,這是很多初學(xué)者都感到困惑的問題。本文的主旨就在于解決這個(gè)問題,簡(jiǎn)單的介紹幾種常用的同步更新原始XML文檔和DOM Tree的方法。為了縮小討論的范圍,本文所涉及的XML解析器僅包括Apache Crimson和Apache Xerces,而XSLT處理器僅僅使用Apache Xalan。

  方法一:直接讀寫XML文檔

  這也許是最笨最原始的辦法了。當(dāng)程序獲取DOM Tree之后,應(yīng)用DOM模型的Node接口的各個(gè)方法對(duì)DOM Tree進(jìn)行更新,下一步應(yīng)該對(duì)原始的XML文檔進(jìn)行更新了。我們可以運(yùn)用遞歸的辦法或者是應(yīng)用TreeWalker類,遍歷整個(gè)DOM Tree,與此同時(shí),將DOM Tree的每一個(gè)節(jié)點(diǎn)/元素依次寫入到預(yù)先打開的原始XML文檔中,當(dāng)DOM Tree被遍歷完全之后,DOM Tree和原始的XML文檔就實(shí)現(xiàn)了同步更新。實(shí)際中,這個(gè)方法極少使用,不過如果你要編程實(shí)現(xiàn)自己的XML解析器,這種方法還是有可能用得上的。

  方法二:使用XmlDocument類

  使用XmlDocument類?JAXP中分明沒有這個(gè)類呀!是不是作者搞錯(cuò)了?沒有錯(cuò)!就是使用XmlDocument類,確切的說,是使用XmlDocument類的write()方法。

  在上文已經(jīng)提到過,JAXP可以和各種各樣的XML解析器聯(lián)合使用,這次我們選用的XML解析器是Apache Crimson。XmlDocument(org.apache.crimson.tree.XmlDocument)是Apache Crimson的一個(gè)類,并不包含于標(biāo)準(zhǔn)的JAXP中,難怪在JAXP的文檔中找不到XmlDocument類的芳蹤呢?,F(xiàn)在問題出來了,如何應(yīng)用XmlDocument類來實(shí)現(xiàn)更新XML文檔的功能?在XmlDocument類中提供了下面三個(gè)write()方法(根據(jù)Crimson最新的版本------Apache Crimson 1.1.3):

public void write (OutputStream out) throws IOException
public void write (Writer out) throws IOException
public void write (Writer out, String encoding) throws IOException

  上述三個(gè)write()方法的主要作用就是輸出DOM Tree中的內(nèi)容到特定的輸出介質(zhì)中,比如文件輸出流、應(yīng)用程序控制臺(tái)等等。那么又如何使用上述三個(gè)write()方法呢?請(qǐng)看下面的Java程序代碼片斷:

String name="fancy";
DocumentBuilder parser;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try
{
 parser = factory.newDocumentBuilder();
 Document doc = parser.parse("user.xml");
 Element newlink=doc.createElement(name);
 doc.getDocumentElement().appendChild(newlink);
((XmlDocument)doc).write(new FileOutputStream(new File("xuser1.xml")));
}
catch (Exception e)
{
 //to log it
}


  在上面的代碼中,首先創(chuàng)建了一個(gè)Document對(duì)象doc,獲取完整的DOM Tree,然后應(yīng)用Node接口的appendChild()方法,在DOM Tree的最后追加了一個(gè)新節(jié)點(diǎn)(fancy),最后調(diào)用XmlDocument類的write(OutputStream out)方法,把DOM Tree中的內(nèi)容輸出到xuser.xml中(其實(shí)也可以輸出到user.xml,更新原始的XML文檔,在這里為了便于做對(duì)比,故而輸出到xuser.xml文件中)。需要注意的是不能直接對(duì)Document對(duì)象doc直接調(diào)用write()方法,因?yàn)镴AXP的Document接口并沒有定義任何write()方法,所以必須將doc由Document對(duì)象強(qiáng)制轉(zhuǎn)換為XmlDocument對(duì)象,然后才能調(diào)用write()方法,在上面的代碼中使用的是write(OutputStream out)方法,這個(gè)方法使用缺省的UTF-8編碼輸出DOM Tree中的內(nèi)容到特定的輸出介質(zhì)中,如果DOM Tree中包含中文字符,那么輸出的結(jié)果有可能是亂碼,亦即存在所謂的"漢字問題",解決的辦法是使用write (Writer out, String encoding)方法,顯式指定輸出時(shí)的編碼,例如將第二個(gè)參數(shù)設(shè)為"GB2312",這時(shí)即不存在"漢字問題",輸出結(jié)果能夠正常顯示中文字符。

  完整的例子請(qǐng)參考下列文件: AddRecord.java(見附件)、user.xml(見附件)。該例子的運(yùn)行環(huán)境為:Windows XP Professional、JDK 1.3.1。為了能夠正常編譯運(yùn)行AddRecord.java這個(gè)程序,你需要到網(wǎng)址http://xml.apache.org/dist/crimson/去下載Apache Crimson,并將所獲取的crimson.jar文件加入到環(huán)境變量CLASSPATH中。

  注意:

  Apache Crimson的前身是Sun Project X Parser,后來不知何故,由X Parser演變?yōu)锳pache Crimson,至今Apache Crimson的很多代碼都是從X Parser中直接移植過來的。比如上文用到的XmlDocument類,它在X Parser中是com.sun.xml.XmlDocument,到了Apache Crimson中搖身一變,就變成了org.apache.crimson.tree.XmlDocument類,其實(shí)它們的絕大部分代碼是一樣的,可能就package語句和import語句以及文件開頭的一段lience有所不同而已。早期的JAXP是和X Parser捆綁在一起的,因此一些老的程序使用了com.sun.xml包,如果你現(xiàn)在重新編譯它們,有可能不能通過,肯定就是因?yàn)檫@個(gè)原因。后來的JAXP和Apache Crimson捆綁在一起,比如JAXP 1.1,如果你使用JAXP 1.1,那么不需要額外下載Apache Crimson,也能夠正常編譯運(yùn)行上面的例子(AddRecord.java)。最新的JAXP 1.2 EA(Early Access)改弦更張,采用性能更好的Apache Xalan和Apache Xerces分別作為XSLT處理器和XML解析器,不能直接支持Apache Crimson了,所以如果你的開發(fā)環(huán)境采用了JAXP 1.2 EA或者是Java XML Pack(內(nèi)含JAXP 1.2 EA),那么將無法直接編譯運(yùn)行上面的例子(AddRecord.java),你需要額外下載并安裝Apache Crimson。

  方法三:使用TransformerFactory和Transformer類

  在JAXP中所提供的標(biāo)準(zhǔn)的更新原始XML文檔的方法就是調(diào)用XSLT引擎,亦即使用TransformerFactory和Transformer類。請(qǐng)看下面的Java代碼片斷:

//首先創(chuàng)建一個(gè)DOMSource對(duì)象,該構(gòu)造函數(shù)的參數(shù)可以是一個(gè)Document對(duì)象
//doc代表更改后的DOM Tree。
DOMSource doms = new DOMSource (doc);

//創(chuàng)建一個(gè)File對(duì)象,代表DOM Tree所包含的數(shù)據(jù)的輸出介質(zhì),這是一個(gè)XML文件。
File f = new File ("XMLOutput.xml");

//創(chuàng)建一個(gè)StreamResult對(duì)象,該構(gòu)造函數(shù)的參數(shù)可以取為File對(duì)象。
StreamResult sr = new StreamResult (f);

//下面調(diào)用JAXP中的XSLT引擎來實(shí)現(xiàn)輸出DOM Tree中的數(shù)據(jù)到XML文件中的功能。
//XSLT引擎的輸入為DOMSource對(duì)象,輸出為StreamResut對(duì)象。
try
{
//首先創(chuàng)建一個(gè)TransformerFactory對(duì)象,再由此創(chuàng)建Transformer對(duì)象。Transformer
//類相當(dāng)于一個(gè)XSLT引擎。通常我們使用它來處理XSL文件,但是在這里我們使
//用它來輸出XML文檔。
TransformerFactory tf=TransformerFactory.newInstance();
Transformer t=tf.newTransformer ();

//關(guān)鍵的一步, 調(diào)用Transformer對(duì)象 (XSLT引擎)的transform()方法,該方法的第一
//個(gè)參數(shù)是DOMSource對(duì)象,第二個(gè)參數(shù)是StreamResult對(duì)象。
t.transform(doms,sr);
}
catch (TransformerConfigurationException tce)
{
System.out.println("Transformer Configuration Exception -----");
tce.printStackTrace();
}
catch (TransformerException te)
{
System.out.println ("Transformer Exception ---------");
te.printStackTrace ();
}


  在實(shí)際的應(yīng)用中,我們可以應(yīng)用傳統(tǒng)的DOM API從XML文檔中獲取DOM Tree,然后根據(jù)實(shí)際的需求對(duì)DOM Tree執(zhí)行各種操作,得到最終的Document對(duì)象,接下來可以由此Document對(duì)象創(chuàng)建DOMSource對(duì)象,剩下的事情就是照搬上面的代碼了,程序運(yùn)行完畢后, XMLOutput.xml就是你所需要的結(jié)果(當(dāng)然了,你可以隨意更改StreamResult類構(gòu)造函數(shù)的參數(shù),指定不同的輸出介質(zhì),而不必是千篇一律的XML文檔)。

  這個(gè)方法最大的好處在于可以隨心所欲的控制DOM Tree中的內(nèi)容輸出到輸出介質(zhì)中的格式,但是光靠TransformerFactory類和Transformer類并不能實(shí)現(xiàn)這個(gè)功能,還需要依賴OutputKeys類的幫助。 完整的例子請(qǐng)參考下列文件: AddRecord2.java(見附件)、user.xml(見附件)。該例子的運(yùn)行環(huán)境為:Windows XP Professional、JDK 1.3.1。為了能夠正常編譯運(yùn)行AddRecord2.java這個(gè)程序,你需要到網(wǎng)址http://java.sun.com去下載安裝JAXP 1.1或者Java XML Pack(Java XML Pack已經(jīng)內(nèi)含JAXP了)。

  OutputKeys類

  javax.xml.transform.OutputKeys類和java.util.Properties類配合使用,可以控制JAXP的XSLT引擎(Transformer類)輸出XML文檔的格式。請(qǐng)看下面的代碼片斷:

//首先創(chuàng)建一個(gè)TransformerFactory對(duì)象,再由此創(chuàng)建Transformer對(duì)象。
TransformerFactory tf=TransformerFactory.newInstance();
Transformer t=tf.newTransformer ();

//獲取Transformser對(duì)象的輸出屬性,亦即XSLT引擎的缺省輸出屬性,這是一個(gè)
//java.util.Properties對(duì)象。
Properties properties = t.getOutputProperties();

//設(shè)置新的輸出屬性:輸出字符編碼為GB2312,這樣可以支持中文字符,XSLT引擎所輸出
//的XML文檔如果包含了中文字符,可以正常顯示,不會(huì)出現(xiàn)所謂的"漢字問題"。
//請(qǐng)留意OutputKeys類的字符串常數(shù)OutputKeys.ENCODING。
properties.setProperty(OutputKeys.ENCODING,"GB2312");

/更新XSLT引擎的輸出屬性。
t.setOutputProperties(properties);

//調(diào)用XSLT引擎,按照輸出屬性中的設(shè)置,輸出DOM Tree中的內(nèi)容到輸出介質(zhì)中。
t.transform(DOMSource_Object,StreamResult_Object);


  從上面的程序代碼,我們不難看出,通過設(shè)置XSLT引擎(Transformer類)的輸出屬性,可以控制DOM Tree中的內(nèi)容的輸出格式,這對(duì)于我們定制輸出內(nèi)容是很有幫助的。那么JAXP的XSLT引擎(Transformer類)有那些輸出屬性可以設(shè)置呢? javax.xml.transform.OutputKeys類定義了很多字符串常數(shù),它們都是可以自由設(shè)置的輸出屬性,常用的輸出屬性如下所示:

public static final java.lang.String METHOD


  可以設(shè)為"xml"、"html"、"text"等值。

public static final java.lang.String VERSION


  所遵循規(guī)范的版本號(hào),如果METHOD設(shè)為"xml",那么它的值應(yīng)該設(shè)為"1.0",如果METHOD設(shè)為"html",那么它的值應(yīng)該設(shè)為"4.0",如果METHOD設(shè)為"text",那么這個(gè)輸出屬性會(huì)被忽略。

public static final java.lang.String ENCODING


  設(shè)置輸出時(shí)所采用的編碼方式,比如"GB2312"、"UTF-8"等等,如果將其設(shè)置為"GB2312",可以解決所謂的"漢字問題"。

public static final java.lang.String OMIT_XML_DECLARATION


  設(shè)置輸出到XML文檔中時(shí)是否忽略XML聲明,亦即類似于:

<?xml version="1.0" standalone="yes" encoding="utf-8" ?>


  這樣的代碼。它可選的值有"yes"、"no"。

public static final java.lang.String INDENT


  IDENT設(shè)定XSLT引擎在輸出XML文檔時(shí),是否自動(dòng)添加額外的空格,它可選的值為"yes"、"no"。

public static final java.lang.String MEDIA_TYPE


  MEDIA_TYPE設(shè)定輸出文檔的MIME類型。

  如果設(shè)定XSLT引擎的輸出屬性呢?下面我們來總結(jié)一下:

  首先是獲取XSLT引擎(Transformer類)的缺省輸出屬性的集合,這需要使用Transformer類的getOutputProperties()方法,返回值是一個(gè)java.util.Properties對(duì)象。

Properties properties = transformer.getOutputProperties();


  然后是設(shè)定新的輸出屬性,比如:

properties.setProperty(OutputKeys.ENCODING,"GB2312");
properties.setProperty(OutputKeys.METHOD,"html");
properties.setProperty(OutputKeys.VERSION,"4.0");
………………………………………………………


  最后是更新XSLT引擎(Transformer類)的缺省輸出屬性的集合,這需要使用Transformer類的setOutputProperties()方法,參數(shù)是一個(gè)java.util.Properties對(duì)象。

  我們編寫了一個(gè)新的程序,其中應(yīng)用了OutputKeys類,用以控制XSLT引擎的輸出屬性,該程序的架構(gòu)和前一個(gè)程序(AddRecord3.java)大致相同,不過輸出結(jié)果略有不同。完整的代碼請(qǐng)參考下列文件: AddRecord3.java(見附件)、user.xml(見附件)。該例子的運(yùn)行環(huán)境為:Windows XP Professional、JDK 1.3.1。為了能夠正常編譯運(yùn)行AddRecord3.java這個(gè)程序,你需要到網(wǎng)址http://java.sun.com去下載安裝JAXP 1.1或者Java XML Pack(Java XML Pack內(nèi)含JAXP了)。

  方法四:使用Xalan XML Serializer

  方法四其實(shí)是方法三的一個(gè)變種,它需要Apache Xalan和Apache Xerces的支持才能夠運(yùn)行。例子代碼如下所示:

//首先創(chuàng)建一個(gè)DOMSource對(duì)象,該構(gòu)造函數(shù)的參數(shù)可以是一個(gè)Document對(duì)象
//doc代表更改后的DOM Tree。
DOMSource domSource = new DOMSource (doc);

//創(chuàng)建一個(gè)DOMResult對(duì)象,臨時(shí)保存XSLT引擎的輸出結(jié)果。
DOMResult domResult = new DOMResult();

//下面調(diào)用JAXP中的XSLT引擎來實(shí)現(xiàn)輸出DOM Tree中的數(shù)據(jù)到XML文件中的功能。
//XSLT引擎的輸入為DOMSource對(duì)象,輸出為DOMResut對(duì)象。
try
{
 //首先創(chuàng)建一個(gè)TransformerFactory對(duì)象,再由此創(chuàng)建Transformer對(duì)象。Transformer
 //類相當(dāng)于一個(gè)XSLT引擎。通常我們使用它來處理XSL文件,但是在這里我們使
 //用它來輸出XML文檔。
 TransformerFactory tf=TransformerFactory.newInstance();
 Transformer t=tf.newTransformer ();

 //設(shè)置XSLT引擎的屬性(必不可少,否則會(huì)產(chǎn)生"漢字問題")。
 Properties properties = t.getOutputProperties();
 properties.setProperty(OutputKeys.ENCODING,"GB2312");
 t.setOutputProperties(properties);

 //關(guān)鍵的一步, 調(diào)用Transformer對(duì)象 (XSLT引擎)的transform()方法,該方法的第一
 //個(gè)參數(shù)是DOMSource對(duì)象,第二個(gè)參數(shù)是DOMResult對(duì)象。
 t.transform(domSource,domResult);

 //創(chuàng)建缺省的Xalan XML Serializer,使用它將臨時(shí)存放在DOMResult對(duì)象
 //(domResult)中的內(nèi)容以輸出流的形式輸出到輸出介質(zhì)中。
 Serializer serializer = SerializerFactory.getSerializer
(OutputProperties.getDefaultMethodProperties("xml"));

 //設(shè)置Xalan XML Serializer的輸出屬性,這一步必不可少,否則也可能產(chǎn)生
 //所謂的"漢字問題"。
 Properties prop=serializer.getOutputFormat();
 prop.setProperty("encoding","GB2312");
 serializer.setOutputFormat(prop);

 //創(chuàng)建一個(gè)File對(duì)象,代表DOM Tree所包含的數(shù)據(jù)的輸出介質(zhì),這是一個(gè)XML文件。
 File f = new File ("xuser3.xml");

 //創(chuàng)建文件輸出流對(duì)象fos,請(qǐng)留意構(gòu)造函數(shù)的參數(shù)。
 FileOutputStream fos=new FileOutputStream(f);

 //設(shè)置Xalan XML Serializer的輸出流。
 serializer.setOutputStream(fos);

 //串行化輸出結(jié)果。
 serializer.asDOMSerializer().serialize(domResult.getNode());
}
catch (Exception tce)
{
 tce.printStackTrace();
}

  這個(gè)方法不太常用,而且似乎有點(diǎn)畫蛇添足,所以我們就不展開討論了。完整的例子請(qǐng)參考下列文件: AddRecord4.java(見附件)、user.xml(見附件)。該例子的運(yùn)行環(huán)境為:Windows XP Professional、JDK 1.3.1。為了能夠正常編譯運(yùn)行AddRecord4.java這個(gè)程序,你需要到網(wǎng)址http://xml.apache.org/dist/去下載安裝Apache Xalan和Apache Xerces。

  或者是到網(wǎng)址http://java.sun.com/xml/download.html去下載安裝Java XML Pack。因?yàn)樽钚碌腏ava XML Pack(Winter 01 版)包含了Apache Xalan和Apache Xerces技術(shù)在內(nèi)。

  結(jié)論:

  本文簡(jiǎn)略的討論了Java語言編程中更新XML文檔的四種方法。第一種方法是直接讀寫XML文件,這種方法十分繁瑣,而且比較容易出錯(cuò),極少使用,除非你需要開發(fā)自己的XML Parser,否則不會(huì)使用這種方法。第二種方法是使用Apache Crimson的XmlDocument類,這種方法極為簡(jiǎn)單,使用方便,如果你選用Apache Crimson作為XML解析器,那么不妨使用這種方法,不過這種方法似乎效率不高(源于效率低下的Apache Crimson),另外,高版本的JAXP或者是Java XML Pack、JWSDP不直接支持Apache Crimson,亦即這種方法不通用。第三種方法是使用JAXP的XSLT引擎(Transformer類)來輸出XML文檔,這種方法也許是標(biāo)準(zhǔn)的方法了,使用起來十分靈活,特別是可以自如控制輸出格式,我們推薦采用這種方法。第四種方法是第三種方法的變種,采用了Xalan XML Serializer,引入了串行化操作,對(duì)于大量文檔的修改/輸出有優(yōu)越性,可惜的是要重復(fù)設(shè)置XSLT引擎的屬性和XML Serializer的輸出屬性,比較麻煩,而且依賴于Apache Xalan和Apache Xerces技術(shù),通用性略顯不足。

  除了上面討論的四種方法以外,實(shí)際上應(yīng)用別的API(比如JDOM、Castor、XML4J、Oracle XML Parser V2)也有很多辦法可以更新XML文檔,限于篇幅,在這里就不一一討論了。

標(biāo)簽:大興安嶺 紅河 拉薩 武威 岳陽 亳州 馬鞍山 鄭州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Java編程中更新XML文檔的常用方法》,本文關(guān)鍵詞  Java,編程,中,更新,XML,文檔,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Java編程中更新XML文檔的常用方法》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于Java編程中更新XML文檔的常用方法的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章