XML,eXtendsible markup language 可扩展的标记语言
- 可以用来保存数据
- 可以用来做配置文件
- 数据传输载体
XML解析其实就是获取元素里的字符数据或者属性数据
常用的XML解析方式
- DOM:Document Object Model,把整个xml全部读取到内存当中,形成树状结构。整个文档称为document对象,属性对应attribute对象,所有的元素节点对应element对象,文本称之为Text对象,以上所有对象称为Node节点;如果xml特别大可能会造成内存溢出;可以对文档进行增删操作
- SAX:Simple API of XML 基于事件驱动。读取一行,解析一行,不会造成内存溢出,不能对文档进行增删,只能查询
DOM方式解析XML文件
Document Object Model,把整个xml全部读取到内存当中,形成树状结构。整个文档称为document对象,属性对应attribute对象,所有的元素节点对应element对象,文本称之为Text对象,以上所有对象称为Node节点;如果xml特别大可能会造成内存溢出;可以对文档进行增删操作
创建一个stus.xml文件,并引入dom4j的jar包
stus.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<stus>
<stu>
<name>wxf</name>
<age>24</age>
</stu>
<stu>
<name>qf</name>
<age>18</age>
</stu>
</stus>
View Code
Dom解析测试类
1 public class MainTest {
2 public static void main(String[] args) {
3 try {
4 //1.创建SAXReader对象
5 SAXReader reader = new SAXReader();
6 //2.读取xml文件,获取Document对象
7 Document doc = reader.read(new File("src/stus.xml"));
8 //3.获取document对象的根元素
9 Element rootElement = doc.getRootElement();
10 System.out.println("rootElement.getName()==="+rootElement.getName());
11 System.out.println("--------------");
12 //4.获取rootElement下的所有子元素
13 List<Element> elements = rootElement.elements();
14 for (Element element : elements) {
15 System.out.println("element.getName()==="+element.getName());
16 System.out.println("name==="+element.element("name").getText());
17 System.out.println("age==="+element.element("age").getText());
18 System.out.println("--------------");
19 }
20 } catch (DocumentException e) {
21 e.printStackTrace();
22 }
23 }
24 }
View Code
console测试结果
rootElement.getName()===stus
--------------
element.getName()===stu
name===wxf
age===24
--------------
element.getName()===stu
name===qf
age===18
--------------
dom解析xml文件还可以根据XPath来处理(需要导入jaxen的jar包,否则会抛出java.lang.NoClassDefFoundError: org/jaxen/NamespaceContext)
XPath的常用语法:
如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径
如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)
星号 * 表示选择所有由星号之前的路径所定位的元素
............
XPath测试类
1 public class MainTest2 {
2 public static void main(String[] args) {
3 try {
4 //1.创建SAXReader对象
5 SAXReader reader = new SAXReader();
6 //2.读取xml文件,获取Document对象
7 Document doc = reader.read(new File("src/stus.xml"));
8 //3.根据XPath获取element元素
9 //查找指定XPath("/")路径下第一个节点
10 Node selectSingleNode = doc.selectSingleNode("/stus/stu/name");
11 System.out.println("name==="+selectSingleNode.getText());
12 System.out.println("==================");
13 //根据XPath("/")查找所有name节点
14 List<Node> selectNodes = doc.selectNodes("/stus/stu/name");
15 for (Node node : selectNodes) {
16 System.out.println("name==="+node.getText());
17 }
18 System.out.println("==================");
19 //根据XPath("//")查找所有name节点
20 List<Node> selectNodes2 = doc.selectNodes("//age");
21 for (Node node : selectNodes2) {
22 System.out.println("age==="+node.getText());
23 }
24 System.out.println("==================");
25 //根据XPath("*")查找stu下的所有子节点
26 List<Node> selectNodes3 = doc.selectNodes("/stus/stu/*");
27 for (Node node : selectNodes3) {
28 System.out.println(node.getName()+"==="+node.getText());
29 }
30 } catch (DocumentException e) {
31 e.printStackTrace();
32 }
33 }
34 }
View Code
console测试结果
name===wxf
==================
name===wxf
name===qf
==================
age===24
age===18
==================
name===wxf
age===24
name===qf
age===18
SAX解析XML方式
Java JDK自带的解析。Simple API of XML 基于事件驱动。读取一行,解析一行
优点:在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷。不需要加载进内存,因此不存在占用内存的问题,可以解析超大XML
缺点:只能用来读取XML中数据,无法进行增删改
SAX解析过程:
解析步骤:
- 创建一个SAXParserFactory对象:SAXParserFactory factory=SAXParserFactory.newInstance();
- 获得解析器 :SAXParser parser=factory.newSAXParser();
- 调用解析方法解析xml,这里的第一个参数可以传递文件、流、字符串、需要注意第二个参数(new DefaultHander)
File file=new File("girls.xml");
parser.parse(file,new DefaultHandler());
/**注解:--->这里的DefaultHandler表示
DefaultHandler类是SAX2事件处理程序的默认基类。它继承了EntityResolver、DTDHandler、
ContentHandler和ErrorHandler这四个接口。包含这四个接口的所有方法,所以我们在编写事件处理程序时,
可以不用直接实现这四个接口,而继承该类,然后重写我们需要的方法,所以在这之前我们先定义一个用于实现解析
方法如下:*/
- 创建一个MyHandler类来继承DefaultHandler并重写方法
//定一个名为MyHandler类用来继承DefaultHandler
(1)MyHandler extends DefaultHander
(2)重写方法,快速记住方法(2个开始,2个结束,1一个文字(charactor--里面的内容))
(3)2个开始:StartDocment(文档的开始)StartElement(元素的开始) 2个结束:endElement(元素的结束)
endDocment(文档的结束,标志着xml文件的结束) 1个文字内容:charactor(文字内容)
- 创建一个集合把所解析的内容添加到集合
分析:目的我们只是需要把xml里面的文字内容添加到我们的集合而不需要其他元素,所以我们需要进行判断得到
- 接步骤三 输出集合System.out.pritnln(list); 解析完成
创建一个实体类Student.java
1 package com.qf.pojo;
2
3 public class Student {
4
5 private String name;
6 private int age;
7
8 public String getName() {
9 return name;
10 }
11 public void setName(String name) {
12 this.name = name;
13 }
14 public int getAge() {
15 return age;
16 }
17 public void setAge(int age) {
18 this.age = age;
19 }
20 @Override
21 public String toString() {
22 return "Student [name=" + name + ", age=" + age + "]";
23 }
24 }
View Code
自定义一个ListHandler类继承DefaultHandler
1 package com.qf.handler;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import org.xml.sax.Attributes;
7 import org.xml.sax.SAXException;
8 import org.xml.sax.helpers.DefaultHandler;
9
10 import com.qf.pojo.Student;
11
12 public class ListHandler extends DefaultHandler {
13
14 private List<Student> stus;
15 private Student stu;
16 private String tag;
17
18
19 @Override
20 public void startDocument() throws SAXException {
21 //因为这个方法只调用一次,所以在开始的时候就可以实例化集合
22 stus = new ArrayList<>();
23 }
24 @Override
25 public void endDocument() throws SAXException {
26 super.endDocument();
27 }
28 @Override
29 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
30 //这个方法,只有当开始一个元素的时候才会调用,
31 //通过分析,当外部开始元素为student的时候,需要将student实例化
32 //将tag赋值
33 tag = qName;
34 if("stu".equals(qName)) {
35 stu = new Student();
36 }
37 }
38 @Override
39 public void endElement(String uri, String localName, String qName) throws SAXException {
40 //这句话,必须写,因为,当sax解析完一个元素的时候,会自动认为换行符是一个字符,会继续执行 character 方法 。如果不写,就会造成没有数据的现象。
41 tag = "";
42 //这个方法,当到了元素结尾的时候,会调用,应该在这里,将对象添加到集合里面去。
43 if ("stu".equals(qName)) {
44 stus.add(stu);
45 }
46 }
47 @Override
48 public void characters(char[] ch, int start, int length) throws SAXException {
49 //这里是内容,但是,无法直接判断属于哪一个元素。
50 String string = new String(ch, start, length);
51 if ("name".equals(tag)) {//判断当前内容,属于哪一个元素。
52 stu.setName(string);
53 }else if ("age".equals(tag)) {
54 stu.setAge(Integer.valueOf(string));
55 }//这两种情况,表示 当前语句执行在 stus 标签内。
56 }
57 public List<Student> getStus() {
58 return stus;
59 }
60 public void setStus(List<Student> stus) {
61 this.stus = stus;
62 }
63 public Student getStu() {
64 return stu;
65 }
66 public void setStu(Student stu) {
67 this.stu = stu;
68 }
69 }
View Code
测试类
1 package com.qf.test;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.List;
6
7 import javax.xml.parsers.ParserConfigurationException;
8 import javax.xml.parsers.SAXParser;
9 import javax.xml.parsers.SAXParserFactory;
10
11 import org.xml.sax.SAXException;
12
13 import com.qf.handler.ListHandler;
14 import com.qf.pojo.Student;
15
16 public class SAXTest {
17 public static void main(String[] args) {
18 //1.创建对象
19 SAXParserFactory newInstance = SAXParserFactory.newInstance();
20 try {
21 //2.获取解析器
22 SAXParser saxParser = newInstance.newSAXParser();
23 //3.调用方法开始解析xml
24 File file = new File("src/stus.xml");
25 ListHandler dh = new ListHandler();
26 saxParser.parse(file, dh);
27 List<Student> stus=dh.getStus();
28 //4.输出集合
29 System.out.println(stus);
30 } catch (ParserConfigurationException | SAXException e) {
31 e.printStackTrace();
32 } catch (IOException e) {
33 e.printStackTrace();
34 }
35
36 }
37 }
View Code
控制台输出
[Student [name=wxf, age=24], Student [name=qf, age=18]]