文章目录
XML
1 简介
(1)XML指可扩展标记语言(eXtensible Markup Language)
(2)用途:按照树形结构存储数据
(3)标记使用语法:
空标记
<标记名 属性列表/>
非空标记
<标记名 属性列表> 标记内容 </标记名>
说明:
属性语法:属性名="属性值"
标记内容=文本+子标记
(4)文本中的特殊字符处理:
a. 实体引用
b. 字符引用
c. CDATA段: <![CDATA[ .... ]]>
(5)规范的XML文档:
a. 必须要有声明,且在第一行
b. 有且仅有一个根节点
c. 区别大小写
d. 命名不能以数字开头
XML不会做任何事情,被设计用来结构化、存储数据以及传输信息,是独立于软件和硬件的信息传输工具。XML标签没有被预定义,需要自行定义标签(可以发明自己的标签),是对HTML的补充,不会替代HTML。
下面实例是 Jani 写给 Tove 的便签,存储为 XML:
<?xml version="1.0" encoding="UTF-8"?> // 声明
<note> // 根元素(像在说:"本文档是一个便签")
<to>Tove</to> // 4 个子元素
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
XML 文档中的元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端。上面的这条便签具有自我描述性。它包含了发送者和接受者的信息,同时拥有标题以及消息主体。但是,这个 XML 文档仍然没有做任何事情。它仅仅是包装在 XML 标签中的纯粹的信息。我们需要编写软件或者程序,才能传送、接收和显示出这个文档。
(简介来自:https://www.runoob.com/xml/xml-intro.html)
2 DOM4J解析XML文档
DOM(Document Object Model 文档对象模型)定义了访问和操作文档的标准方法;
(1)简介
DOM4J是用java语言编写的专门用于XML文档操作的组件(外部类库)。
(2)下载
DOM4J的组件jar包
(3)使用
A. 把DOM4J的jar包导入到项目中
在项目根目录下,创建一个lib文件夹,将jar拷贝到lib中;
选中项目根目录,鼠标右键-properties,找到JavaBuildPath,在Libraries中使用AddJars将lib文件夹中的jar导入到项目中使用。
B. 在项目中使用DOM4J的API
a. 获得Document对象
a1. 读取XML文件,获得document对象
SAXReader reader = new SAXReader();
Document document = reader.read(new File("csdn.xml"));
a2. 解析XML形式的文本,得到document对象.
String text = "<csdn></csdn>";
Document document = DocumentHelper.parseText(text);
a3. 主动创建document对象.
Document document = DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement("csdn");
b. 将Document对象的信息写入XML文档
b1. 不设置编码,直接写入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("ot.xml"));
writer.write(document);
writer.close();
b2. 设置编码格式写入的形式.
OutputFormat format = OutputFormat.createPrettyPrint();
// 创建文件输出的时候,自动缩进的格式
format.setEncoding("UTF-8");//设置编码
XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format); writer.write(document);
writer.close();
c. 对Document对象进行操作
c1. 节点操作
//获取根节点
Element root=document.getRootElement();
//获取子节点
List<Element> list1=父节点对象.elements();//所有子节点
List<Element> list2=父节点对象.elements("子节点名称");//所有名称为XXX的子节点
Element e=父节点对象.element("子节点名称");//第一个叫XXX的子节点
//获取和设置节点的文本
节点对象.getText();
节点对象.setText("文本");
//添加CDATA段
节点对象.addCDATA(“cdata区域”);
//通过父节点,添加新节点
父节点对象.addElement("新节点名");
//通过父节点,删除某个节点
父节点对象.remove(子节点对象);
c2. 属性操作
//获取属性
Attribute a=节点对象.attribute("属性名");
List<Attribute> as=节点对象.attributes();
//获取属性的名字和值
String name=a.getName();
String value=a.getValue();
String text=a.getText();
//添加新属性
节点对象.addAttribute("属性名","属性值");
//设置已有属性的值
节点对象.addAttribute("属性名","属性值");
a.setText("文本");
//删除已有的属性
节点对象.remove(a);
其他dom4j操作相关参考:
https://www.cnblogs.com/forlina/archive/2011/06/09/2076534.html
3 XML+泛型+反射 案例
需求:学生管理系统,可以对学生信息进行增、删、修改、删除操作
目的:操作xml元素的增删改查
当使用DOM4J,还有经常用到的几种方法:
SAXReader.read(xmlSource)() - 构建XML源的DOM4J文档。
Document.getRootElement() - 得到的XML的根元素。
Element.node(index) - 获得在元素特定索引XML节点。
Element.attributes() - 获取一个元素的所有属性。
Node.valueOf(@Name) - 得到元件的给定名称的属性的值。
拓展:利用XPath应用解析xml文件。(和DOM4J是一个整体,实际上是它的一个工具,要导包)单纯使用dom访问节点时,需要一层一层的处理,如果有了XPath,定位节点变得轻松,可以根据路径表达式快速检索元素、属性。
1. Student类封装学生信息(Student.java)
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 实体类封装学生信息
*/
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String birthday;
private String gender;
private String major;
private String calssName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
// String time = sdf.format(birthday);
this.birthday = birthday;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getCalssName() {
return calssName;
}
public void setCalssName(String calssName) {
this.calssName = calssName;
}
public Student() {
// 学号自动生成,生成规则为当年年份+5位数迭代数据例如,201900001,201900002,201900003...
int year = Calendar.getInstance().get(Calendar.YEAR)*100000+(++StudentService.startTime);
this.id = year;
}
public Student(String name, String birthday, String gender, String major, String calssName) {
this();
this.name = name;
this.birthday = birthday;
this.gender = gender;
this.major = major;
this.calssName = calssName;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", birthday=" + birthday + ", gender=" + gender
+ ", major=" + major + ", calssName=" + calssName + "]";
}
}
2. xml存储数据(student.xml)
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student name="杨越帅" birthday="21" gender="男" major="计算机" calssName="201班"></student>
<student name="孔皓" birthday="24" gender="男" major="计算机" calssName="201班"></student>
<student name="李静" birthday="30" gender="女" major="计算机" calssName="201班"></student>
<student name="刘勤辉" birthday="24" gender="男" major="计算机" calssName="201班"></student>
<student name="杨生" birthday="26" gender="男" major="计算机" calssName="201班"></student>
<student name="杨生2" birthday="26" gender="男" major="计算机" calssName="201班"></student>
</students>
3. 封装操作XML文件功能方法(ReadWriteXML.java)
注意:导入dom4j的jar包
点击链接下载:dom4j-1.6.1.jar
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class ReadWriteXML {
/**
* 直接给路径获得Document
*/
public Document getDocument(String path) {
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(path);
} catch (DocumentException e) {
e.printStackTrace();
}
return document;
}
/**
* 给路径获得根元素
*/
public Element getRootElement(String path) {
if(!new File(path).exists()) {
return creatXML(null,path).getRootElement();
} else {
return getDocument(path).getRootElement();
}
}
/**
* 产生一个新的XML文件
*/
@SuppressWarnings({ "unused", "null" })
public Document creatXML(Document document, String path) {
if(document == null) {
document = DocumentHelper.createDocument();
// 创建根元素
Element root = DocumentHelper.createElement("students");
document.add(root);
}
// 创建流
OutputStream outputStream = null;
XMLWriter xmlWriter = null;
// 持久化
try {
outputStream = new FileOutputStream(path);
xmlWriter = new XMLWriter(outputStream);
xmlWriter.write(document);
xmlWriter.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(xmlWriter == null) {
xmlWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(xmlWriter == null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return document;
}
}
4. 封装操作XML的工具类(ServiceUtil.java)
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Element;
public class ServiceUtil {
ReadWriteXML readWriteXML = new ReadWriteXML();
/**
* 反射和泛型
*/
@SuppressWarnings("deprecation")
public<T> List<T> selectAll(Class<T> class1, String path) {
// 获得根目录
Element root = readWriteXML.getRootElement(path);
List<T> list = new ArrayList<>();
// 获得二级目录
List<Element> twos = root.elements();
// <student name="杨越帅" birthday="21" gender="男" major="计算机" calssName="201班"></student>
for(Element element : twos) {
// 获得所有标签的属性
List<Attribute> listAttr = element.attributes();
// 创建对象
T t;
try {
t = class1.newInstance();
for(Attribute attribute : listAttr) {
// 进行比较,对应的属性一致,给对象属性赋值
// 标签属性的名字
String attrName = attribute.getName().trim();
// 字段属性
Field fieldName;
try {
// 查找对应属性
fieldName = class1.getDeclaredField(attrName);
// 异常
if(fieldName != null) {
// 获得标签属性值
String valueSrc = attribute.getValue();
Object value = null;
// System.out.println(fieldName.getType());
// System.out.println(Integer.class);
// 判断属性的类型
if(fieldName.getType() == Integer.class) {
value = Integer.parseInt(valueSrc);
} else if (fieldName.getType() == Character.class) {
value = new Character(valueSrc.charAt(0));
} else {
value = valueSrc;
}
// 有此属性给属性赋值(调用set方法给属性赋值)
fieldName.setAccessible(true);
fieldName.set(t, value);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
list.add(t);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return list;
}
}
5. 操作学生类的类(StudentService.java)
对学生进行增 删 改 查操作:
import java.util.Iterator;
import java.util.List;
public class StudentService {
public static int startTime = 0;// 在实体类计算学号时用到
String path = "src/day10work/student.xml";
ServiceUtil serviceUtil = new ServiceUtil();
/**
* 查询所有学生信息
*/
public List<Student> selectAll() {
List<Student> list = serviceUtil.selectAll(Student.class, path);
return list;
}
/**
* 根据学生ID查询信息
*/
public void selectById(List<Student> list, Integer id) {
boolean isSelect = false;
for(Student student : list) {
if(student.getId().equals(id)) {
isSelect = true;
System.out.println(student);
}
}
if(!isSelect) {
System.out.println("查无此人~");
}
}
/**
* 根据姓名模糊查询
*/
public void selectByName(List<Student> list, String name) {
boolean isSelect = false;
for(Student student : list) {
if(student.getName().contains(name)) {
isSelect = true;
System.out.println(student);
}
}
if(!isSelect) {
System.out.println("查无此人~");
}
}
/**
* 根据ID删除学生信息
*/
public void deleteById(List<Student> list, Integer id) {
boolean isDelete = false;
Iterator<Student> it = list.iterator();
while(it.hasNext()) {
if(it.next().getId().equals(id)) {
isDelete = true;
it.remove();
System.out.println("删除成功!");
}
}
if(!isDelete) {
System.out.println("无此学号,删除失败");
}
}
/**
* 利用ID,修改学生其他信息
*/
public void update(List<Student> list, int sid, String sname, String sbirthday) {
boolean isUpdate = false;
for(Student student : list) {
System.out.println("aaa");
System.out.println(student.getId());
System.out.println(student.getId().equals(sid));
if(student.getId().equals(sid)) {
System.out.println("bb");
student.setName(sname);
student.setBirthday(sbirthday);
isUpdate = true;
System.out.println("修改成功!");
System.out.println(student);
}
}
if(!isUpdate) {
System.out.println("修改失败~");
}
}
}
6. 测试类(TestAll.java)
import java.util.List;
import java.util.Scanner;
public class TestAll {
static StudentService service = new StudentService();
static List<Student> students = service.selectAll();
private static void choose() {
System.out.println("请输入:1.查询全部 2.按学号查询 3.按姓名模糊查询 4.删除 5.修改 6.退出");
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
switch (i) {
case 1:
for(Student stu : students) {
System.out.println(stu);
}
choose();
break;
case 2:
System.out.println("请输入学号:");
Integer id = scanner.nextInt();
service.selectById(students, id);
choose();
break;
case 3:
System.out.println("请输入姓名:");
String name = scanner.next();
service.selectByName(students, name);
choose();
break;
case 4:
System.out.println("请输入要删除学生的学号:");
Integer deleid = scanner.nextInt();
service.deleteById(students, deleid);
choose();
break;
case 5:
System.out.println("请输入要修改学生的学号:");
int sid = scanner.nextInt();
System.out.println("请输入修改后的学生的信息:");
System.out.println("姓名:");
String sname = scanner.next();
System.out.println("年龄:");
String sbirthday = scanner.next();
Student stude = new Student();
service.update(students,sid,sname,sbirthday);
choose();
break;
case 6:
System.exit(0);
default:
break;
}
}
public static void main(String[] args) {
choose();
}
}