一、JDOM?/P>
JDOM是一个开源项目,它基于树型结构,利用UJAVA的技术对XML文档实现解析、生成、序列化以及多种操作?/P>
JDOM直接为JAVA~程服务。它利用更ؓ强有力的JAVA语言的诸多特性(Ҏ(gu)重蝲、集合概念以及映)Q把SAX和DOM的功能有效地l合h?/P>
在用设计上可能地隐藏原来使用XMLq程中的复杂性。利用JDOM处理XML文档是一件轻松、简单的事?/P>
JDOM?000q的春天被BrettMcLaughlin和JasonHunter开发出来,以I补DOM及SAX在实际应用当中的不之处?/P>
q些不之处主要在于SAX没有文档修改、随问以及输出的功能Q而对于DOM来说QJAVAE序员在使用时来用v来总觉得不太方ѝ?/P>
DOM的缺点主要是来自于由于Dom是一个接口定义语aQIDLQ?它的d是在不同语言实现中的一个最低的通用标准Qƈ不是为JAVA特别设计的。JDOM的最新版本ؓJDOMBeta9。最qJDOM被收录到JSR-102内,q标志着JDOM成ؓ了JAVAq_l成的一部分?/P>
二、JDOM包概?/P>
JDOM是由以下几个包组成的
org.jdom 包含了所有的xml文档要素的javac?/P>
org.jdom.adapters 包含了与dom适配的javac?/P>
org.jdom.filter 包含了xml文档的过滤器c?/P>
org.jdom.input 包含了读取xml文档的类
org.jdom.output 包含了写入xml文档的类
org.jdom.transform 包含了将jdomxml文档接口转换为其他xml文档接口
org.jdom.xpath 包含了对xml文档xpath操作的类三、JDOMc说?/P>
1、org.JDOMq个包里的类是你J解析xml文g后所要用到的所有数据类型?/P>
Attribute
CDATA
Coment
DocType
Document
Element
EntityRef
Namespace
ProscessingInstruction
Text
2、org.JDOM.transform在涉及xslt格式转换时应使用下面?个类
JDOMSource
JDOMResult
org.JDOM.input
3、输入类Q一般用于文档的创徏工作
SAXBuilder
DOMBuilder
ResultSetBuilder
org.JDOM.output
4、输出类Q用于文档{换输?/P>
XMLOutputter
SAXOutputter
DomOutputter
JTreeOutputter
使用前注意事:
1.JDOM对于JAXP以及TRax的支?/P>
JDOM支持JAXP1.1Q你可以在程序中使用M的parser工具c?默认情况下是JAXP的parser?/P>
制定特别的parser可用如下形式
SAXBuilderparser
=newSAXBuilder("org.apache.crimson.parser.XMLReaderImpl");
Documentdoc=parser.build("http://www.cafeconleche.org/");
//workwiththedocument...
JDOM也支持TRaXQXSLT可通过JDOMSource以及JDOMResultcL转换Q参见以后章节)
2.注意在JDOM里文档(DocumentQ类由org.JDOM.Document来表C。这要与org.w3c.dom中的Document区别开Q这2U格式如何{换在后面会说明?/P>
以下如无Ҏ(gu)均指JDOM里的Document?/P>
四、JDOM主要使用Ҏ(gu)
1.Ducumentc?/P>
(1)Document的操作方法:
Elementroot=newElement("GREETING");
Documentdoc=newDocument(root);
root.setText("HelloJDOM!");
或者简单的使用Documentdoc=newDocument(newElement("GREETING").setText("HelloJDOM!t"));
q点和DOM不同。Dom则需要更为复杂的代码Q如下:
DocumentBuilderFactoryfactory=DocumentBuilderFactory.newInstance();
DocumentBuilderbuilder=factory.newDocumentBuilder();
Documentdoc=builder.newDocument();
Elementroot=doc.createElement("root");
Texttext=doc.createText("Thisistheroot");
root.appendChild(text);
doc.appendChild(root);
注意事项QJDOM不允许同一个节点同时被2个或多个文档相关联,要在W?个文档中使用原来老文档中的节点的话。首先需要用detach()把这个节点分开来?/P>
(2)从文件、流、系lID、URL得到Document对象Q?/P>
DOMBuilderbuilder=newDOMBuilder();
Documentdoc=builder.build(newFile("jdom_test.xml"));
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=builder.build(url);
在新版本中DOMBuilder已经Deprecated掉DOMBuilder.builder(url)Q用SAX效率会比较快?/P>
q里举一个小例子Qؓ了简单v见,使用String对象直接作ؓxml数据源:
publicjdomTest(){
StringtextXml=null;
textXml="<note>";
textXml=textXml+
"<to>aaa</to><from>bbb</from><heading>ccc</heading><body>ddd</body>";
textXml=textXml+"</note>";
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=null;
Readerin=newStringReader(textXml);
try{
doc=builder.build(in);
Elementroot=doc.getRootElement();
Listls=root.getChildren();//注意此处取出的是root节点下面的一层的Element集合
for(Iteratoriter=ls.iterator();iter.hasNext();){
Elementel=(Element)iter.next();
if(el.getName().equals("to")){
System.out.println(el.getText());
}
}
}
catch(IOExceptionex){
ex.printStackTrace();
}
catch(JDOMExceptionex){
ex.printStackTrace();
}
}
(3)DOM的document和JDOM的Document之间的相互{换用方法,单!
DOMBuilderbuilder=newDOMBuilder();
org.jdom.DocumentjdomDocument=builder.build(domDocument);
DOMOutputterconverter=newDOMOutputter();//workwiththeJDOMdocument?/P>
org.w3c.dom.DocumentdomDocument=converter.output(jdomDocument);
//workwiththeDOMdocument?/P>
2.XML文档输出
XMLOutPutterc:
JDOM的输出非常灵z?支持很多Uio格式以及风格的输?/P>
Documentdoc=newDocument(...);
XMLOutputteroutp=newXMLOutputter();
outp.output(doc,fileOutputStream);//Rawoutput
outp.setTextTrim(true);//Compressedoutput
outp.output(doc,socket.getOutputStream());
outp.setIndent("");//Prettyoutput
outp.setNewlines(true);
outp.output(doc,System.out);
详细请参阅最新的JDOMAPI手册
3.Elementc:
(1)览Element?/P>
Elementroot=doc.getRootElement();//获得根元素element
ListallChildren=root.getChildren();//获得所有子元素的一个list
ListnamedChildren=root.getChildren("name");//获得指定名称子元素的list
Elementchild=root.getChild("name");//获得指定名称的第一个子元素
JDOMl了我们很多很灵zȝ使用Ҏ(gu)来管理子元素Q这里的List是java.util.ListQ?/P>
ListallChildren=root.getChildren();
allChildren.remove(3);//删除W四个子元素
allChildren.removeAll(root.getChildren("jack"));//删除叫“jack”的子元?/P>
root.removeChildren("jack");//便捷写法
allChildren.add(newElement("jane"));//加入
root.addContent(newElement("jane"));//便捷写法
allChildren.add(0,newElement("first"));
(2)UdElements:
在JDOM里很?/P>
Elementmovable=newElement("movable");
parent1.addContent(movable);//place
parent1.removeContent(movable);//remove
parent2.addContent(movable);//add
在Dom?/P>
Elementmovable=doc1.createElement("movable");
parent1.appendChild(movable);//place
parent1.removeChild(movable);//remove
parent2.appendChild(movable);//出错!
补充Q纠错?/P>
JDOM的Element构造函敎ͼ以及它的其他函数Q会查element是否合法?/P>
而它的add/removeҎ(gu)会检查树l构Q检查内容如下:
1.在Q何树中是否有回环节点
2.是否只有一个根节点
3.是否有一致的命名I间QNamespacesQ?/P>
(3)Element的text内容d
<description>
Acooldemo
</description>
//Thetextisdirectlyavailable
//Returns"\nAcooldemo\n"
Stringdesc=element.getText();
//There'saconvenientshortcut
//Returns"Acooldemo"
Stringdesc=element.getTextTrim();
(4)Elment内容修改
element.setText("Anewdescription");
3.可正解释特D字W?/P>
element.setText("<xml>content");
4.CDATA的数据写入、读?/P>
element.addContent(newCDATA("<xml>content"));
StringnoDifference=element.getText();
混合内容
element可能包含很多U内容,比如?/P>
<table>
<!--Somecomment-->
Sometext
<tr>Somechildelement</tr>
</table>
取table的子元素tr
Stringtext=table.getTextTrim();
Elementtr=table.getChild("tr");
也可使用另外一个比较简单的Ҏ(gu)
ListmixedCo=table.getContent();
Iteratoritr=mixedCo.iterator();
while(itr.hasNext()){
Objecto=i.next();
if(oinstanceofComment){...}
//q里可以写成Comment,Element,Text,CDATA,ProcessingInstruction,或者是EntityRef的类?/P>
}
//现在U除Comment,注意q里游标应ؓ1。这是由于回车键也被解析成Textcȝ~故,所以Comment应??/P>
mixedCo.remove(1);
4.Attributec?/P>
<tablewidth="100%"border="0"></table>
Stringwidth=table.getAttributeValue("width");//获得attribute
intborder=table.getAttribute("width").getIntValue();
table.setAttribute("vspace","0");//讄a(chn)ttribute
table.removeAttribute("vspace");//删除一个或全部attribute
table.getAttributes().clear();
5.处理指o(ProcessingInstructions)操作
一个Pls的例?/P>
<?br?>
<?cocoon-processtype="xslt"?>
| |
| |
目标 数据
处理目标名称(Target)
Stringtarget=pi.getTarget();
获得所有数据(dataQ,在目标(targetQ以后的所有数据都会被q回?/P>
Stringdata=pi.getData();
Stringtype=pi.getValue("type");获得指定属性的数据
Listls=pi.getNames();获得所有属性的名称
6.命名I间操作
<xhtml:html
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xhtml:title>HomePage</xhtml:title>
</xhtml:html>
Namespacexhtml=Namespace.getNamespace("xhtml","http://www.w3.org/1999/xhtml");
Listkids=html.getChildren("title",xhtml);
Elementkid=html.getChild("title",xhtml);
kid.addContent(newElement("table",xhtml));
7.XSLT格式转换
使用以下函数可对XSLT转换
最后如果你需要用w3c的Document则需要{换一下?/P>
publicstaticDocumenttransform(StringstylesheetQDocumentin)
throwsJDOMException{
try{
Transformertransformer=TransformerFactory.newInstance()
.newTransformer(newStreamSource(stylesheet));
JDOMResultout=newJDOMResult();
transformer.transform(newJDOMSource(in),out);
returnout.getDeocument();
}
catch(TransformerExceptione){
thrownewJDOMException("XSLTTrandformationfailed",e);
}
}
五、用?
1、生成xml文档Q?/P>
publicclassWriteXML{
publicvoidBuildXML()throwsException{
Elementroot,student,number,name,age;
root=newElement("student-info");//生成根元素:student-info
student=newElement("student");//生成元素Qstudent(number,name,age)
number=newElement("number");
name=newElement("name");
age=newElement("age");
Documentdoc=newDocument(root);//根元素植入文档doc?/P>
number.setText("001");
name.setText("lnman");
age.setText("24");
student.addContent(number);
student.addContent(name);
student.addContent(age);
root.addContent(student);
Formatformat=Format.getCompactFormat();
format.setEncoding("gb2312");//讄xml文g的字Wؓgb2312
format.setIndent(" ");//讄xml文g的羃qؓ4个空?/P>
XMLOutputterXMLOut=newXMLOutputter(format);//元素后换行一层元素羃四格
XMLOut.output(doc,newFileOutputStream("studentinfo.xml"));
}
publicstaticvoidmain(String[]args)throwsException{
WriteXMLw=newWriteXML();
System.out.println("NowwebuildanXMLdocument.....");
w.BuildXML();
System.out.println("finished!");
}
}
生成的xml文档为:
<?xmlversion="1.0"encoding="gb2312"?>
<student-info>
<student>
<number>001</number>
<name>lnman</name>
<age>24</age>
</student>
</student-info>
创徏XML文档2Q?/P>
publicclassCreateXML{
publicvoidCreate(){
try{
Documentdoc=newDocument();
ProcessingInstructionpi=newProcessingInstruction("xml-stylesheet","type="text/xsl"href="test.xsl"");
doc.addContent(pi);
Namespacens=Namespace.getNamespace("http://www.bromon.org");
Namespacens2=Namespace.getNamespace("other","http://www.w3c.org");
Elementroot=newElement("根元?,ns);
root.addNamespaceDeclaration(ns2);
doc.setRootElement(root);
Elementel1=newElement("元素一");
el1.setAttribute("属?,"属性一");
Texttext1=newText("元素?);
Elementem=newElement("元素?).addContent("W二个元?);
el1.addContent(text1);
el1.addContent(em);
Elementel2=newElement("元素?).addContent("W三个元?);
root.addContent(el1);
root.addContent(el2);
//~进四个I格,自动换行,gb2312~码
XMLOutputteroutputter=newXMLOutputter(" ",true,"GB2312");
outputter.output(doc,newFileWriter("test.xml"));
}catch(Exceptione) {
System.out.println(e);
}
}
publicstaticvoidmain(Stringargs[]){
newCreateXML().Create();
}
}
2、读取xml文档的例子:
importorg.jdom.output.*;
importorg.jdom.input.*;
importorg.jdom.*;
importjava.io.*;
importjava.util.*;
publicclassReadXML{
publicstaticvoidmain(String[]args)throwsException{
SAXBuilderbuilder=newSAXBuilder();
Documentread_doc=builder.build("studentinfo.xml");
Elementstu=read_doc.getRootElement();
Listlist=stu.getChildren("student");
for(inti=0;i<list.size();i++){
Elemente=(Element)list.get(i);
Stringstr_number=e.getChildText("number");
Stringstr_name=e.getChildText("name");
Stringstr_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验证的:
publicclassXMLWithDTD{
publicvoidvalidate() {
try{
SAXBuilderbuilder=newSAXBuilder(true);
builder.setFeature("http://xml.org/sax/features/validation";,true);
Documentdoc=builder.build(newFileReader("author.xml"));
System.out.println("搞掂");
XMLOutputteroutputter=newXMLOutputter();
outputter.output(doc,System.out);
}catch(Exceptione){
System.out.println(e);
}
}
publicstaticvoidmain(Stringargs[]){
newXMLWithDTD().validate();
}
}
需要说明的是,q个E序没有指明使用哪个DTD文g。DTD文g的位|是在XML中指定的Q而且DTD不支持命名空_一个XML只能引用一个DTDQ所以程序直接读取XML中指定的DTDQ程序本w不用指定。不q这样一来,好象只能用外部式的DTD引用方式了?高h指点?/P>
4、XMLSchema验证的:
publicclassXMLWithSchema{
Stringxml="test.xml";
Stringschema="test-schema.xml";
publicvoidvalidate(){
try{
SAXBuilderbuilder=newSAXBuilder(true);
//指定U束方式为XMLschema
builder.setFeature("http://apache.org/xml/features/validation/schema";, true);
//导入schema文g
builder.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";,schema);
Documentdoc=builder.build(newFileReader(xml));
System.out.println("搞掂");
XMLOutputteroutputter=newXMLOutputter();
outputter.output(doc,System.out);
}catch(Exceptione){
System.out.println("验证p|:"+e);
}
}
}
上面的程序就指出了要引入的XMLSchema文g的位|?/P>
pȝ默认输出是UTF-8Q这有可能导致出Cؕ码?/P>
5、Xpath例子Q?/P>
JDOM的关于XPATH的api在org.jdom.xpathq个包里。这个包下,有一个抽象类XPath.java和实现类JaxenXPath.javaQ用时先用XPathcȝ静态方法newInstance(Stringxpath)得到XPath对象Q然后调用它的selectNodes(Objectcontext)Ҏ(gu)或selectSingleNode(Objectcontext)Ҏ(gu)Q前者根据xpath语句q回一l节?List对象)Q后者根据一个xpath语句q回W合条g的第一个节?Objectcd)。请看jdom-1.0自带的范例程序:
它分析在web.xml文g中的注册的servlet的个数及参数个数Qƈ输出角色名?/P>
web.xml文gQ?/P>
<?xmlversion="1.0"encoding="ISO-8859-1"?>
<!--
<!DOCTYPEweb-app
PUBLIC"-//SunMicrosystems,Inc.//DTDWebApplication2.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>Theinitialvalueforthecounter <!--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>
处理E序Q?/P>
importjava.io.*;
importjava.util.*;
publicclassXPathReader{
publicstaticvoidmain(String[]args)throwsIOException,JDOMException{
if(args.length!=1){
System.err.println("Usage:javaXPathReaderweb.xml");
return;
}
Stringfilename=args[0];//从命令行输入web.xml
PrintStreamout=System.out;
SAXBuilderbuilder=newSAXBuilder();
Documentdoc=builder.build(newFile(filename));//得到Document对象
//Printservletinformation
XPathservletPath=XPath.newInstance("http://servlet");//,选择L路径下servlet元素
Listservlets=servletPath.selectNodes(doc);//q回所有的servlet元素?/P>
out.println("ThisWARhas"+servlets.size()+"registeredservlets:");
Iteratori=servlets.iterator();
while(i.hasNext()){//输出servlet信息
Elementservlet=(Element)i.next();
out.print("\t"+servlet.getChild("servlet-name")
.getTextTrim()+
"for"+servlet.getChild("servlet-class")
.getTextTrim());
ListinitParams=servlet.getChildren("init-param");
out.println("(ithas"+initParams.size()+"initparams)");
}
//Printsecurityroleinformation
XPathrolePath=XPath.newInstance("http://security-role/role-name/text()");
ListroleNames=rolePath.selectNodes(doc);//得到所有的角色?/P>
if(roleNames.size()==0){
out.println("ThisWARcontainsnoroles");
}else{
out.println("ThisWARcontains"+roleNames.size()+"roles:");
i=roleNames.iterator();
while(i.hasNext()){//输出角色?/P>
out.println("\t"+((Text)i.next()).getTextTrim());
}
}
}
}
输出l果:
C:\java>java XPathReaderweb.xml
ThisWARhas2registeredservlets:
snoopforSnoopServlet(ithas0initparams)
fileforViewFile(ithas1initparams)
ThisWARcontains3roles:
manager
director
president
6、数据输入要用到XML文档要通过org.jdom.input包,反过来需要org.jdom.output。如前面所_x看API文档p够用?/P>
我们的例子读入XML文gexampleA.xmlQ加入一条处理指令,修改W一本书的h(hun)格和作者,q添加一条属性,然后写入文gexampleB.xmlQ?/P>
//exampleA.xml
<?xmlversion="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
importorg.jdom.*;
importorg.jdom.output.*;
importorg.jdom.input.*;
importjava.io.*;
publicclassTestJDOM{
publicstaticvoidmain(Stringargs[])throwsException{
SAXBuildersb=newSAXBuilder();
//从文件构造一个DocumentQ因为XML文g中已l指定了~码Q所以这里不必了
Documentdoc=sb.build(newFileInputStream("exampleA.xml"));
ProcessingInstructionpi=newProcessingInstruction//加入一条处理指?/P>
("xml-stylesheet","href=\"bookList.html.xsl\"type=\"text/xsl\"");
doc.addContent(pi);
Elementroot=doc.getRootElement();//得到根元?/P>
java.util.Listbooks=root.getChildren();//得到根元素所有子元素的集?/P>
Elementbook=(Element)books.get(0);//得到W一个book元素
//为第一本书d一条属?/P>
Attributea=newAttribute("hot","true");
book.setAttribute(a);
Elementauthor=book.getChild("author");//得到指定的字元素
author.setText("王五");//作者改为王?/P>
//或Textt=newText("王五");book.addContent(t);
Elementprice=book.getChild("price");//得到指定的字元素
//修改hQ比较郁L是我们必自p{换数据类型,而这正是JAXB的优?/P>
author.setText(Float.toString(50.0f));
Stringindent="";
booleannewLines=true;
XMLOutputteroutp=newXMLOutputter(indent,newLines,"GBK");
outp.output(doc,newFileOutputStream("exampleB.xml"));
}
};
执行l果exampleB.xmlQ?/P>
<?xmlversion="1.0"encoding="GBK"?>
<bookList>
<bookhot=”true?gt;
<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-stylesheethref="bookList.html.xsl"type="text/xsl"?>
在默认情况下QJDOM的ElementcȝgetText()q类的方法不会过滤空白字W,如果你需要过滤,用setTextTrim()