【JavaEE学习笔记】XML_概述,DOM4J解析器,Pull解析器,DOM4J增删改,xPath

来源:互联网 发布:湖南网络工程学院宿舍 编辑:程序博客网 时间:2024/06/01 18:26

XML

A.概述

1.起源

W3C万维网联盟,先定义出来的是HTML,XML推出初衷是为了替换HTML

因为HTML语法太过松散,为了规范,推出了XML语言

后来,XML语言用做配置文件,封装数据,版本只有一个v1.0

2.概念

可扩展标记语言:标签可以自定义

命名规范:不能用数字开头,不能使用纯数字,区分大小写

3.功能

a.用做配置文件

b.用做网络数据传输的载体

4.语法

新建一个文本文件,后缀名必须为.xml

5.组成部分

a.文档声明:<?xml version="1.0" encoding="utf-8"?>

encoding告诉浏览用什么编码去解析

文档声明必须在第一行,顶格

b.根标签:有且仅有一个根标签

c.其他标签:有开始标签,一定要有结束标签

d.文本:CDATA区:该区域的文本,会按照纯文本解析

格式:<![CDATA[内容]]>

<?xml version="1.0" encoding="UTF-8"?><students><student id="s001"><name>张三</name><age>23</age><tel>110</tel></student><student id="s002"><name>李四</name><age>24</age><tel>119</tel></student></students>

6.解析xml

a.DOM

将文档的各个组成部分 抽取一个对象

Element 标签对象

Attribute 属性对象

Text 文本对象

Comment 注释对象

Node 节点对象

Doucment 文档对象

解析过程:将文档一次性,加载进内存,然后将文档各个组成不封抽取为对象

优点:能够对文档进行增删改查

缺点:耗内存,适用于PC端

b.SAX

基于事件,逐行解析,一次读取一行,释放一行

优点:不占内存,适用于移动端

缺点:只能查,不能增删改

7.常用解析器

a.DOM4J:第三方jar包,实现了DOM思想


b.Pull解析器:第三方jar包,实现了SAX思想


B.DOM4J解析器

1.步骤

a.导入DOM4J jar包

b.将上一条的students.xml文件,放入工程根目录

<?xml version="1.0" encoding="UTF-8"?><students><!-- 根标签 --><student id = "s001"><!-- 子标签 --><name>张三</name><age>23</age><tel>110</tel></student><student id = "s002"><name>李四</name><age>24</age><tel>120</tel></student></students>

c.代码实现


2.获取标签对象

创建解析器对象

SAXReader reader = new SAXReader();

具体方法在代码中注释

package org.xxxx.dom4j;import java.io.FileInputStream;import java.util.Iterator;import java.util.List;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;public class DOM4JDemo {public static void main(String[] args) throws Exception {// 导入DOM4J jar包// 创建解析器对象SAXReader reader = new SAXReader();// 加载xml文件Document doc = reader.read(new FileInputStream("students.xml"));// 获取根标签对象 getRootElement();Element rootElement = doc.getRootElement();// 获取根标签下的子标签,默认获取的是第一个子标签 element();Element stuElement = rootElement.element("student");System.out.println("根标签下的子标签(默认第一个):" + stuElement.getName());System.out.println("----------获取所有子标签----------");// 1)elements();返回结果集List<Element> ele = rootElement.elements();for (Element e : ele) {System.out.println(e.getName());}// 2)迭代器获取 elementIterator();System.out.println("----------迭代器获取所有子标签----------");Iterator<Element> elementIterator = rootElement.elementIterator();while (elementIterator.hasNext()) {Element element = elementIterator.next();System.out.println(element.getName());}}}

3.获取属性对象和标签之间的文本

三种方式,代码中实现

package org.xxxx.dom4j;import java.io.FileInputStream;import java.util.Iterator;import java.util.List;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;public class DOM4JDemo {public static void main(String[] args) throws Exception {// 导入DOM4J jar包// 创建解析器对象SAXReader reader = new SAXReader();// 加载xml文件Document doc = reader.read(new FileInputStream("students.xml"));// 方式1:分布获取属性对象// 获取跟标签对象Element rootElement = doc.getRootElement();// 获取属性对象Element element = rootElement.element("student");// 获取属性id attribute("id");Attribute attribute = element.attribute("id");// 获取值String value = attribute.getValue();String name = attribute.getName();System.out.println(name + "---" + value);// 方式2:直接获取属性值System.out.println("--------------------------");String value2 = rootElement.element("student").attributeValue("id");System.out.println(value2);// 方式3:获取所有属性对象 attributes();System.out.println("------------------");List<Attribute> attributes = rootElement.element("student").attributes();for (Attribute attr : attributes) {String name2 = attr.getName();String value3 = attr.getValue();System.out.println(name2 + "---" + value3);}// 通过迭代器获取所有属性对象System.out.println("------------------");Iterator<Attribute> attributeIterator = rootElement.element("student").attributeIterator();while (attributeIterator.hasNext()) {Attribute attribute2 = attributeIterator.next();System.out.println(attribute2.getName() + "---" + attribute2.getValue());}// 获取标签之间的文本System.out.println("------------------");// 方式1:层层往下拿String text1 = doc.getRootElement().element("student").element("name").getText();System.out.println(text1);// 方式2:一步到位String text2 = doc.getRootElement().element("student").elementText("name");System.out.println(text2);}}

4.获取所有节点

a.node():获取单个节点对象;nodeIterator(); 获取多个节点对象,只能获取子节点

b.获取根标签对象 getRootElement()

c.Element()获取第一个子标签

   Elements() 获取所有的子标签 

   elememtesIterator() 获取所有子标签对象

d.attribute() 获取单个属性对象  getName()获取属性的键  getValue()获取属性的值

   attributes()获取所有的属性对象 

   attributeIterator() 获取所有的属性对象

   直接获取属性对象的值 attributeValue()

e.先获取到文本所在的标签对象 通过getText()拿出这个标签直接的文本elementText("name");

package org.xxxx.dom4j;import java.io.FileInputStream;import java.util.Iterator;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.Node;import org.dom4j.io.SAXReader;public class DOM4JDemo {public static void main(String[] args) throws Exception {// 导入DOM4J jar包// 创建解析器对象SAXReader reader = new SAXReader();// 加载xml文件Document doc = reader.read(new FileInputStream("students.xml"));// 方式1:分布获取属性对象// 获取跟标签对象Element rootElement = doc.getRootElement();// 使用递归获取所有节点getNodes(rootElement);}private static void getNodes(Element ele) {// 输出当前节点System.out.println(ele.getName());// 迭代器获取所有子节点Iterator<Node> iterator = ele.nodeIterator();// 遍历while (iterator.hasNext()) {Node nodes = iterator.next();// 判断节电是否属于标签if (nodes instanceof Element) {Element eles = (Element) nodes;// 调用递归getNodes(eles);}}}}

5.封装数据

把从xml中解析的数据封装起来

a.创建javabean存放对象

package org.xxxx.dom4j.bean;import java.io.Serializable;public class Student implements Serializable {private static final long serialVersionUID = 1L;private String id;private String name;private String age;private String tel;public Student() {super();// TODO Auto-generated constructor stub}public Student(String id, String name, String age, String tel) {super();this.id = id;this.name = name;this.age = age;this.tel = tel;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}public String getTel() {return tel;}public void setTel(String tel) {this.tel = tel;}@Overridepublic String toString() {return "Student [id=" + id + ", name=" + name + ", age=" + age + ", tel=" + tel + "]";}}

b.测试类

package org.xxxx.dom4j;import java.io.FileInputStream;import java.util.ArrayList;import java.util.Iterator;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import org.xxxx.dom4j.bean.Student;public class FZStudent {public static void main(String[] args) throws Exception {// 创建集合存储对象ArrayList<Student> list = new ArrayList<>();// 创建解析器SAXReader reader = new SAXReader();// 加载xml文件Document doc = reader.read(new FileInputStream("students.xml"));// 获取根标签对象Element rootElement = doc.getRootElement();// 获取所有的子标签对象Iterator<Element> elementIterator = rootElement.elementIterator();// 遍历取出数据并封装while (elementIterator.hasNext()) {Element element = elementIterator.next();// 直接获取属性的值String id = element.attributeValue("id");// 获取标签之间的文本String name = element.elementText("name");String age = element.elementText("age");String tel = element.elementText("tel");// 封装到对象中Student stu = new Student(id, name, age, tel);// 添加到集合中list.add(stu);}// 遍历集合for (Student s : list) {System.out.println(s.getId() + "---" + s.getName() + "---" + s.getAge() + "---" + s.getTel());}}}

C.Pull解析器

1.概述

SAX:逐行解析,读取一行,释放一行,不占内存

2.需求(序列化与反序列化)

将students.xml文件读取到内存中(反序列化),然后保存到stu.xml文件中去(序列化)

主要方法在代码中注释

注意:写入文档,标签要成对的写

serializer.startDocument("utf-8", true);       // standalone='yes' 文档是否独立

在此写根标签,子标签,都是成对写

serializer.endDocument();     // 文档结束

package org.xxxx.pull;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import org.xmlpull.v1.XmlPullParserFactory;import org.xmlpull.v1.XmlSerializer;import org.xxxx.pull.bean.Student;public class PullParseDemo {// 创建集合,存放对象private static ArrayList<Student> list;private static Student student;public static void main(String[] args) throws Exception {// 导入jar包// 获取解析器工厂对象XmlPullParserFactory factory = XmlPullParserFactory.newInstance();// 获取解析器XmlPullParser parser = factory.newPullParser();// 读取文件内容到内存中:反序列化// 加载文件// 参数1:要解析的文件 参数2:编码格式parser.setInput(new FileInputStream("students.xml"), "utf-8");// 获取事件类型// 指针默认的位置在文档开始// 从硬盘中把文件数据读取到内存中,即反序列化// 获取起始位置int type = parser.getEventType();// 一次读取,当判断条件为1,则表示读取到最后一行,结束循环// 使用XmlPullParse.END_DOCUMENT结束标记,不要直接写1while (type != XmlPullParser.END_DOCUMENT) {// 获取标签名称String tagName = parser.getName();// 判断switch (type) {case XmlPullParser.START_TAG: // 标签开始事件if ("students".equals(tagName)) {// 是根标签,创建集合list = new ArrayList<>();} else if ("student".equals(tagName)) {// 子标签,创建javabean对象student = new Student();// 获取idString id = parser.getAttributeValue(0); // 从0开始// 写入对象student.setId(id);} else if ("name".equals(tagName)) {// 获取标签之间的文本// String name = parser.getText(); 这个获取不到,注意String name = parser.nextText();// 写入对象student.setName(name);} else if ("age".equals(tagName)) {// 获取年龄String age = parser.nextText();student.setAge(age);} else if ("tel".equals(tagName)) {String tel = parser.nextText();student.setTel(tel);}break;case XmlPullParser.END_TAG: // 结束标签时间if ("student".equals(tagName)) {list.add(student);}break;}type = parser.next(); // 让指针下移,获取新的事件类型,并重新赋值,防止死循环}// 遍历集合,查看是否读取完毕for (Student stu : list) {System.out.println(stu.getId() + "---" + stu.getName() + "---" + stu.getAge() + "---" + stu.getTel());}System.out.println("--------------------------------");// 接下来,开始存储数据到stu.xml文件中,也就是序列化// 抽取一个方法SavaDataToXML(factory);}private static void SavaDataToXML(XmlPullParserFactory factory) throws XmlPullParserException, IllegalArgumentException, IllegalStateException, FileNotFoundException, IOException {// 获取序列化器XmlSerializer serializer = factory.newSerializer();// 设置输出流关联文件serializer.setOutput(new FileOutputStream("stu.xml"), "utf-8");// 写入文档声明// 参数1:编码    参数2:文档是否独立// 文档开始,也要有文档结束,成对去写serializer.startDocument("utf-8", true);// standalone='yes' 文档是否独立// 写入根标签// 参数1 命名空间,一般给null   参数2 标签名称serializer.startTag(null, "students");// 写入开始标签// 遍历集合,写子标签for (Student stu : list) {// 写入student标签serializer.startTag(null, "student");// 写入id属性 参数1 命名空间   参数2 属性名 参数3 属性值serializer.attribute(null, "id", stu.getId());// 写入name标签serializer.startTag(null, "name");// 写入文本nameserializer.text(stu.getName());serializer.endTag(null, "name");// 写入age标签serializer.startTag(null, "age");// 写入文本ageserializer.text(stu.getAge());serializer.endTag(null, "age");// 写入tel标签serializer.startTag(null, "tel");// 写入文本telserializer.text(stu.getTel());serializer.endTag(null, "tel");// studeng结束标签serializer.endTag(null, "student");}serializer.endTag(null, "students");// 写入结束标签serializer.endDocument();// 文档结束}}

运行完毕,刷新工程,查看stu.xml文件




D.DOM4J解析实现增删改

1.修改删除

a.先读取到内存中,进行修改

主要方法

setText();就是设置文本

detach();删除标签

b.重新写入硬盘覆盖掉源文件

XMLWriter 类

c.代码实现

修改以下xml文件

<?xml version="1.0" encoding="UTF-8"?><students>  <student id="s001">    <name>张三</name>    <gender>男</gender>  </student>  <student id="s002">    <name>李四</name>    <gender>女</gender>  </student></students>
修改张三的姓名为王五,性别为空

删除id="002"的属性

package org.xxxx.xml;import java.io.FileInputStream;import java.io.FileOutputStream;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 Demo01 {public static void main(String[] args) throws Exception {// 读取xml文件SAXReader reader = new SAXReader();Document doc = reader.read(new FileInputStream("students.xml"));// 修改文本// 第一个标签,直接获取doc.getRootElement().element("student").element("name").setText("王五");doc.getRootElement().element("student").element("gender").setText("");// 删除属性// 获取根标签Element rootElement = doc.getRootElement();// 获取属性集List<Element> elements = rootElement.elements();// 遍历for (Element ele : elements) {// 获取属性String value = ele.attributeValue("id");if (value.equals("s002")) {ele.attribute("id").detach();}}// 重新写入硬盘XMLWriter writer = new XMLWriter(new FileOutputStream("students.xml"));writer.write(doc);writer.close();}}

2.增加属性

添加标签:用文档帮助类DocumentHelper,创建一个文档,最后记得XMLWriter 写到硬盘

添加标签:addElement("标签名");

添加属性:addAtrriburte("属性","属性值")

添加文本:addText("文本");

package org.xxxx.xml;import java.io.FileOutputStream;import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.XMLWriter;public class Demo02 {public static void main(String[] args) throws Exception {// 用代码写一个xml// 文档帮助类写一个声明Document doc = DocumentHelper.createDocument();// 添加一个根标签Element rootEle = doc.addElement("students");// 添加一个子标签// 根标签的子标签,用根标签调,后面同理Element stuELe = rootEle.addElement("student");// 添加属性stuELe.addAttribute("id", "s001");// 添加名字标签Element name = stuELe.addElement("name");// 添加名字name.addText("张三");// 添加年龄Element age = stuELe.addElement("age");age.addText("20");// 添加电话Element tel = stuELe.addElement("tel");tel.addText("110");// 写到硬盘上XMLWriter writer = new XMLWriter(new FileOutputStream("mydoc.xml"));writer.write(doc);writer.close();}}
运行程序,刷新工程


E.xPath

1.概述

路径规则书写的一门技术,它的作用是用来快速找到

XML文档中一个或多个标签,不需要一层一层标签去获取

直接通过标签的特征检索

2.步骤

a.导入DOM4J jar包和支持xPath技术的jar包


b.定义path语句

比如寻找id="s002"的student标签

String path = "//student[@id='s002']";

寻找name为王五的人标签

String path = "//name[text()='王五']";

c.配合xPath找到单个节点对象

Element selectSingleNode = (Element) doc.selectSingleNode(path);System.out.println(selectSingleNode.getName());

d.找到根标签下的所有标签 selectNodes(path);配合xPath 找到多个节点

String path = "//student";List<Node> selectNodes = doc.selectNodes(path);for (Node node : selectNodes) {System.out.println(node.getName());}

3.还有很多方法,可以查阅官方文档