Java xml 工具 JDOM 使用详解.
一, 什么是JDOM工具
在編程中, 我們往往需要一些配置數(shù)據(jù),? 這些值我們一般不會hardcode在代碼中的. 而是寫在配置文件.
在Java世界中, 我們通常會把配置變量寫在xml文件中.
而xml 也不只是配置文件這么簡單, 實(shí)際上, 我們可以把一些用戶數(shù)據(jù)寫在xml里.
這樣, xml就如一個微型簡便的數(shù)據(jù)庫.
簡單來講, 我們可以將一個對象的所有屬性(Attribute)寫在xml里, 也可以通過讀取xml里的數(shù)據(jù)構(gòu)造1個對象出來.
Java里有若干個讀寫xml的工具, 它們分別是
DOM:? 方便,? 但是會將整個xml所有數(shù)據(jù)一次過讀進(jìn)內(nèi)存.
SAX:?? 內(nèi)存占用少, 使用起來稍稍復(fù)雜.
JDOM: 基于SAX編寫的xml工具, 集合上面兩個工具的優(yōu)點(diǎn).
本文主要介紹JDOM.
二, 安裝JDOM工具.
JDOM實(shí)際上只是1個jar包, 而不是1個eclipse插件.
JDOM的最新版本是2.0.5 , 也就是JDOM2 了..
可以在如下網(wǎng)址中下載.
http://www.jdom.org/downloads/
下載得到1個zip包, 解壓出 jdom-2.0.5.jar 文件.
把它寫進(jìn)CLASSPATH變量里就可以使用了.
三,XML各個關(guān)鍵字簡單介紹
在正式開始介紹JDOM 用法時, 有必要簡單講下xml各個組成部分.
如下圖:
上面是一個常見的XML圖, 它實(shí)際上存儲了兩個Student對象的數(shù)據(jù).
下面簡單解釋一下xml的常見名詞:
3.1 頭部信息
頭部信息包含了xml的版本信息, 以及編碼方法.
頭部信息是每個xml文件都必須備有的.
3.2 Element.
我們可以把Element(元素) 看成xml的一個基本單元.
1個Element的常見寫法如下:
<A>abc</A>, 有點(diǎn)類似與html,?? Element的值被兩個標(biāo)簽(Tag)包住.
3.3 name of Element.
Element標(biāo)簽里的值就算是這個Element的名字了,? 這個值很重要, JDOM檢索Element基本上是靠它來檢索(而不是依照Value來檢索)>Name 是Element里的1個必備組成部分.
也就是每1個Element都必須有1個name啦
3.4 Value of Element.
被name標(biāo)簽(tag),包住的部分就是value了.注意, value并不是Element的必備部分,? 例如上圖例子中,? Element "fox:Student"? 就沒有Value, 但是它有3個子Element.
3.5 Child
child就是子Element, 例如上圖例子中, id, name, age 都是 Student的child,? 而 Student 是 StudentRecords的Child.
注意, child只是一層的, 也就說 id, name,age 并不是 StudentRecords的child啊.
3.6 Children
1個Element的所有child的集合,? 例如上圖StudentRecords 有兩個child,? 而這兩個child各自又有3個child(id, name, student),
3.7 Decsendant
1個Element 的后代, 子孫集合
相對于child來將, 這個概念就是多層的,
就如一個Tree結(jié)構(gòu), 所有子孫節(jié)點(diǎn)(node) 在Descendant的集合里面.
3.8 Root Element
就是根節(jié)點(diǎn)的意思啦. 上圖例子中的StudentRecords就是1個Root Element.
在JDOM中,? 1個xml文件只能有1個Root Element,? 所有其他Element都在Root Element的 Descendant 集合中.
3.9 NameSpace
首先Namespace不是必須的.
有時為了區(qū)分同名的節(jié)點(diǎn), 可以為一些節(jié)點(diǎn)加入另1個屬性, 就是所謂的命名空間.
實(shí)際上, 命名空間的存在可以將xml里的節(jié)點(diǎn)依照命名空間分成若干個部分.
也就系講, 令到xml中, 某些element是屬于這個Namespace,? 某些element是另1個Namespace.
而且Namespace可以任意加在任何1個Element里.
在JDOM的世界里,
Namespace是1個重要的filter條件.
也就是說, 如果1個Element有Namespace,?? 如果只靠這個Element的name是filter不出來的, 必須加上命名空間才能得到這個Element.
命名空間作為element的一個屬性(Attribute)存在.
通常來講, 命名空間可以寫成如下格式:
xmlns:ggl="www.google.com"
其中, xmlns是1個關(guān)鍵字, 表示后面的是1個命名空間.
www.google.com是1個URL, 作為命名空間的URL了. 因?yàn)镮nternet上每個網(wǎng)址都是唯一的.
注意這個URL只是Element的一個標(biāo)石.? 而不是說xml會去訪問這個網(wǎng)址.
ggl 這個就是命名空間的Prefix, 可以理解成命名空間的1個簡稱.
例如上面例子中.
<ggl:Student xmlns:ggl="www.google.com"><ggl:id>1</ggl:id><ggl:name>Jack</ggl:name><ggl:age>14</ggl:age></ggl:Student>有4個element
都是屬于1個命名空間, 而URL的值只定義一次就夠了,? 后面的都可以用命名空間來代替.
上面的只是1個例子.
實(shí)際上我們不需要為xml的每1個element都加上命名空間, 只需要在關(guān)鍵的element加上就ok了.
四,利用JDOM 把對象數(shù)據(jù)寫入1個新文件.
這個小節(jié)中, 會說明
1. 如何創(chuàng)建1個xml.
4.1 Student類
首先你要有個對象是吧.. 我們就把1個student類寫出來
它有3個成員id, name, 和 age
class Student{private int id;private String name;private int age;public Student(int id, String name, int age){this.setId(id);this.setName(name);this.setAge(age);}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString(){return "Student: " + this.getId() + ", " + this.getName() + ", " + this.getAge();}4.2 客戶端代碼:
public class Testxml2 {public static void Create(){Student sd1 = new Student(1,"Jack",14);Student sd2 = new Student(2,"Mike",15);Student sd3 = new Student(3,"Paul",15);// new a xml fileDocument docJdom = new Document();//Namespace(not must, it's optional, to indicate elements with same nameNamespace np1 = Namespace.getNamespace("ggl", "www.google.com");Namespace np2 = Namespace.getNamespace("fox","www.firefox.com");// new a new root nodeElement eRoot = new Element("StudentRecords");docJdom.addContent(eRoot);//add sd1 nodeElement nodeSd1 = new Element("Student",np1);nodeSd1.setNamespace(np1);//idElement nodeId1 = new Element("id");nodeId1.addContent(""+sd1.getId());//nameElement nodeName1 = new Element("name");nodeName1.addContent(""+sd1.getName());//ageElement nodeAge1 = new Element("age");nodeAge1.addContent(""+sd1.getAge());nodeSd1.addContent(nodeId1);nodeSd1.addContent(nodeName1);nodeSd1.addContent(nodeAge1);eRoot.addContent(nodeSd1);//add sd2 nodeElement nodeSd2 = new Element("Student",np1);nodeSd2.setNamespace(np1);//idElement nodeId2 = new Element("id");nodeId2.addContent(""+sd2.getId());//nameElement nodeName2 = new Element("name");nodeName2.addContent(""+sd2.getName());//ageElement nodeAge2 = new Element("age");nodeAge2.addContent(""+sd2.getAge());nodeSd2.addContent(nodeId2);nodeSd2.addContent(nodeName2);nodeSd2.addContent(nodeAge2);eRoot.addContent(nodeSd2);//add sd3 nodeElement nodeSd3 = new Element("Student",np2);nodeSd3.setNamespace(np2);//idElement nodeId3 = new Element("id");nodeId3.addContent(""+sd3.getId());//nameElement nodeName3 = new Element("name");nodeName3.addContent(""+sd3.getName());//ageElement nodeAge3 = new Element("age");nodeAge3.addContent(""+sd3.getAge());nodeSd3.addContent(nodeId3);nodeSd3.addContent(nodeName3);nodeSd3.addContent(nodeAge3);eRoot.addContent(nodeSd3); OutputXML(docJdom,"/home/gateman/Studies/JavaDesignPattern/xml/02.xml");System.out.println("Done!");}private static void OutputXML(Document dXml, String sFilenm){XMLOutputter xot = new XMLOutputter();xot.setFormat(Format.getPrettyFormat());try{FileWriter fwXML = new FileWriter(sFilenm);xot.output(dXml, fwXML);}catch(Exception e){e.printStackTrace();}} }代碼其實(shí)不難看懂.
1. 首先創(chuàng)建3個student對象
2. 創(chuàng)建兩個命名空間
3. 建立1個Document對象(JDOM中, Document指的是xml文件本身, 一個xml文件對應(yīng)1個Document對象.
4. 建立1個Root Element對象.
5. 根據(jù)3個對象依次建立3個element, 然后把這個3個element添加到Root Element里, 作為它的子element.
6. 利用XMLOutputter把Document對象寫出到硬盤. 注意這個方法是覆蓋已存在文件, 并不是append到文件末尾.
生成的xml文件是這樣的:
gateman@TPEOS xml $ cat 02.xml <?xml version="1.0" encoding="UTF-8"?> <StudentRecords><ggl:Student xmlns:ggl="www.google.com"><id>1</id><name>Jack</name><age>14</age></ggl:Student><ggl:Student xmlns:ggl="www.google.com"><id>2</id><name>Mike</name><age>15</age></ggl:Student><fox:Student xmlns:fox="www.firefox.com"><id>3</id><name>Paul</name><age>15</age></fox:Student> </StudentRecords>五,把寫入xml的方法作為1個接口
的確, 上面的代碼又長又臭, 而且重復(fù)代碼實(shí)在太多,.
所以, 我們一般會把寫入xml的動作放入類的代碼中, 作為1個接口.
5.1 XMLable 接口:
import org.jdom2.Element; import org.jdom2.Namespace; public interface XMLable {public Element buildElement(Namespace np); }
只需定義1個返回1個Element對象的方法.
5.2 Student 類:
讓Student類去實(shí)現(xiàn)這個接口.
import org.jdom2.Element; import org.jdom2.Namespace;public class Student implements XMLable {private int id;private String name;private int age;public Student(int id, String name, int age){this.setId(id);this.setName(name);this.setAge(age);}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString(){return "Student: " + this.getId() + ", " + this.getName() + ", " + this.getAge();}@Overridepublic Element buildElement(Namespace np) {Element node = new Element("Student",np);node.setNamespace(np);//idElement nodeId = new Element("id");nodeId.addContent(""+this.getId());//nameElement nodeName = new Element("name");nodeName.addContent(""+this.getName());//ageElement nodeAge = new Element("age");nodeAge.addContent(""+this.getAge());node.addContent(nodeId);node.addContent(nodeName);node.addContent(nodeAge);return node;} }5.3 XMLExport類
把Output方法封裝1個類的靜態(tài)函數(shù):
import org.jdom2.Document; import org.jdom2.output.XMLOutputter; import org.jdom2.output.Format; import java.io.FileWriter;public class XMLExport {public static void OutputXML(Document dXml, String sFilenm){XMLOutputter xot = new XMLOutputter();xot.setFormat(Format.getPrettyFormat());try{FileWriter fwXML = new FileWriter(sFilenm);xot.output(dXml, fwXML);}catch(Exception e){e.printStackTrace();}} }5.4 客戶端代碼:
這樣一來, 客戶端代碼就相當(dāng)簡潔了: Student sd1 = new Student(1,"Jack",14);Student sd2 = new Student(2,"Mike",15);Student sd3 = new Student(3,"Paul",15);// new a xml fileDocument docJdom = new Document();//Namespace(not must, it's optional, to indicate elements with same nameNamespace np1 = Namespace.getNamespace("ggl", "www.google.com");Namespace np2 = Namespace.getNamespace("fox","www.firefox.com");// new a new root nodeElement eRoot = new Element("StudentRecords");docJdom.addContent(eRoot);eRoot.addContent(sd1.buildElement(np1));eRoot.addContent(sd2.buildElement(np1));eRoot.addContent(sd3.buildElement(np2));XMLExport.OutputXML(docJdom,"/home/gateman/Studies/JavaDesignPattern/xml/04.xml");六, 根據(jù)條件從XML文件中獲取Element對象.
首先講一句,
JDOM中沒有根據(jù)xml文件中某個Element的值(Value)返回其Element的方法. 不要把它當(dāng)做sql數(shù)據(jù)庫那么強(qiáng)大啦.
基本上常用filter方法有種.
1.是根據(jù)名字來filter.
2.是根據(jù)Namespace來filter.
上面的filter返回的都是1個集合. 也就是說你還需要遍歷它們的子Element才能獲得真正需要的Element.
而且當(dāng)1個Element具有Namespace, 當(dāng)屏它的Name是filter不出來的, 必須用Name和Namespace一起來filter.
一步一步來..
6.1 根據(jù)文件名獲得Document對象.
這個是前提.
代碼也很簡單, 需要用到類SaxBuilder(也在JDOM包中)
6.2 獲取Root Element
JDOM中Root Element只會有1個.
而JDOM也提供1個獲取Root Element的方法
當(dāng)然前提是你有1個Document對象啦.
6.3 getChild()方法
這個方法返回1個Element中的第1個子Element.
注意, 不包括孫Element哦.
它有兩個重載方法.
getChild(String name)? -> 返回第1個名字是name.而且沒有Namespace的子Element,
6.4 getChildren()方法
返回1個Element的所有子Element的集合,? 這個集合是1個java.util.List對象.注意, 也不包括孫Element, 只有1層哦.
也有兩個重載方法
getChildren(String name)? -> 返回所有名字是name, 而且沒有Namespace的子Element的對象集合,
6.5 getDescendant()方法
這個就厲害了.? Descendant是后代的意思, 這個方法能返回1個Element的所有子孫后代的Element集合. 注意這個集合是1個org.jom2.util.IteratorIterable<Element>?對象的集合
它也有1個重載方法:
getDescendant(Filter ft)? ->? 根據(jù)條件ft(1個Filter對象) 來獲得所有符合條件的后代Element集合. 下面的例子會用到這個方法
這個方法是真正上的Filter了, 因?yàn)樗鼙闅v1個Element的所有子孫.
也就說如過用它來遍歷RootElement, 就相當(dāng)于遍歷整個xml文件!
6.6 Filter 類
org.jdom2.Filter是Jdom2包里的一個抽象類.
最常用的子類是ElementFilter.?
它的對象通常用來作為getDescendant 方法的參數(shù).
new ElementFilter(name, np) 代表構(gòu)造1個用名字name和命名空間np組成的Filter對象
6.7 getParentElement()方法
獲得1個非RootElement的的父Element.注意1個Element只會有1個父Element啦.
6.8 獲取上面xml文件中id為1的Element的例子代碼.
艾呀這篇文章太冗長了.
上面的xml是這樣的:
gateman@TPEOS xml $ cat 04.xml <?xml version="1.0" encoding="UTF-8"?> <StudentRecords><ggl:Student xmlns:ggl="www.google.com"><id>1</id><name>Jack</name><age>14</age></ggl:Student><ggl:Student xmlns:ggl="www.google.com"><id>2</id><name>Mike</name><age>15</age></ggl:Student><fox:Student xmlns:fox="www.firefox.com"><id>3</id><name>Paul</name><age>15</age></fox:Student> </StudentRecords>它包含3個Student對象的數(shù)據(jù)
假如我想獲得id等于2的StudentElement, 可以這樣寫:
還是先說幾句
首先, id = 2中, 2是1個值, 上面說過了, JDOM是不支持用值來檢索的.
id是1個名字, 可以用"id"來檢索.? 該xml中有3個名字是"id"的Element(分別屬于3個Student Element),? 它們都沒有Namespace.
所以只需要
利用RootElement的? getDescendant("id")得到3個id Element的集合, 然后再去遍歷它們的值..
代碼如下:
SAXBuilder sbd = new SAXBuilder();Document docJdom = null;File xmlfile = null;try{xmlfile = new File("/home/gateman/Studies/JavaDesignPattern/xml/02.xml");docJdom = sbd.build(xmlfile);}catch(Exception e){e.printStackTrace();}Element rootElement = docJdom.getRootElement();//all the element named "id" & without namespaceIteratorIterable<Element> elist = rootElement.getDescendants(new ElementFilter("id"));Iterator it = elist.iterator();Element eId2 = null;//loopwhile(it.hasNext()){Element em = (Element)(it.next());if (2 == new Integer(em.getChild("id").getValue()).intValue()){eId2 = em.getParentElement(); }}上面的eId2就是想要得到的Element對象.
七, 把1個Element封裝成1個類
例如上面我獲得了id=2 的element, 如何把這個element封裝成1個類?
下面是1個利用簡單工廠模式的例子把構(gòu)造類方法寫在1個產(chǎn)品里的方法里:
7.1 BuildXmlObj 接口
import org.jdom2.Element; public interface BuildXmlObj {public Object buildObj(Element elm); }它具有1個根據(jù)Element構(gòu)造1個對象的方法.
7.2 BuildXmlStudent 類
實(shí)現(xiàn)上面的接口
import org.jdom2.Element;public class BuildXmlStudent implements BuildXmlObj {@Overridepublic Object buildObj(Element em) {try{return new Student(new Integer(em.getChild("id").getValue()).intValue(), em.getChild("name").getValue(),new Integer(em.getChild("age").getValue()).intValue()); }catch(Exception e){e.printStackTrace();return null;}} }7.3 工廠 類
public class FactoryXmlObj {public static BuildXmlObj getBuildXmlObj(String name){BuildXmlObj bxj = null;switch(name){case "Student" :bxj = new BuildXmlStudent();break;//..}return bxj;}}7.4 客戶段代碼:
SAXBuilder sbd = new SAXBuilder();Document docJdom = null;File xmlfile = null;try{xmlfile = new File("/home/gateman/Studies/JavaDesignPattern/xml/04.xml");docJdom = sbd.build(xmlfile);}catch(Exception e){e.printStackTrace();}Element rootElement = docJdom.getRootElement();//all the element named "id" & without namespaceIteratorIterable<Element> elist = rootElement.getDescendants(new ElementFilter("id"));Iterator it = elist.iterator();Element eId2 = null;//loopwhile(it.hasNext()){Element em = (Element)(it.next());if (2 == new Integer(em.getValue()).intValue()){eId2 = em.getParentElement(); break;}}//packaging to a Student objStudent std = null;BuildXmlObj bxj = FactoryXmlObj.getBuildXmlObj("Student");std = (Student)(bxj.buildObj(eId2));System.out.println(std);
1g
總結(jié)
以上是生活随笔為你收集整理的Java xml 工具 JDOM 使用详解.的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 利用反射实现C#的委托
- 下一篇: Java TCP 编程简介