简介:
dom4j的解析是从上到下的。
dom4j不是javase的一部分,所以需要导入dom4j的jar包。
首先是进入dom4j下载jar包:
下载完成后在eclipse新建一个lib文件夹:
将下载的jar包复制到lib文件夹中:
复制后右击lib文件夹,选择构建路径(builder-panth),然后点配置构建路径:
然后按照步骤(必须导入类路径):
然后再跟着步骤:
最后应用并关闭就能看到一个引用的库里面有下载的jar包:
dom4j的应用:
首先查看org.dom4j.io下的SAXReader类:
public class SAXReader
extends Object
在SAXReader类中有一个方法
从给定的文件中读取一个文档:public Document read(File file) throws DocumentException
返回一个新创建的Document实例对象;
public interface Document
extends Branch
public interface Branch
extends Node
可以发现Document是Node接口的子接口,所以Document实例对象可以使用父接口Node的方法,
在Document中有一个方法:
返回根元素:public Element getRootElement();
在Node中有方法:
返回父节点(不存在则返回空):
public Element getParent();
判断此节点是否支持父节点:
public boolean supportsParent();
设置父节点(如果不支持父节点则无操作):
public void setParent(Element parent);
返回节点的文本:
public String getText();
判断此节点是否为只读:
public boolean isReadOnly();
设置文本内容(节点为可写,isReadOnly为false):
public void setText(String text);
案例:
用dom4j实现获取xml中节点的文本信息:
新建person.xml文档:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>11</age>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
获取person.xml下<name>节点的文本内容:
package dom4jDemo1;
import java.io.File;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4jParseXml {
public static void main(String[] args) throws Exception{
selectName();
}
public static void selectName() throws Exception {
// 创建解析器
SAXReader reader = new SAXReader();
// 通过read()方法读取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml");
// 得到根节点
Element rootElement = doc.getRootElement();
// 获取p1节点
List<Element> lists = rootElement.elements("p1");
for (Element element : lists) {
// Element就是p1,有两个p1
// 获取name节点
Element name = element.element("name");
// 获取name节点的文本内容
String text = name.getText();
System.out.println(text);
}
}
}
输出结果:
通过集合的get(int index)获取索引位置的标签,然后获取标签文本内容:
package dom4jDemo1;
import java.io.File;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4jParseXml {
public static void main(String[] args) throws Exception{
selectName();
}
public static void selectName() throws Exception {
// 创建解析器
SAXReader reader = new SAXReader();
// 通过read()方法读取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml");
// 得到根节点
Element rootElement = doc.getRootElement();
// 获取p1节点
List<Element> lists = rootElement.elements("p1");
// 通过List中的get()方法获取对应索引位置的元素
System.out.println(lists.get(0).element("age").getText());
}
}
输出结果:
为了体现dom4j从上到下解析的过程,新建一个方法进行重复获取:
public static void selectNameF() throws Exception {
// 创建解析器
SAXReader reader = new SAXReader();
// 通过read()方法读取xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml");
// 得到根节点
Element rootElement = doc.getRootElement();
// 获取p1
Element p1 = rootElement.element("p1");
// 获取p1下的name
Element name = p1.element("name");
// 获取name文本
String text1 = name.getText();
// 获取p1
Element p1_2 = rootElement.element("p1");
// 获取p1下的name
Element name2 = p1_2.element("name");
// 获取name文本
String text2 = name2.getText();
System.out.println(text1);
System.out.println(text2);
}
输出结果:
可以发现,在进行重复获取<p1>的时候并不是对第一个<p1>标签进行了两次获取,而是获取一次第一个<p1>标签之后,又向下获取第二个<p1>标签,所以可以得到第一个<name>标签的文本内容和第二个<name>标签的文本内容。
使用dom4j进行添加操作:
有一个写入流XMLWriter:
java.lang.Object
extended byorg.xml.sax.helpers.XMLFilterImpl
extended byorg.dom4j.io.XMLWriter
public class XMLWriter
extends XMLFilterImpl
implements LexicalHandler
构造方法:
public XMLWriter(OutputStream out,OutputFormat format) throws UnsupportedEncodingException
其中有一个写入的操作方法:
public void write(Document doc) throws IOException
传入的是Document类型参数,一般这个参数都是在回写xml操作之前进行了修改的参数。
/**
* 在第一个p1标签后添加一个sex标签并设置文本内容为nv
* @throws Exception
*/
public static void addSex() throws Exception{
// 创建解析器
SAXReader reader = new SAXReader();
// 解析xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml");
// 获取根节点
Element rootElement = doc.getRootElement();
// 获取第一个p1
Element p1_1 = rootElement.element("p1");
// 添加新节点sex
Element sex = p1_1.addElement("sex");
// 设置sex节点文本
sex.setText("nv");
// 回写xml
// 格式化文本,有缩进的效果
OutputFormat format = OutputFormat.createPrettyPrint();
// XML输出流
XMLWriter write = new XMLWriter(new FileOutputStream("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"),format);
// 写入读取的已经修改后的xml文档,此时的doc是已经修改后的xml数据
write.write(doc);
// 关闭流
write.close();
System.out.println("ok");
}
添加成功:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>11</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
如果使用另一个OutputFormat的static方法:OutputFormat.createCompactFormat();
OutputFormat format = OutputFormat.createCompactFormat();
会发现xml内容会被压缩为一行:
在指定位置添加新元素:
这里会使用一个DocumentHelper类:
java.lang.Object
extended byorg.dom4j.DocumentHelper
public final class DocumentHelper
extends Object
可以发现这个类是final修饰的,所以其中的方法都是static方法可以直接用 类名. 的形式进行调用,那么就会使用到其中的一个方法:
public static Element createElement(String name)
使用 DocumentHelper.createElement("school") 可以直接创建一个名为"school"的新标签,然后使用List集合的add(int index,Element ele)方法将新标签添加进去,添加时确定添加位置也是在add()方法中。
/**
* 在age标签前面添加school标签
* @throws Exception
*/
public static void addSchool() throws Exception{
// 创建解析器
SAXReader reader = new SAXReader();
// 解析xml
Document doc = reader.read("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml");
// 获取根元素
Element rootElement = doc.getRootElement();
// 获取第一个p1
Element p1_1 = rootElement.element("p1");
// 获取第一个p1下的所有标签元素
List<Element> lists = p1_1.elements();
// 创建新元素
Element school = DocumentHelper.createElement("school");
// 添加元素,第一个参数是索引,第二个参数是新元素,表示在索引位置添加新元素
lists.add(1, school);
// 设置文本
school.setText("hope school");
// 回写xml
// 格式化缩进
OutputFormat format = OutputFormat.createPrettyPrint();
// 写入流
XMLWriter writer = new XMLWriter(new FileOutputStream("src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml"),format);
// 写入操作
writer.write(doc);
// 关闭流
writer.close();
// 提示完成
System.out.println("its ok!");
}
添加后的xml:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<school>hope school</school>
<age>11</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
将重复的操作封装为方法:
package cn.dom4jUtile.lm;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public final class Dom4jUtils {
/**
* 将xml的回写操作封装为一个方法
* @param xmlPath:xml的路径
* @param doc:回写操作前修改数据后的Document对象
*/
public static void ReWriteXml(String xmlPath,Document doc) {
try {
//缩进文本
OutputFormat format = OutputFormat.createPrettyPrint();
// 创建写入流
XMLWriter Writer = new XMLWriter(new FileOutputStream(xmlPath),format);
Writer.write(doc);
Writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将创建解析器和解析xml的步骤封装为一个方法
* @param path xml文件的路劲
* @return
*/
public static Document getDocument(String path) {
try {
// 创建解析器
SAXReader reader = new SAXReader();
// 解析xml得到Document
Document doc = reader.read(path);
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
可以发现在上面的代码仍然有重复的地方可以改进,那就是路径,那么就可以设置一个路径常量,这样就可以在对路径进行修改的时候达到改一而改全部的目的:
package cn.dom4jUtile.lm;
import java.io.File;
import java.io.FileOutputStream;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public final class Dom4jUtils {
public static final String PATH="src" + File.separator + "dom4jDemo1" + File.separator + "dom4j1_1.xml";
/**
* 将xml的回写操作封装为一个方法
* @param xmlPath:xml的路径
* @param doc:回写操作前修改数据后的Document对象
*/
public static void ReWriteXml(Document doc) {
try {
//缩进文本
OutputFormat format = OutputFormat.createPrettyPrint();
// 创建写入流
XMLWriter Writer = new XMLWriter(new FileOutputStream(PATH),format);
Writer.write(doc);
Writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将创建解析器和解析xml的步骤封装为一个方法
* @param path xml文件的路劲
* @return
*/
public static Document getDocument() {
try {
// 创建解析器
SAXReader reader = new SAXReader();
// 解析xml得到Document
Document doc = reader.read(PATH);
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
这样在修改xml文档路径的时候就可以直接修改路径常量,就可以修改所有的路径了。
这样就大大减少了代码的重复性,降低了时间成本。
使用dom4j实现修改节点内容的操作:
/** * 创建一个方法:删除第一个p1下的school元素 */ public static void removeSchool() { // 获取解析xml后的Document对象 Document doc = Dom4jUtils.getDocument(); // 获取根节点 Element rootElement = doc.getRootElement(); // 获取第一个p1 Element p1_1 = rootElement.element("p1"); // 获取第一个p1下的school元素 Element school = p1_1.element("school"); // // 得到父节点 // Element parent = school.getParent(); // // 通过父节点删除school元素 // parent.remove(school); // 直接使用p1删除school p1_1.remove(school); // 回写xml Dom4jUtils.ReWriteXml(doc); }
删除后:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<p1>
<name>zs</name>
<age>100</age>
<sex>nv</sex>
</p1>
<p1>
<name>ls</name>
<age>11</age>
</p1>
</person>
获取元素的属性:
public Attribute attribute(int index)
获取元素属性列表中的第 index 个,例如元素有两个属性,那么元素A.attribute(0):表示获取元素A的第一个属性;
public Attribute attribute(String name)
获取指定名称的属性。
/** * 获取第一个p1下的name标签的属性 */ public static void getAttribute() { // 获取解析xml后的Document对象 Document doc = Dom4jUtils.getDocument(); // 获取根节点 Element rootElement = doc.getRootElement(); // 获取第一个p1 Element p1_1 = rootElement.element("p1"); // 获取name Element name = p1_1.element("name"); // 获取name中的属性,0:索引为0,表示第一个属性 Attribute at = name.attribute(0); System.out.println(at.getName() + ": " + at.getData()); }
输出结果: