《java世界观》文集说明
- 本文集记载的所有内容均是java的学习笔记,主要重点记录概念,可能不会为每个概念列举完整的代码例子,更多代码例子请移步《java种田记》文集
- 本文主要涉及内容来自开课吧新职课-JavaEE开发工程师V2.0
- 若有错漏之处,欢迎各位指正
XML简介
XML,可扩展标记语言(eXtensible Markup Language),主要用于网络数据传输,数据存储,及配置文件等。
这里简单介绍一下XML的基础语法:
- XML文档声明 <?xml version="1.0" encoding="UTF-8"?>
- XML文档由一对对标记组成
- 属性可以在开始标记中被描述,属性以 键="值" 的方式存储,多个属性之间由空格分割
- XML文档中必须有且只有一个根标记
- 标记可以嵌套,但不允许交叉
以下是一个例子
<?xml version="1.0" encoding="UTF-8"?>
<drinks>
<drink id="1">
<name>寒天爱玉</name>
<ice>少冰</ice>
<sugar>少糖</sugar>
<addons>
<addon>奶盖</addon>
<addon>椰果</addon>
</addons>
</drink>
<drink id="2">
<name>奶盖乌龙</name>
<ice>去冰</ice>
<sugar>七分糖</sugar>
<addons>
<addon>珍珠</addon>
<addon>椰果</addon>
</addons>
</drink>
</drinks>
XML的解析方式
SAX解析
SAX, Simple API for XML
- 事件驱动的解析机制
- SAX解析器会逐行阅读,当读取到一个标记的开始、属性、内容、结束时触发事件
- 需要编写事件触发的相应处理程序
优点
- 无需等待数据全部加载完毕,立即开始分析
- 逐行加载,节省内存
- 不必解析整个文档,可以在满足某个条件时停止解析
缺点
- 单向解析,无法对之前的数据再进行操作
- 逐行解析无法得知复杂的元素的层次,只能维护父子关系的节点
- 只读解析,无法修改内容
DOM解析
DOM,文档对象模型(Document Object Model),是w3c官方制定的用以处理XML文档的标准编程接口。DOM将XML文档解析成树状结构,程序员可以通过操作此文档树来获取、修改、删除数据。
优点
- 文档被加载至内存,允许对数据和结构进行更改
- 支持双向解析数据
缺点
- 文档全部被加载至内存中,消耗资源大
Java中的DOM解析
对比SAX解析和DOM解析,后者的缺点可以忽略不计,因此主要使用DOM解析的方式处理XML文档
JDOM
如上文所说,DOM解析本身是面向所有平台的接口,DOM提供给Java的接口也只是达到了能够实现的最低通用标准,并没有特地考虑到Java的特性并作出相应的优化设计,因此Java程序员直接使用DOM的接口则会感觉到不便。
JDOM则是为了解决这一问题,由Brett McLaughlin和Jason Hunter开发出来的开源项目,该项目致力于提供完善方便的用Java解析XML的解决方案。
优点
- 实现了许多工具类,比起直接使用DOM的API,简便了XML的解析过程
- 加入了大量java集合,方便java程序员进行开发
缺点
- 不是面向接口设计,没有较好的灵活性
- 优化并不是很好,性能没有那么优异
DOM4J
DOM4J也是为Java设计的用于解析XML的开源API(Application Programming Interface,应用程序接口)
和JDOM相比,DOM4J的性能更为优异,功能更加强大,使用更加便捷,因此也更为常用
代码实现步骤
- 下载并引入
dom4j.jar
- 创建XML读取工具对象
SAXReader sr = new SAXReader();
- 通过XML读取工具对象读取文档对象(加载到内存的整个XML文档)
Document doc = sr.read(<文档对象>);
,这里read(<文档对象>)
方法可以接收输入流,也可以直接接收文件或URL - 通过文档对象获得根元素对象再进行后续操作
Element root = doc.getRootElement();
元素对象 Element 常用操作
- 获取节点名称
String getName();
- 获取节点内容
String getText();
- 设置节点内容
void setText(String text);
- 根据子节点的名称,获取匹配到的第一个子节点对象
Element element(String name)
- 获取所有的子节点对象
List<Element> elements();
- 获取节点的属性值
String attributeValue(String attributeName);
- 获取子节点的内容
String elementText(String childName);
- 添加子节点
Element addElement(String s)
- 添加属性
Element addAttribute(String name, String value);
示例
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
/**
* @author 蜗先生
* @date 2020/9/22
*/
public class Main {
public static void main(String[] args) throws DocumentException {
// 创建XML读取工具对象,并获取文档对象,文档内容在文章开头
Document doc = new SAXReader().read(new File("drinks.xml"));
// 获取根元素
Element root = doc.getRootElement();
// 解析示例
// 打印根元素名称
System.out.println(root.getName());
// 打印所有元素信息
List<Element> elements = root.elements();
for (Element drink : elements) {
System.out.println(drink.attributeValue("id"));
System.out.println(drink.elementText("name"));
System.out.println(drink.elementText("ice"));
System.out.println(drink.elementText("sugar"));
List<Element> addons = drink.element("addons").elements();
for (Element addon : addons) {
System.out.println(addon.getText());
}
}
}
}
运行结果
drinks
1
寒天爱玉
少冰
少糖
奶盖
椰果
2
奶盖乌龙
去冰
七分糖
珍珠
椰果
Process finished with exit code 0
XPATH 路径表达式
XPath是一种用来确定XML文档中某部分位置的语言,它可以便捷的查询元素,dom4j中也提供了对XPath的支持
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从当前节点选取所有后代节点。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
@ 属性使用方式:
- [@attributeName='value']
- [@attributeName>'value']
- [@attributeName<'value']
- [@attributeName!='value']
DOM4J中的XPATH使用方式:
- 需要导入
jaxen.jar
-
Element element = (Element) document.selectSignleNode(<XPath路径表达式>);
或Node node = document.selectSignleNode(<XPath路径表达式>);
List<Element> elements = document.selectNodes(<XPath路径表达式>);
注:
Node selectSingleNode(String var1);
和 List selecNodes(String var1);
均为接口org.dom4j.Node
的方法,而org.dom4j.Document
和org.dom4j.Element
均继承了此接口(当然,此接口被许多其他类实现),此接口内的方法还包括前文提到的void setText(String var1)
、String getText()
等
更多内容建议查阅API文档(github来源 第三方来源)或直接阅读源码
代码示例
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
/**
* @author 蜗先生
* @date 2020/9/22
*/
public class Main {
public static void main(String[] args) throws DocumentException {
// 创建XML读取工具对象,并获取文档对象,文档内容在文章开头
Document doc = new SAXReader().read(new File("drinks.xml"));
// XPath解析示例
// 查找所有addon元素并打印信息
List<Element> addons = doc.selectNodes("//addon");
for (Element addon : addons) {
System.out.println(addon.getText());
}
System.out.println("--------------------");
// 查找id为2的饮料的addon元素并打印信息
addons = doc.selectNodes("//drink[@id='2']//addon");
for (Element addon : addons) {
System.out.println(addon.getText());
}
}
}
运行结果
奶盖
椰果
珍珠
椰果
--------------------
珍珠
椰果
Process finished with exit code 0
生成/修改XML
- 获取现有文档对象(见上文),或创建空文档对象
Document doc = DocumentHelper.createDocument();
- 添加或修改节点或内容(见上文)
- 创建储存新文档的文件输出流
FileOutputStream fos = new FileOutputStream(<filePath>);
- 将文件输出流转换成XML文档输出流
XMLWrite xw = new XMLWriter(fos);
- 写出文档
xw.write(doc);
- 释放资源
xw.close(); fos.close();
代码示例
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author 蜗先生
* @date 2020/9/22
*/
public class Main {
public static void main(String[] args) throws DocumentException, IOException {
// 创建XML读取工具对象,并获取文档对象,文档内容在文章开头
Document doc = new SAXReader().read(new File("drinks.xml"));
// 修改文档
// 给id为1的饮料添加addon珍珠
Element element = (Element) doc.selectSingleNode("//drink[@id=1]//addons");
element.addElement("addon").setText("珍珠");
// 添加id为3的饮料及相应信息
element = doc.getRootElement();
Element drink = element.addElement("drink");
drink.addAttribute("id", "3");
drink.addElement("name").setText("红枣桂圆");
drink.addElement("ice").setText("热饮");
drink.addElement("sugar").setText("正常");
Element addons = drink.addElement("addons");
// 以下配料纯属举例,请不要轻易尝试黑暗料理
addons.addElement("addon").setText("椰果");
addons.addElement("addon").setText("小芋圆");
// 修改完毕,写出文档并关闭资源
FileWriter fileWriter = new FileWriter("drinks2.xml");
XMLWriter xmlWriter = new XMLWriter(fileWriter);
xmlWriter.write(doc);
xmlWriter.close();
fileWriter.close();
}
}
生成的drinks2.xml
文件内容
*由于直接生成的内容挤在一行不便阅读,以下内容进行过美化格式处理
<?xml version="1.0" encoding="UTF-8"?>
<drinks>
<drink id="1">
<name>寒天爱玉</name>
<ice>少冰</ice>
<sugar>少糖</sugar>
<addons>
<addon>奶盖</addon>
<addon>椰果</addon>
<addon>珍珠</addon>
</addons>
</drink>
<drink id="2">
<name>奶盖乌龙</name>
<ice>去冰</ice>
<sugar>七分糖</sugar>
<addons>
<addon>珍珠</addon>
<addon>椰果</addon>
</addons>
</drink>
<drink id="3">
<name>红枣桂圆</name>
<ice>热饮</ice>
<sugar>正常</sugar>
<addons>
<addon>椰果</addon>
<addon>小芋圆</addon>
</addons>
</drink>
</drinks>