参考:java操作xml方法,总有适合你的
XML技术在Java开发中的应用
1、简介
xml: extensible Markup Language
1.1使用场景:
不同的系统之间交互时使用xml数据传输,目前主要使用json
作为框架的配置文件
存储数据
1.2XML特点:
平台无关性
90%的语言都支持xml
xml具有自我描述性,(内容自定义)
html文件中,所有元素(标签)都是官方定义好的,我们直接引用
xml文件中,所有元素自定义
1.3xml语法
文档声明<?xml version="1.0" encoding="UTF-8"?>
XML必须有根元素
xml元素(标签)有开必有合(结束标签)
xml元素对大小写敏感
xml元素必须正确的嵌套
xml元素的属性必须加引号(单引号双引号都可以)
1.4 CDATA区
处理xml文件中的特殊字符
在xml文件中写特殊符号是,报错,忽略其本性,编程普通的字符串<socre><![CDATA[成绩<60]]></socre>
<?xml version="1.0" encoding="UTF-8"?>
<!--
这是注释
定义一个xml文件,描述自己的家庭
家庭成员
每个人都有姓名职业
-->
<class>
<student duty="班长" >
<id>1</id>
<name>张三</name>
<socre><![CDATA[成绩<60]]></socre>
</student>
</class>
1.5 DTD文件
DTD: document Type Definiton
DTD的目的是帮助你编写合法的代码
DTD和xml之间的关系
类(人类)和对象(我)的关系
数据库的表和行(一条记录),dtd相当于设计表,xml相当是表中数据
下面代码的意思是根目录下有n个student元素,student元素下有name和age两个元素,其中name元素为字符串类型,age也是字符串类型
<!ELEMENT students (student*)>
<!ELEMENT student (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
在xml中引用
<?xml version="1.0" encoding="UTF-8"?>
<!-- 下面语句就是引用dtd文件 -->
<!DOCTYPE students SYSTEM "demon.dtd">
<!--
这是注释
定义一个xml文件,描述自己的家庭
家庭成员
每个人都有姓名职业
-->
<students>
<student>
<name></name>
<age></age>
</student>
</students>
1.6 xsd
xsd是xml结构定义(XML Schemas Definition)
xsd是dtd替代品,比dtd高端一些
xsd有点:
xsd的代码基于xml没有专门的语法,和xml一样的解析和处理
xsd文件支持一些列的数据类型
下面代码中
xs是命名空间的意思
maxOccurs=“unbounded” 代表相应元素的子元素没有数量限制
type=“xs:string” 代表响应元素数据类型
xs:complexType 当元素中存在多个元素时使用此类型定义
xs:sequence 排序
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="https://www.we.org/2001/xmlSchema"
targetNamespace="http://www.example.org/demon"
xmlns:tns="http://www.example.org/demon" elementFormDefault="qualified">
<xs:element name="NBA">
<xs:complexType>
<xs:sequence>
<xs:element name="star" maxOccurs="unbounded">
<xs:complexType>
<xs:element name="starname" type="xs:string" />
<xs:element name="no" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
xml引用
<?xml version="1.0" encoding="UTF-8"?><NBA
xmlns=“http://www.w3school.com.cn”
xmlns=“https://www.we.org/2001/xmlSchema”
xsi:schemaLoaction=“http://www.w3school.com.cn demon.xsd”
<star>
<starname></starname>
<no></no>
</star>
## 1.7读写操作技术总览
2、术语解释
2.1jaxp
jaxp: java API for xmlProcessing
作用:关注如何找到某个元素的内容,
详细介绍地址:https://docs.oracle.com/javase/8/docs/technotes/guides/xml/
dom:document object Model 文档对象模型
w3c: world Wide Web Consortium
sax: simple API for xml
2.2 jaxb:
扩充:json也有很多框架,例如:fastjson,gson,json-lib,jackson等
jaxb: java Architecture for xml binding
作用:关注xml与java object之间的转换
https://docs.oracle.com/javase/8/docs/technotes/guides/xml/jaxb/index.html
2.3 OXM
xom: object xml mapping 对象与xml之间的映射
3、XML解析
解析XML文件共有四种方式
DOM解析
SAX解析
JDOM解析
DOM4J解析
前两种属于基础方法,是官方提供的与平台无关的解析
后两种属于扩展方法,他们是在基础的方法上扩展出来的,只适用于JAVA平台
3.1 DOM解析
原理:解析XML的时候,把文档中的所有元素按照其出现的层次关系,在内存中构造出树形结构 生成一个Document对象
优点:元素和元素之间保留结构、关系,可以针对元素进行增删改查
缺点:内存压力较大,解析较慢
3.2 SAX
是一种XML解析的替代方法,更加高效解析。他是朱行扫描,边扫描边解析,并且以时间驱动的方式来进行解析,每解析一行都会触发一个事件
优点:不会出现内存溢出问题,可处理大文件
缺点:只能读,不能写
3.3 JDOM
仅适用具体的类,而不用接口,不灵活
3.4 DOM4J
JDOM的一种智能的分支,合并了许多超出基本XML文档的功能
著名的底层框架hibernate就是用dom4来解析
3.5 性能对比
dom4j 性能最高,其次是SAX, dom和jdom表现不好(解析10兆大小的XML文件,就内存溢出了)
解析器
DOM4J 比较简单的XML解析类库
jsoup功能欠打的DOM方式解析的类库,尤其对HTML的解析更加方便
4 XML操作(DOM4J)
4.1XML文件内容
<content>
<webSite desc="xml视频教程">https://www.baidu.com</webSite>
<desc desc="xml视频教程">Java 操作xml文件</desc>
<owner desc="xml视频教程">darly</owner>
<detail desc="xml视频教程">
<videos desc="视频列表">
<video desc="xml视频教程">
<chapter id="1">1. java操作xml相关技术概览</chapter>
<chapter id="2">2.dom读写xml</chapter>
</video>
<video id="8099" name="httpclient视频教程">
<chapter id="1">14.发送上传文件的post请求</chapter>
<chapter id="2">15.为何要绕过HTTS安全认证</chapter>
<chapter id="2">16.httpclient链接池和通用工具类封装</chapter>
</video>
</videos>
<projects>
<project>
<id>1</id>
<name>学生成绩管理</name>
</project>
<project>
<id>2</id>
<name>游戏成绩</name>
</project>
</projects>
</detail>
</content>
步骤
- 创建解析对象
- 使用解析器对象读取XML文档生产Document对象
- 根据Document对象获取XML的元素(标签)信息
DOM4j重要API说明
org.dom4j.Document常用方法
Element getRootElement(); 获取XML文档的根节点
org.dom4j.Element常用方法
- String getName(); 返回标签的名称
- List elements(); 获取子标签列表
- String atrributeValae(String name); 获取指定属性名称的属性值
- String getText(); 获取标签的文本
- String getData();获取标签文本
- String elementText(String name); 获取指定名称的子标签的文本返回子标签文本的值
- String getTextTrim(); 获取标签文本,同时去除空格
Dom4j中getText()和getStringValue()的作用和区别。
1)二者都是取得标签的文本值,但有一点不同。
eg: <books><book><title>java</title></book> <book><title>ruby</title></book></books>
document.selectSingleNode("//books").getText(); //这里输入为空;
document.selectSingleNode("//books").getStringValue();//这里输出为javaruby;
4.2 获取元素及遍历元素
package xml;
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Testxml_1 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
// 1.加载xml文件到jvm中,形成数据流
InputStream xml = Testxml_1.class.getClassLoader().getResourceAsStream("demon1.xml");
//2、创建解析对象
SAXReader sax= new SAXReader();
//3、获取文档对象(整过xml文件)[将数据流转换成一个文档对象]
Document doc = sax.read(xml);
//4. 获得根元素
Element root = doc.getRootElement();
//5.获得根元素下的所有子元素
List<Element> list = root.elements();
// 与上句作用相同,这里只是体现列表的一种定义方式,使用?代表列表元素类型根据上下文自动定义
// List<?> list=root.elements();
// System.out.println(list.size());
// list.forEach(s -> System.out.println(s)); //Lambda 表达式是一种匿名函数
//当获取元素列表时使用?(List<?>),那循环时取出元素可以定义为对象,for (Object e1:list)
//当获取元素列表时已经明确列表中元素类型(List<Element>),那循环时取出元素可以定义为相应类型(Element),for (Object e1:list)
for (Element e1:list) { //当获取元素列表时使用?,那循环时取出元素可以定义为对象,
// Element E1= (Element)e1; //只有上面获取元素使用?的方式是,需要强制转换为Element类型
System.out.println("一级元素"+e1.getName()+":"+e1.getData()); //获取元素标签名
List<Element> list2 = e1.elements();
for (Element e2: list2) {
//
//
/*
* 1、getData() 获取元素的内容(元素文本,及开始标签和结束标签之间的内容,开始标签与结束标签至少有一个换行符)
* 2、<chapter id="1">14.发送上传文件的post请求</chapter> 元素文本为 “14.发送上传文件的post请求”加一个换行符
* 3、下面projects的getData()获取的是两个换行,一个子标签代表一行(无论子标签下有多少个子孙标签)
* <projects>
* <project>
* <id>1</id>
* <name>学生成绩管理</name>
* </project>
* <project>
* <id>1</id>
* <name>学生成绩管理</name>
* </project>
* </projects>
*/
System.out.println("二级元素"+e2.getName()+":"+e2.getData());
}
}
}
}
4.3 获取元素属性
package xml;
import java.io.InputStream;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Testxml_1 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
// 1.加载xml文件到jvm中,形成数据流
InputStream xml = Testxml_1.class.getClassLoader().getResourceAsStream("demon1.xml");
//2、创建解析对象
SAXReader sax= new SAXReader();
//3、获取文档对象(整过xml文件)[将数据流转换成一个文档对象]
Document doc = sax.read(xml);
//4. 获得根元素
Element root = doc.getRootElement();
//5.获得根元素下的所有子元素
List<Element> list = root.elements();
for(Element e1:list) {
Attribute miaoshu = e1.attribute("desc");
System.out.println("属性"+e1);
System.out.println("属性"+miaoshu.getValue());
}
for(Element e1:list) {
//
System.out.println("直接获取属性"+e1.attributeValue("desc"));
}
}
}
添加元素
package xml;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class Testxml_1 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
// 1.加载xml文件到jvm中,形成数据流
InputStream xml = Testxml_1.class.getClassLoader().getResourceAsStream("demon1.xml");
//2、创建解析对象
SAXReader sax= new SAXReader();
//3、获取文档对象(整过xml文件)[将数据流转换成一个文档对象]
Document doc = sax.read(xml);
//4. 获得根元素
Element root = doc.getRootElement();
System.out.println(root.getName());
//创建元素(节点)是创建到内存中
Element detail = root.addElement("detail");
//进一步创建新建节点的子节点
Element videos=detail.addElement("videos");
Element video=videos.addElement("video");
Element chapter1=video.addElement("chapter1");
chapter1.setText("pthon基础");
Element chapter2=video.addElement("chapter2");
chapter2.setText("pthon运算");
//写入XML文件中
FileOutputStream out = new FileOutputStream(new File("F:/code.xml"));
OutputFormat format = new OutputFormat("\t",true,"utf-8");
XMLWriter XM = new XMLWriter(out,format);
//将整个文档对象写到文件中
XM.write(doc);
System.out.println("写入成功");
XM.close();
}
}
xpath
官网地址:https://zvon.org/xxl/XPathTutorial/General_chi/examples.html
- xpath:是一门在xml文档中快速查找信息的方式
- 单纯的使用dom4j访问节点时,需要一层一层的查找,
- 使用xpath访问层级的节点就简单了
- 使用xpath需要引包:jaxen-1.1-beta-7.jar(jaxen-1.1-beta-6.jar)
dom4j提供基于XPATH的API
Doceument/Element 关于XPath的API
Node selectSingleNode(String xpathExpression); 根据xpath表达式获取单个标签
List selectNodes(String xpathExpression); 根据xpath表达式获取多个标签
xml文件
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1" type="aa">
<name>a</name>
<age>11</age>
</student>
<student id="2" >
<name>b</name>
<age>22</age>
</student>
<student id="3" type="cc">
<name>c</name>
<age>33</age>
</student>
<beast id="4" >
<name>d</name>
<age>44</age>
</beast>
<beast id="5" type="ee">
<name>e</name>
<age>55</age>
</beast>
</students>
xpath示例代码
针对跟标签下得一级子标签可以用“/student”也可以直接使用“student”
package xml;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class Testxml_1 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
// 1.加载xml文件到jvm中,形成数据流
InputStream xml = Testxml_1.class.getClassLoader().getResourceAsStream("demo5xml.xml");
// 2、创建解析对象
SAXReader sax = new SAXReader();
// 3、获取文档对象(整过xml文件)[将数据流转换成一个文档对象]
Document doc = sax.read(xml);
// 4. 获得根元素
System.out.println("获得根元素");
Element students = doc.getRootElement();
System.out.println(students.getName());
System.out.println("");
System.out.println("使用根目录全文搜索获取name");
//使用根目录全文搜索获取nam
List<Element> nameList = students.selectNodes("//name");
nameList.forEach(s-> System.out.println(s));
System.out.println("");
System.out.println("使用DOCUMENT对象全文搜索获取name");
//使用DOCUMENT对象全文搜索获取name
List<Element> nameList2 = doc.selectNodes("//name");
nameList2.forEach(s-> System.out.println(s));
System.out.println("");
System.out.println("获取标签名为student的元素");
//获取标签名为student的元素
List<Element> studentList = students.selectNodes("/student");
studentList.forEach(s-> System.out.println(s));
System.out.println("获取标签名为beate的元素");
//获取标签名为beate的元素
List<Element> beastList = students.selectNodes("beast");
beastList.forEach(s-> System.out.println(s));
System.out.println("");
System.out.println("获取所有学生的名字");
//获取所有学生的名字
List<Element> namelist= students.selectNodes("student/name");
namelist.forEach(System.out::println); //lanmda表达式的另一种形式
namelist.forEach(s->System.out.println(s.getData())); //输出标签的文本
System.out.println("");
System.out.println("获取所有名字,无论层级和位置");
//获取所有名字,无论层级和位置
List<Element> namelist2= students.selectNodes("//name");
namelist2.forEach(System.out::println); //lanmda表达式的另一种形式
System.out.println("");
System.out.println("获得第一个学生的名字");
//获得第一个学生的名字
List<Element> firststudent= students.selectNodes("student[1]");
firststudent.forEach(System.out::println); //lanmda表达式的另一种形式
System.out.println("");
System.out.println("获得最后一个学生的名字");
//获得最后一个学生的名字
List<Element> laststudent= students.selectNodes("student[last()]");
laststudent.forEach(System.out::println); //lanmda表达式的另一种形式
System.out.println("");
System.out.println("获得倒数第二个学生的名字");
//获得倒数第二个学生的名字
List<Element> lastsecondstudent= students.selectNodes("student[last()-1]");
lastsecondstudent.forEach(s->System.out.println(s.getData()));
System.out.println("");
System.out.println("获得前两个学生");
//获得前两个学生
List<Element> fisestudent= students.selectNodes("student[position()<3]");
fisestudent.forEach(System.out::println); //lanmda表达式的另一种形式
System.out.println("");
System.out.println("获得前两个学生的名字");
//获得前两个学生的名字
List<Element> fisename= students.selectNodes("student[position()<3]/name");
fisename.forEach(s->System.out.println(s.getData())); //输出标签的文本
System.out.println("");
System.out.println("获得所有有属性type的学生");
//获得所有有属性type的学生
List<Element> type= students.selectNodes("student[@type]/name");
type.forEach(s->System.out.println(s.getData())); //输出标签的文本
System.out.println("");
System.out.println("获得type为cc的学生");
//获得所有有属性type的学生
List<Element> type2= students.selectNodes("student[@type='cc']/name");
type2.forEach(s->System.out.println(s.getData())); //输出标签的文本
System.out.println("");
System.out.println("获得年龄超过20岁的学生");
//获得年龄超过20岁的学生
List<Element> age= students.selectNodes("student[age>20]/name");
age.forEach(s->System.out.println(s.getData())); //输出标签的文本
}
}