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; } @Override public 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结束标记,不要直接写1 while (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(); // 获取id String 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"); // 写入文本name serializer.text(stu.getName()); serializer.endTag(null, "name"); // 写入age标签 serializer.startTag(null, "age"); // 写入文本age serializer.text(stu.getAge()); serializer.endTag(null, "age"); // 写入tel标签 serializer.startTag(null, "tel"); // 写入文本tel serializer.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.还有很多方法,可以查阅官方文档