JDOM使用详解及实例
一、
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(0, new 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 "\n A cool demo\n"
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("\t" + 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("\t" + ((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()
。