【Java解析XML】【三】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 包概览

maven结构:

<dependency>
	<groupId>org.jdom</groupId>
	<artifactId>jdom</artifactId>
<version>1.1</version>

打开jar结构,看到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这个包里的类是你解析xml文件后所要用到的所有数据类型和异常。部分如下:
Attribute
CDATA
Coment
DocType
Document
Element
EntityRef
Namespace
ProscessingInstruction
Text

2、org.JDOM.transform在涉及xslt格式转换时使用类


3、 org.JDOM.input 输入类,一般用于文档的创建工作

SAXBuilder
DOMBuilder
ResultSetBuilder
4、
org.JDOM.output输出类,用于文档转换输出

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对象:

使用dom

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

使用sax

SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(url);

在新版本中DOMBuilder 已经Deprecated掉 DOMBuilder.builder(url),用SAX效率会比较快。


这里举一个小例子,为了简单起见,使用String对象直接作为xml数据源:

public class App {
	public static void main(String[] args) throws Exception {
		StringBuilder textXml = new StringBuilder("<companies><name>baidu</name>");
		textXml.append("<contry>CN</contry><ceo>liyanhong</ceo></companies>");
	
	
		// 使用SAXBuilder
		SAXBuilder builder = new SAXBuilder();
		Document doc = null;
		Reader in = new StringReader(textXml.toString());

		doc = builder.build(in);
		Element root = doc.getRootElement();
		//将子元素放入列表
		List<Element> ls=root.getChildren();
		//迭代输出子元素的文本内容
		Iterator<Element> iter = ls.iterator();
		while(iter.hasNext()){
			System.out.println(iter.next().getText());
		}	

	}
}
输出:

baidu
CN
liyanhong

(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);


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方法会检查树结构,检查内容如下:

  • 在任何树中是否有回环节点
  • 是否只有一个根节点
  • 是否有一致的命名空间(Namespaces)

(3)Element的文本内容读取

String desc = element.getText();
//清除前后空格
String desc = element.getTextTrim();

(4)Elment内容修改
element.setText("A new description");


3.可正确解释特殊字符


4.CDATA的数据写入、读出
element.addContent(new CDATA(" content"));
String noDifference = element.getText();


混合内容
element可能包含很多种内容,比如说Some text,Some child element

取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类
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)操作


6.命名空间操作


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文档:
创建XML文档1:学生信息

public class CreateXML {
   @Test
   public void create() 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("1001");
        name.setText("chenjazz");
        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")); 
    }

}

在项目根目录生成的文件为:

<?xml version="1.0" encoding="gb2312"?>
<student-info>
    <student>
        <number>1001</number>
        <name>chenjazz</name>
        <age>24</age>
    </student>
</student-info>

   

创建XML文档2:
 
public class CreateXML {
	@Test
	public void create() throws Exception {
		Document doc = new Document();
		Map<Object, Object> map =new HashMap<Object, Object>();
		map.put("xxxx", "1111");
		ProcessingInstruction pi = new ProcessingInstruction("xml-stylesheet",map);
		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);
		
		XMLOutputter outputter = new XMLOutputter();
		
		outputter.output(doc, new FileWriter("test.xml"));
	}
}


2、读取xml文档的例子:

package com.jazz.testm.testm_t1;

import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.junit.Test;

public class CreateXML {
	@Test
	public void parse() throws Exception {
		SAXBuilder builder = new SAXBuilder();
		Document read_doc = builder.build("studentinfo.xml");
		Element stu = read_doc.getRootElement();
		List<Element> list = stu.getChildren("student");
		for (int i = 0; i < list.size(); i++) {
			Element e = 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验证的:


 
 
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类 型)。


 
6、数据输入

要用到XML文档要通过org.jdom.input包,反过来需要org.jdom.output。

我们的例子读入XML文件exampleA.xml,加入一条处理指令,修改第一本书的价格和作者,并添加一条属性,然后写入文件exampleB.xml:

package com.jazz.testm.testm_t1;

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.ProcessingInstruction;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.junit.Test;

public class CreateXML {
	@Test
	public void parse() 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));
		
		XMLOutputter outp = new XMLOutputter();
		outp.output(doc, new FileOutputStream("exampleB.xml"));
	}
}


你可能感兴趣的:(【Java解析XML】【三】JDOM介绍)