JDOM 簡介

JDOM是一個開源項目,它基於樹型結構,利用純JAVA的技術對XML文檔實現解析、生成、序列化以及多種操作。

JDOM 直接爲JAVA編程服務。它利用更爲強有力的JAVA語言的諸多特性(方法重載、集合概念以及映射),把SAX和DOM的功能有效地結合起來。

在使用設計上儘可能地隱藏原來使用XML過程中的複雜性。利用JDOM處理XML文檔將是一件輕鬆、簡單的事。

JDOM 在2000年的春天被Brett McLaughlin和Jason Hunter開發出來,以彌補DOM及SAX在實際應用當中的不足之處。

這些不足之處主要在於SAX沒有文檔修改、隨機訪問以及輸出的功能,而對於DOM來說,JAVA程序員在使用時來用起來總覺得不太方便。

DOM的缺點主要是來自於由於Dom是一個接口定義語言(IDL),它的任務是在不同語言實現中的一個最低的通用標準,並不是爲JAVA特別設計的。JDOM的最新版本爲JDOM Beta 
9。最近JDOM被收錄到JSR-
102內,這標誌着JDOM成爲了JAVA平臺組成的一部分。

二、JDOM 包概覽

JDOM是由以下幾個包組成的
org.jdom                包含了所有的xml文檔要素的java類

 

org.jdom.adapters         包含了與dom適配的java類

 

org.jdom.filter            包含了xml文檔的過濾器類

 

org.jdom.input            包含了讀取xml文檔的類

 

org.jdom.output           包含了寫入xml文檔的類

 

org.jdom.transform        包含了將jdom xml文檔接口轉換爲其他xml文檔接口

 

org.jdom.xpath            包含了對xml文檔xpath操作的類三、JDOM 類說明

1
、org.JDOM這個包裏的類是你J解析xml文件後所要用到的所有數據類型。

Attribute

CDATA

Coment

DocType

Document

Element

EntityRef

Namespace

ProscessingInstruction

Text

2
、org.JDOM.transform在涉及xslt格式轉換時應使用下面的2個類

JDOMSource

JDOMResult

org.JDOM.input

3
、輸入類,一般用於文檔的創建工作

SAXBuilder

DOMBuilder

ResultSetBuilder

org.JDOM.output

4
、輸出類,用於文檔轉換輸出

XMLOutputter

SAXOutputter

DomOutputter

JTreeOutputter

使用前注意事項:

1
.JDOM對於JAXP 以及 TRax 的支持

JDOM 支持JAXP1.
1
:你可以在程序中使用任何的parser工具類,默認情況下是JAXP的parser。

制定特別的parser可用如下形式

SAXBuilder parser 

  
= new SAXBuilder("org.apache.crimson.parser.XMLReaderImpl"
);

 Document doc 
= parser.build("http://www.cafeconleche.org/"
);

 
// work with the document...


JDOM也支持TRaX:XSLT可通過JDOMSource以及JDOMResult類來轉換(參見以後章節)

2.注意在JDOM裏文檔(Document)類由org.JDOM.Document 來表示。這要與org.w3c.dom中的Document區別開,這2種格式如何轉換在後面會說明。

以下如無特指均指JDOM裏的Document。

四、JDOM主要使用方法

1
.Ducument類

(
1
)Document的操作方法:

Element root 
= new Element("GREETING"
);

Document doc 
= new
 Document(root);

root.setText(
"Hello JDOM!"
);

或者簡單的使用Document doc 
= new Document(new Element("GREETING").setText("Hello JDOM!t"
));

這點和DOM不同。Dom則需要更爲複雜的代碼,如下:

DocumentBuilderFactory factory 
=
DocumentBuilderFactory.newInstance();

DocumentBuilder builder 
=
factory.newDocumentBuilder();

Document doc 
=
 builder.newDocument();

Element root 
=doc.createElement("root"
);

Text text 
= doc.createText("This is the root"
);

root.appendChild(text);

doc.appendChild(root);

注意事項:JDOM不允許同一個節點同時被2個或多個文檔相關聯,要在第2個文檔中使用原來老文檔中的節點的話。首先需要使用detach()把這個節點分開來。

(
2
)從文件、流、系統ID、URL得到Document對象:

DOMBuilder builder 
= new
 DOMBuilder();

Document doc 
= builder.build(new File("jdom_test.xml"
));

SAXBuilder builder 
= new
 SAXBuilder();

Document doc 
=
 builder.build(url);

在新版本中DOMBuilder 已經Deprecated掉 DOMBuilder.builder(url),用SAX效率會比較快。

這裏舉一個小例子,爲了簡單起見,使用String對象直接作爲xml數據源:

 
public jdomTest() 
{

    String textXml 
= null
;

    textXml 
= "<note>"
;

    textXml 
= textXml +


        
"<to>aaa</to><from>bbb</from><heading>ccc</heading><body>ddd</body>";

    textXml 
= textXml + "</note>"
;

    SAXBuilder builder 
= new
 SAXBuilder();

    Document doc 
= null
;

    Reader in
= new
 StringReader(textXml);

    
try 
{

      doc 
=
 builder.build(in);

      Element root 
=
 doc.getRootElement();

      List ls 
= root.getChildren();//注意此處取出的是root節點下面的一層的Element集合


      
for (Iterator iter = ls.iterator(); iter.hasNext(); ) {

        Element el 
=
 (Element) iter.next();

        
if(el.getName().equals("to"))
{

         System.out.println(el.getText());

        }


      }


    }


    
catch (IOException ex) {

      ex.printStackTrace();

    }


    
catch (JDOMException ex) {

      ex.printStackTrace();

    }


  }


(
3)DOM的document和JDOM的Document之間的相互轉換使用方法,簡單!

DOMBuilder builder 
= new
 DOMBuilder();

org.jdom.Document jdomDocument 
=
 builder.build(domDocument);

DOMOutputter converter 
= new DOMOutputter();// work with the JDOM document…


org.w3c.dom.Document domDocument 
= converter.output(jdomDocument);

// work with the DOM document…


2.XML文檔輸出

XMLOutPutter類:

JDOM的輸出非常靈活,支持很多種io格式以及風格的輸出

Document doc 
= new
 Document(...);

XMLOutputter outp 
= new
 XMLOutputter();

outp.output(doc, fileOutputStream); 
// Raw output


outp.setTextTrim(
true); // Compressed output

outp.output(doc, socket.getOutputStream());

outp.setIndent(
" ");// Pretty output

outp.setNewlines(
true);

outp.output(doc, System.out);

詳細請參閱最新的JDOM API手冊

3
.Element 類:

(
1
)瀏覽Element樹

Element root 
= doc.getRootElement();//獲得根元素element


List allChildren 
= root.getChildren();// 獲得所有子元素的一個list

List namedChildren 
= root.getChildren("name");// 獲得指定名稱子元素的list

Element child 
= root.getChild("name");//獲得指定名稱的第一個子元素

JDOM給了我們很多很靈活的使用方法來管理子元素(這裏的List是java.util.List)

List allChildren 
= root.getChildren();

allChildren.remove(
3); // 刪除第四個子元素


allChildren.removeAll(root.getChildren(
"jack"));// 刪除叫“jack”的子元素

root.removeChildren(
"jack"); // 便捷寫法

allChildren.add(
new Element("jane"));// 加入

root.addContent(
new Element("jane")); // 便捷寫法

allChildren.add(
0new Element("first"));

(
2
)移動Elements:

在JDOM裏很簡單

Element movable 
= new Element("movable"
);

parent1.addContent(movable); 
// place


parent1.removeContent(movable); 
// remove

parent2.addContent(movable); 
// add

在Dom裏

Element movable 
= doc1.createElement("movable");

parent1.appendChild(movable); 
// place


parent1.removeChild(movable); 
// remove

parent2.appendChild(movable); 
// 出錯!

補充:糾錯性

JDOM的Element構造函數(以及它的其他函數)會檢查element是否合法。

而它的add
/remove方法會檢查樹結構,檢查內容如下:

1
.在任何樹中是否有迴環節點

2
.是否只有一個根節點

3
.是否有一致的命名空間(Namespaces) 

(
3
)Element的text內容讀取

<description>


A cool demo

</description>

// The text is directly available

// Returns "  A cool demo "


String desc 
= element.getText();

//
 There's a convenient shortcut

// Returns "A cool demo"


String desc 
= element.getTextTrim();

(
4
)Elment內容修改

element.setText(
"A new description"
);

3
.可正確解釋特殊字符

element.setText(
"<xml> content"
);

4
.CDATA的數據寫入、讀出

element.addContent(
new CDATA("<xml> content"
));

String noDifference 
=
 element.getText();

混合內容

element可能包含很多種內容,比如說

<table>


<!-- Some comment -->

Some text

<tr>Some child element</tr>

</table>

取table的子元素tr

String text 
= table.getTextTrim();

Element tr 
= table.getChild("tr"
);

也可使用另外一個比較簡單的方法

List mixedCo 
=
 table.getContent();

Iterator itr 
=
 mixedCo.iterator();

while (itr.hasNext()) 
{

Object o 
=
 i.next();

if (o instanceof Comment) {...}


// 這裏可以寫成Comment, Element, Text, CDATA,ProcessingInstruction, 或者是EntityRef的類型

}


// 現在移除Comment,注意這裏遊標應爲1。這是由於回車鍵也被解析成Text類的緣故,所以Comment項應爲1。

mixedCo.remove(
1); 

4
.Attribute類

<table width="100%" border="0"> </table>


String width 
= table.getAttributeValue("width");//獲得attribute

int border = table.getAttribute("width").getIntValue();

table.setAttribute(
"vspace""0");//設置attribute


table.removeAttribute(
"vspace");// 刪除一個或全部attribute

table.getAttributes().clear(); 

5.處理指令(Processing Instructions)操作

一個Pls的例子

<?br?>


<?cocoon-process type="xslt"?>

          
|        |

          
|        |

        目標     數據

處理目標名稱(Target)

String target 
= pi.getTarget();

獲得所有數據(data),在目標(target)以後的所有數據都會被返回。

String data 
=
 pi.getData();

String type 
= pi.getValue("type"
);獲得指定屬性的數據

List ls 
=
 pi.getNames();獲得所有屬性的名稱

6
.命名空間操作

<
xhtml:html 

 xmlns:xhtml
="http://www.w3.org/1999/xhtml">


<xhtml:title>Home Page</xhtml:title>

</xhtml:html>

Namespace xhtml 
= Namespace.getNamespace("xhtml""http://www.w3.org/1999/xhtml");

List kids 
= html.getChildren("title"
, xhtml);

Element kid 
= html.getChild("title"
, xhtml);

kid.addContent(
new Element("table"
, xhtml));

7
.XSLT格式轉換

使用以下函數可對XSLT轉換

最後如果你需要使用w3c的Document則需要轉換一下。

public static
 Document transform(String stylesheet,Document in)

                                        
throws JDOMException 
{

     
try 
{

       Transformer transformer 
=
 TransformerFactory.newInstance()

                             .newTransformer(
new
 StreamSource(stylesheet));

       JDOMResult out 
= new
 JDOMResult();

       transformer.transform(
new
 JDOMSource(in), out);

       
return
 out.getDeocument();

     }


     
catch (TransformerException e) {

       
throw new JDOMException("XSLT Trandformation failed"
, e);

     }


   }


五、用例:

1、生成xml文檔:

 

 

public class WriteXML
{

    
public void BuildXML() throws Exception 
{

        Element root,student,number,name,age;         

        root 
= new Element("student-info"); //生成根元素:student-info


        student 
= new Element("student"); //生成元素:student(number,name,age)                             

        number 
= new Element("number");

        name 
= new Element("name"
);

        age 
= new Element("age"
);

        Document doc 
= new Document(root); //將根元素植入文檔doc中


        number.setText(
"001");

        name.setText(
"lnman"
);

        age.setText(
"24"
);

        student.addContent(number);

        student.addContent(name);

        student.addContent(age);

        root.addContent(student);

        Format format 
=
 Format.getCompactFormat();

        format.setEncoding(
"gb2312"); //設置xml文件的字符爲gb2312


        format.setIndent(
"    "); //設置xml文件的縮進爲4個空格

        XMLOutputter XMLOut 
= new XMLOutputter(format);//元素後換行一層元素縮四格 

        XMLOut.output(doc, 
new FileOutputStream("studentinfo.xml"));  

}


    
public static void main(String[] args) throws Exception {

        WriteXML w 
= new
 WriteXML();

        System.out.println(
"Now we build an XML document ....."
);

        w.BuildXML();

        System.out.println(
"finished!"
);

}


}


生成的xml文檔爲:

<?xml version="1.0" encoding="gb2312"?>

<student-info>

    
<student>

        
<number>001</number>

        
<name>lnman</name>

        
<age>24</age>

    
</student>

</student-info>

 

 

創建XML文檔2:

 
public class CreateXML {

  
public void Create() 
{

   
try 
{

    Document doc 
= new
 Document();   

    ProcessingInstruction pi
=new ProcessingInstruction("xml-stylesheet","type="text/xsl" href="test.xsl""
);

    doc.addContent(pi);    

    Namespace ns 
= Namespace.getNamespace("http://www.bromon.org"
 );

    Namespace ns2 
= Namespace.getNamespace("other""http://www.w3c.org"
 );

    Element root 
= new Element("根元素"
, ns);

    root.addNamespaceDeclaration(ns2);

    doc.setRootElement(root);

    Element el1 
= new Element("元素一"
);

    el1.setAttribute(
"屬性""屬性一"
);    

    Text text1
=new Text("元素值"
);

             Element em 
= new Element("元素二").addContent("第二個元素"
);

    el1.addContent(text1);

             el1.addContent(em);             

             Element el2 
= new Element("元素三").addContent("第三個元素"
);

             root.addContent(el1);

             root.addContent(el2);             

             
//縮進四個空格,自動換行,gb2312編碼


             XMLOutputter outputter 
= new XMLOutputter("  "true,"GB2312");

             outputter.output(doc, 
new FileWriter("test.xml"
));

         }
catch(Exception e)  {

          System.out.println(e);

         }


     }
     

     
public static void main(String args[]) 
{

      
new
 CreateXML().Create();

     }
     

 }


2、讀取xml文檔的例子:

import org.jdom.output.*
;

import org.jdom.input.*
;

import org.jdom.*
;

import java.io.*
;

import java.util.*
;

public class ReadXML
{

    
public static void main(String[] args) throws Exception 
{

        SAXBuilder builder 
= new
 SAXBuilder();

        Document read_doc 
= builder.build("studentinfo.xml"
);

        Element stu 
=
 read_doc.getRootElement();

        List list 
= stu.getChildren("student"
);

        
for(int i = 0;i < list.size();i++
{

            Element e 
=
 (Element)list.get(i);

            String str_number 
= e.getChildText("number"
);

            String str_name 
= e.getChildText("name"
);

            String str_age 
= e.getChildText("age"
);

            System.out.println(
"---------STUDENT--------------"
);

            System.out.println(
"NUMBER:" +
 str_number);

            System.out.println(
"NAME:" +
 str_name);

            System.out.println(
"AGE:" +
 str_age);

            System.out.println(
"------------------------------"
);

            System.out.println();

        }
  

       }


}


3、DTD驗證的:

 
public class XMLWithDTD 
{

  
public void validate()  
{

   
try 
{

    SAXBuilder builder 
= new SAXBuilder(true
);

    builder.setFeature(
"http://xml.org/sax/features/validation";,true
); 

    Document doc 
= builder.build(new FileReader("author.xml"
));    

    System.out.println(
"搞掂"
);

    XMLOutputter outputter 
= new
 XMLOutputter();

    outputter.output(doc, System.out);

   }
catch(Exception e) {

    System.out.println(e);

   }
   

  }


  
public static void main(String args[]) {

   
new
 XMLWithDTD().validate();

  }
  

 }


   需要說明的是,這個程序沒有指明使用哪個DTD文件。DTD文件的位置是在XML中指定的,而且DTD不支持命名空間,一個XML只能引用一個DTD,所以程序直接讀取XML中指定的DTD,程序本身不用指定。不過這樣一來,好象就只能使用外部式的DTD引用方式了?高人指點。

 

 

4、XML Schema驗證的:

 
public class XMLWithSchema 
{

  String xml
="test.xml"
;

  String schema
="test-schema.xml"
;

  
public void validate() 
{

   
try 
{

    SAXBuilder builder 
= new SAXBuilder(true
);

    
//指定約束方式爲XML schema


    builder.setFeature(
"http://apache.org/xml/features/validation/schema";,  true);

    
//導入schema文件


builder.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";,schema); 

    Document doc 
= builder.build(new
 FileReader(xml));    

    System.out.println(
"搞掂"
);

    XMLOutputter outputter 
= new
 XMLOutputter();

    outputter.output(doc, System.out);

   }
catch(Exception e) {

    System.out.println(
"驗證失敗:"+
e);

   }
  

  }
 

 }


 上面的程序就指出了要引入的XML Schema文件的位置。

 

 

 系統默認輸出是UTF
-8,這有可能導致出現亂碼。

5
、Xpath例子:

JDOM的關於XPATH的api在org.jdom.xpath這個包裏。這個包下,有一個抽象類XPath.java和實現類JaxenXPath.java, 使用時先用XPath類的靜態方法newInstance(String xpath)得到XPath對象,然後調用它的selectNodes(Object context)方法或selectSingleNode(Object context)方法,前者根據xpath語句返回一組節點(List對象);後者根據一個xpath語句返回符合條件的第一個節點(Object類型)。請看jdom
-1
.0自帶的範例程序: 

     它分析在web.xml文件中的註冊的servlet的個數及參數個數,並輸出角色名。 

web.xml文件: 

<?xml version="1.0" encoding="ISO-8859-1"?>
 

<!--
 

<!DOCTYPE web-
app 

    PUBLIC 
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
 

    
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
 

-->
 

<web-app>
 

    
<servlet>
 

        
<servlet-name>snoop</servlet-name>
 

        
<servlet-class>SnoopServlet</servlet-class>
 

    
</servlet>
 

    
<servlet>
 

        
<servlet-name>file </servlet-name>
 

        
<servlet-class>ViewFile</servlet-class>
 

        
<init-param>
 

            
<param-name>initial</param-name>
 

            
<param-value>1000</param-value>
 

            
<description>The initial value for the counter  <!-- optional --></description>
 

        
</init-param>
 

    
</servlet>
 

    
<servlet-mapping>
 

        
<servlet-name>mv</servlet-name>
 

        
<url-pattern>*.wm</url-pattern>
 

    
</servlet-mapping>
 

    
<distributed/>
 

    
<security-role>
 

      
<role-name>manager</role-name>
 

      
<role-name>director</role-name>
 

      
<role-name>president</role-name>
 

    
</security-role>
 

</web-app>
 

處理程序: 

import java.io.*


import java.util.*
;  

public class XPathReader 
{      

    
public static void main(String[] args) throws IOException, JDOMException 


        
if (args.length != 1


            System.err.println(
"Usage: java XPathReader web.xml"
); 

            
return


        }
 

        String filename 
= args[0];//從命令行輸入web.xml 


        PrintStream out 
= System.out; 

        SAXBuilder builder 
= new
 SAXBuilder(); 

        Document doc 
= builder.build(new File(filename));//
得到Document對象 

 

 

        
// Print servlet information 


        XPath servletPath 
= XPath.newInstance("//servlet");//,選擇任意路徑下servlet元素 

        List servlets 
= servletPath.selectNodes(doc);//返回所有的servlet元素。

        out.println(
"This WAR has "+ servlets.size() +" registered servlets:"); 

        Iterator i 
=
 servlets.iterator(); 

        
while (i.hasNext()) 
{//輸出servlet信息 

            Element servlet 
= (Element) i.next(); 

            out.print(
" " + servlet.getChild("servlet-name"


                                    .getTextTrim() 
+
 

                      
" for " + servlet.getChild("servlet-class"


                                       .getTextTrim()); 

            List initParams 
= servlet.getChildren("init-param"
); 

            out.println(
" (it has " + initParams.size() + " init params)"
);  

        }
              

        
// Print security role information 


        XPath rolePath 
= XPath.newInstance("//security-role/role-name/text()"); 

        List roleNames 
= rolePath.selectNodes(doc);//得到所有的角色名 


        
if (roleNames.size() == 0

            out.println(
"This WAR contains no roles"
); 

        }
 else 

            out.println(
"This WAR contains " + roleNames.size() + " roles:"
); 

            i 
=
 roleNames.iterator(); 

            
while (i.hasNext()) 
{//輸出角色名 

                out.println(
" " + ((Text)i.next()).getTextTrim()); 

            }
 

        }
 

    }
     

}
 

 

 

輸出結果: 

C:java
>
java   XPathReader web.xml 

This WAR has 
2
 registered servlets: 

        snoop 
for SnoopServlet (it has 0
 init params) 

        file 
for ViewFile (it has 1
 init params) 

This WAR contains 
3
 roles: 

        manager 

        director 

        president

 

 

6
、數據輸入要用到XML文檔要通過org.jdom.input包,反過來需要org.jdom.output。如前面所說,關是看API文檔就能夠使用。 

我們的例子讀入XML文件exampleA.xml,加入一條處理指令,修改第一本書的價格和作者,並添加一條屬性,然後寫入文件exampleB.xml: 

//exampleA.xml 


<?xml version="1.0" encoding="GBK"?> 

<bookList>
 

<book>
 

<name>Java編程入門</name>
 

<author>張三</author>
 

<publishDate>2002-6-6</publishDate>
 

<price>35.0</price>
 

</book>
 

<book>
 

<name>XML在Java中的應用</name>
 

<author>李四</author>
 

<publishDate>2002-9-16</publishDate>
 

<price>92.0</price>
 

</book>
 

</bookList>
 

//testJDOM.java 


import org.jdom.*

import org.jdom.output.*


import org.jdom.input.*


import java.io.*


public class TestJDOM


public static void main(String args[])throws Exception


SAXBuilder sb 
= new
 SAXBuilder(); 

//從文件構造一個Document,因爲XML文件中已經指定了編碼,所以這裏不必了 


Document doc 
= sb.build(new FileInputStream("exampleA.xml")); 

ProcessingInstruction pi 
= new ProcessingInstruction//加入一條處理指令 


(
"xml-stylesheet","href="bookList.html.xsl" type="text/xsl""); 

doc.addContent(pi); 

Element root 
= doc.getRootElement(); //得到根元素 


java.util.List books 
= root.getChildren(); //得到根元素所有子元素的集合 

Element book 
= (Element)books.get(0); //得到第一個book元素 

//爲第一本書添加一條屬性 


Attribute a 
= new Attribute("hot","true"); 

book.setAttribute(a); 

Element author 
= book.getChild("author"); //得到指定的字元素 


author.setText(
"王五"); //將作者改爲王五 

//或 Text t = new Text("王五");book.addContent(t); 


Element price 
= book.getChild("price"); //得到指定的字元素 

//修改價格,比較鬱悶的是我們必須自己轉換數據類型,而這正是JAXB的優勢 


author.setText(Float.toString(
50.0f)); 

String indent 
= " "


boolean newLines = true


XMLOutputter outp 
= new XMLOutputter(indent,newLines,"GBK"
); 

outp.output(doc, 
new FileOutputStream("exampleB.xml"
)); 

}
 

}


執行結果exampleB.xml: 

<?xml version="1.0" encoding="GBK"?>
 

<bookList>
 

<book hot=true>
 

<name>Java編程入門</name>
 

<author>50.0</author>
 

<publishDate>2002-6-6</publishDate>
 

<price>35.0</price>
 

</book>
 

<book>
 

<name>XML在Java中的應用</name>
 

<author>李四</author>
 

<publishDate>2002-9-16</publishDate>
 

<price>92.0</price>
 

</book>
 

</bookList>
 

<?xml-stylesheet href="bookList.html.xsl" type="text/xsl"?>
 

在默認情況下,JDOM的Element類的getText()這類的方法不會過濾空白字符,如果你需要過濾,用setTextTrim() 。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章