DOM4J
XML解析
1. 常用API
- 解析器:SAXReader
- 文档对象:Document
- 元素对象:Element
- 文档帮助类(用于创建节点):DocumentHelper
- 文档对象子类:DefaultElement
- 文档对象子类:BaseElement
- 格式化输出对象:OutputFormat
- 保存文件对象:XMLWriter
2. 解析XML获取文档对象
public static void main(String[] args) {// 创建SAXReader对象SAXReader reader = new SAXReader();// 解析XML获取Document对象try {Document doc = reader.read("/bin/LocalList.xml");} catch (DocumentException e) {e.printStackTrace();}}
3. 获取节点文本内容
private static String getElementText(Document doc) {// 获取根节点Element root = doc.getRootElement();// 获取指定节点集合List<Element> elements = root.elements("City");// 获取指定节点Element e = elements.get(7);// 获取指定节点的文本内容String text = e.getText();return text;}
4. 递归获取所有节点的文本
private static void getAllElementText(Document doc) {// 获取根节点Element root = doc.getRootElement();// 递归遍历所有节点recursion(root);}// 使用深度优先搜索递归遍历所有节点private static void recursion(Element node) {// 如果非元素节点,则直接返回if (node.getNodeType() != Element.ELEMENT_NODE) {return;}// 如果该节点无子元素节点,则输出元素文本if (node.elements().isEmpty()) {System.out.println(node.getText());} else {// 如果该节点有子元素,则递归遍历List<Element> elements = node.elements();for (Element element : elements) {// 递归调用recursion(element);}}}
5. 使用迭代器获取所有City节点的元素内容
private static void getCityElementText(Document doc) {// 获取根元素节点Element root = doc.getRootElement();// 使用元素迭代器进行迭代for (Iterator<Element> iterator = root.elementIterator(); iterator.hasNext();) {Element e = iterator.next();// 如果该节点无子元素节点,则输出元素文本内容if (e.elements().isEmpty()) {System.out.println(e.getText());}}}
6. 将Document保存到XML中
private static void saveXML(Document doc) {try {// 创建XML文件的字节输出流OutputStream out = new FileOutputStream("src/LocalList.xml");// 获取数据格式的对象,createCompactFormat紧凑格式,createPrettyPrint缩进格式OutputFormat format = OutputFormat.createPrettyPrint();// 创建XMLWriter对象XMLWriter writer = new XMLWriter(out, format);// 将DOM树写入XML文件writer.write(doc);// 关闭资源writer.close();} catch (IOException e) {e.printStackTrace();}}
7. 修改元素文本内容
private static void update(Document doc) {// 获取要修改节点Element root = doc.getRootElement();Element element = (Element) root.elements().get(3);// 修改文本内容element.setText("天上人间");// 保存文件saveXML(doc);}
8. 添加子元素节点
private static void addChild(Document doc) {// 获取要添加的父元素节点Element root = doc.getRootElement();Element city = (Element) root.elements().get(3);// 创建要添加的子元素节点Element street = DocumentHelper.createElement("street");// Element streetE1 = new DefaultElement("street");// Element streetE2 = new BaseElement("street");// 设置节点的文本内容street.setText("南天门大街");// 将子节点添加到父节点中city.add(street);// 保存文件saveXML(doc);}
9. 添加兄弟元素节点
public static void addSibling(Document doc) {// 获取目标元素节点Element root = doc.getRootElement();List<Element> elist = root.elements("City");// 创建要添加的元素节点Element city = new DefaultElement("City");// <City></City>// 设置新节点的文本city.setText("哈哈区");// 在指定位置加入元素 cityelist.add(4, city);// 保存文件saveXML(doc);}
10. 删除指定节点
public static void removeElement(Document doc) {// 获取要删除节点Element root = doc.getRootElement();Element city = (Element) root.elements("City").get(3);Element street = (Element) city.elements("street").get(0);// 用父节点删除子节点city.remove(street);// 保存文件saveXML(doc);}
11. 为节点添加属性
public static void addAttribute(Document doc) {// 获取要添加属性的节点Element root = doc.getRootElement();Element city = (Element) root.elements("City").get(3);// 为节点添加属性city.addAttribute("type", "food");// 保存文件saveXML(doc);}
XPath
概述
XPath的作用就像在一个文件系统中定位文件一样在XML文件中定位元素,XPath是由W3C的XPath 1.0标准所描述。
标准
1. 如果路径以斜线 / 开始,那么该路径就表示到一个元素的绝对路径。
/AAA/CCC:选择AAA的所有CCC子元素。
2. 如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)。
//DDD/BBB:选择父元素是DDD的所有BBB元素。
3. 星号 * 表示选择所有由星号之前的路径所定位的元素。
/*/*/*/BBB:选择所有的有3个祖先元素的BBB元素。
//*:选择所有元素。
4. 方块号里的表达式可以进一步的指定元素,其中数字表示元素在选择集里的位置,而last()函数则表示选择集中的最后一个元素。
/AAA/BBB[1]:选择AAA的第一个BBB子元素。
/AAA/BBB[last()]:选择AAA的最后一个BBB子元素。
5. 使用 @ 符号来选择特定的属性或特定属性的元素。
//@id:选择所有的id属性。
//BBB[@id]:选择有id属性的BBB元素。
//BBB[not(@*)]:选择没有属性的BBB元素。
6. 属性的值可以被用来作为选择的准则,normalize-space函数删除了前部和尾部的空格,并且把连续的空格串替换为一个单一的空格。
//BBB[@id='b1']:选择含有属性id且其值为'b1'的BBB元素。
//BBB[normalize-space(@name)='bbb']:选择含有属性name且其值(在用normalize-space函数去掉前后空格后)为'bbb'的BBB元素。
7. 多个路径可以用分隔符 | 合并在一起。
/AAA/EEE | //BBB:选择所有的BBB元素和作为AAA子元素的所有EEE元素。
8. 相关函数
- count():计数所选元素的个数。
- name():返回元素的名称。
- start-with():在该函数的第一个参数字符串是以第二个参数字符开始的情况返回true。
- contains():当其第一个字符串参数包含有第二个字符串参数时返回true。
- string-length:返回字符串的字符数,应用 < 替代 < ,用 > 代替 > 。
//*[count(BBB)=2]:选择含有2个BBB子元素的元素。
//*[name()='BBB']:选择所有名称为BBB的元素,等价于//BBB。
//*[starts-with(name(),'B')]:选择所有名称以"B"起始的元素。
//*[contains(name(),'C')]:选择所有名称包含"C"的元素。
//*[string-length(name()) < 3]:选择名字长度小于3的元素。
DOM4J中XPath的使用
1. 使用XPath获取指定节点
private static void getNode(Document doc) {Node node = doc.selectSingleNode("/State/City/street");System.out.println(node.getText());}
2. 使用XPath获取节点集合
private static void getNodes(Document doc) {List<Node> nodes = doc.selectNodes("/State/City");System.out.println(nodes.size());}
3. 使用XPath获取指定属性
private static void getAttribute(Document doc) {// 获取拥有Name属性的节点Node node = doc.selectSingleNode("//*[@Name]");// 获取该节点的Name属性值String name = node.valueOf("@Name");System.out.println(name);}
案例
学生信息存储
Dom4jUtils:DOM4J解析的工具类,包括获取文档对象方法和保存文件方法。
public class Dom4jUtils {/*** 获取XML数据的Document对象** @return*/public static Document getDocument(String path) {if (path == null) {return null;}// 创建XML解析器Document doc = null;SAXReader reader = new SAXReader();try {// 解析XML文件doc = reader.read(path);} catch (DocumentException e) {// 异常处理System.out.println("读取XML失败!");e.printStackTrace();}return doc;}/*** 将Document对象保存到XML文件中** @param doc 要保存的Document对象* @return*/public static boolean saveXml(Document doc, String path) {if (path == null || doc == null) {return false;}// 创建保存格式OutputFormat of = OutputFormat.createPrettyPrint();// 创建XML写入对象XMLWriter writer = null;try {// 将Document对象写入到XML文件中OutputStream os = new FileOutputStream(new File(path));writer = new XMLWriter(os, of);writer.write(doc);} catch (IOException e) {// 异常处理System.out.println("文件写入错误!");e.printStackTrace();return false;} finally {// 资源释放if (writer != null) {try {writer.close();} catch (IOException e) {System.out.println("资源关闭错误!");e.printStackTrace();return false;}}}return true;}}
config.xml:配置具体Dao的实现类名,xml数据存储路径。
<?xml version="1.0" encoding="UTF-8"?><dao><student><class>com.xml.dao.impl.StudentDaoByDom4j</class><db>src/com/xml/db/student.xml</db></student></dao>
student.xml:学生数据存储的xml文件。
<?xml version="1.0" encoding="UTF-8"?><students><student studentid="1255" classid="55"><name>帅哥</name><gender>男</gender><score>90</score></student></students>
StudentDao:DAO的接口设计
package com.xml.dao;import com.xml.bean.Student;public interface StudentDao {/*** 添加学生信息* @param s 要添加的学生对象* @return*/public boolean add(Student s);/*** 删除学生的信息* @param sid 要删除的学生id* @return*/public boolean delete(int sid);/*** 查询学生成绩* @param sid 要查询的学生id* @return*/public float getScore(int sid);}
StudentDaoFactory:DAO的获取工厂类,该类为枚举单例,通过config.xml的配置信息,提供获取具体DAO对象的公有方法。
package com.xml.dao;import org.dom4j.Document;import com.xml.util.Dom4jUtils;public enum StudentDaoFactory {dao;public StudentDao getInstance() {StudentDao sdao = null;// 获取配置信息XML文档的Document对象Document doc = Dom4jUtils.getDocument("bin/com/xml/config/config.xml");// 获取StudentDao的实现类名String className = doc.selectSingleNode("/dao/student/class").getText();// 创建StudentDao实现类try {sdao = (StudentDao) Class.forName(className).newInstance();} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {System.out.println("配置信息错误!找不到该类。");e.printStackTrace();}return sdao;}}
StudentDaoByDom4j:DAO的实现类,根据配置信息能够获取具体数据XML的位置,并对之操作。
package com.xml.dao.impl;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.Node;import com.xml.bean.Student;import com.xml.dao.StudentDao;import com.xml.util.Dom4jUtils;public class StudentDaoByDom4j implements StudentDao {private Document doc = null;private String path = null;public StudentDaoByDom4j() {// 获取配置信息XML文档的Document对象Document config = Dom4jUtils.getDocument("bin/com/xml/config/config.xml");// 获取学生信息存储路径this.path = config.selectSingleNode("/dao/student/db").getText();// 获取学生信息XML文档的Document对象this.doc = Dom4jUtils.getDocument(this.path);}@Overridepublic boolean add(Student s) {// 性别预处理String[] mask = {"男", "女", "人妖"};// 在根节点下创建学生元素并设置属性Element e = doc.getRootElement().addElement("student").addAttribute("studentid", String.valueOf(s.getId())).addAttribute("classid", String.valueOf(s.getClassId()));// 为学生元素添加子元素e.addElement("name").setText(s.getName());e.addElement("gender").setText(mask[s.getGender()]);e.addElement("score").setText(String.valueOf(s.getScore()));// 将Document保存到XML文件中Dom4jUtils.saveXml(doc, this.path);return true;}@Overridepublic boolean delete(int sid) {// 获取要删除的节点Node node = doc.selectSingleNode("/students/student[@studentid='" + String.valueOf(sid) + "']");// 使用父节点删除该节点node.getParent().remove(node);// 将Document保存到XML文件中Dom4jUtils.saveXml(doc, this.path);return true;}@Overridepublic float getScore(int sid) {// 获取要查询成绩的学生成绩String score = doc.selectSingleNode("/students/student[@studentid='"+ String.valueOf(sid) + "']/score").getText();// 返回成绩return Float.parseFloat(score);}}
测试
package com.xml.test;import org.junit.Test;import com.xml.bean.Student;import com.xml.dao.StudentDao;import com.xml.dao.StudentDaoFactory;public class StudentDaoTest {private StudentDao sdao = null;{sdao = StudentDaoFactory.dao.getInstance();}@Testpublic void testAdd() {Student s = new Student(1248, "苏苏", 55, 2, 80);sdao.add(s);}@Testpublic void testDelete() {sdao.delete(1248);}@Testpublic void testGetScore() {float score = sdao.getScore(1255);System.out.println(score);}}
DOM4J XML解析实战
本文介绍DOM4J库的基本使用方法,涵盖XML文件的读写、节点操作、XPath查询等功能,并通过具体案例展示了学生信息管理系统的设计与实现。
4245

被折叠的 条评论
为什么被折叠?



