1、XML
简单介绍一下xml文件。
可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。
什么是可扩展标记语言
- 可扩展标记语言是一种很像超文本标记语言的标记语言。
- 它的设计宗旨是传输数据,而不是显示数据。
- 它的标签没有被预定义。您需要自行定义标签。
- 它被设计为具有自我描述性。
它是W3C的推荐标准。
很多人可能会想到HTML超文本标记语言。
可扩展标记语言和超文本标记语言之间的差异
- 可扩展标记语言不是超文本标记语言的替代。
- 可扩展标记语言是对超文本标记语言的补充。
- 超文本标记语言旨在显示信息,而可扩展标记语言旨在传输信息。
- 可扩展标记语言是独立于软件和硬件的信息传输工具。
2、解析xml文件
这里简单介绍一些DOM的基本对象。
Document,Node,NodeList,Element和Attr。
- Document 对象是一棵文档树的根,可为我们提供对文档数据的最初(或最顶层)的访问入口。
- Node对象是DOM结构中最为基本的对象,代表了文档树中的一个抽象的节点。
- NodeList对象是是代表了一个包含了一个或者多个Node的列表。可以简单的把它看成一个Node的数组
- Element对象是XML文档中的标签元素,继承于Node,亦是Node的最主要的子对象。在标签中可以包含有属性,因而Element对象中有存取其属性的方法,而任何Node中定义的方法,也可以用在Element对象上面。
- Attr 对象表示 Element 对象的属性。属性的容许值通常定义在 DTD 中。
由于 Attr 对象也是一种节点,因此它继承 Node 对象的属性和方法。不过属性无法拥有父节点,同时属性也不被认为是元素的子节点,对于许多 Node 对象的属性来说都将返回 null。
2.1 DOM解析xml文件
第一步:创建一个xml文件。
<?xml version="1.0" encoding="GBK"?>
<exam>
<student examid="222" idcard="324">
<name>李四</name>
<location>上海</location>
<grade>70</grade>
</student>
<student examid="333" idcard="999">
<name>王五</name>
<location>武汉</location>
<grade>40</grade>
</student>
</exam>
第二步:生成对应的JavaBean。
(忽略命名不规范,捂脸wu)
class Student {
private String name;
private String examid;
private String idcard;
private String location;
private String grade;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getExamid() {
return examid;
}
public void setExamid(String examid) {
this.examid = examid;
}
public String getIdcard() {
return idcard;
}
public void setIdcard(String idcard) {
this.idcard = idcard;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
}
第三步:获取xml文件的Document对象
private static Document getDocument() throws ParserConfigurationException,
SAXException, IOException {
//得到创建DOM解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//得到DOM解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//得到代表整个文档的Document对象
Document document = builder.parse(new File("test.xml"));
return document;
}
第四步:基础的增、删、查操作
private static void query(String name) throws Exception {
Document document = getDocument();
NodeList list = document.getElementsByTagName("student");
for(int i = 0; i < list.getLength(); i++) {
Element element = (Element) list.item(i);
String value = element.getElementsByTagName("name").item(0).getTextContent();
if(name.equals(value)) {
System.out.println("学生姓名:" +
element.getElementsByTagName("name").item(0).getTextContent());
System.out.println("学生出生地:" +
element.getElementsByTagName("location").item(0).getTextContent());
System.out.println("学生成绩:" +
element.getElementsByTagName("grade").item(0).getTextContent());
System.out.println("学号:" +
element.getAttribute("idcard"));
System.out.println("考号:" +
element.getAttribute("examid"));
}
}
}
private static void delete(String name) throws Exception {
Document document = getDocument();
NodeList nodeList = document.getElementsByTagName("name");
for(int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if(node.getTextContent().equals(name)) {
node.getParentNode().getParentNode().removeChild(node.getParentNode());
}
}
write(document);
}
private static void add(Student student) throws Exception {
Document document = getDocument();
Element studentNode = document.createElement("student");
studentNode.setAttribute("idcard", student.getIdcard());
studentNode.setAttribute("examid", student.getExamid());
Node name = document.createElement("name");
name.setTextContent(student.getName());
Node location = document.createElement("location");
location.setTextContent(student.getLocation());
Node grade = document.createElement("grade");
grade.setTextContent(student.getGrade());
studentNode.appendChild(name);
studentNode.appendChild(location);
studentNode.appendChild(grade);
Element root = document.getDocumentElement();
root.appendChild(studentNode);
write(document);
}
为什么没有改操作啊,因为我忘记写了啊emmm。
第五步:将数据写回xml文件
private static void write(Document document) throws TransformerException {
DOMSource source = new DOMSource(document);
StreamResult rs = new StreamResult(new File("test.xml"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, rs);
}
基础的解析操作差不多完成,下面是main函数。
public static void main(String[] args) throws Exception {
System.out.println("a:添加学生信息");
System.out.println("b:删除学生信息");
System.out.println("c:查询学生信息");
System.out.print("请选择操作类型:");
String type;
Scanner in = new Scanner(System.in);
type = in.nextLine();
switch (type) {
case "a":
Student student = CreateStudent();
add(student);
break;
case "b":
System.out.print("请输入删除的学生姓名:");
String name = in.nextLine();
delete(name);
break;
case "c":
System.out.print("请输入学生的姓名:");
name = in.nextLine();
query(name);
break;
default:
break;
}
}
2.2用dom4j解析xml
第二步:获取Document对象
选取对象导包的时候,不要导入错误。
private static org.dom4j.Document getDocument() throws Exception {
SAXReader saxReader = new SAXReader();
FileInputStream in = new FileInputStream(new File("test.xml"));
Reader reader = new InputStreamReader(in, "GBK");
org.dom4j.Document document = saxReader.read(reader);
return document;
}
这里就有一点奇怪,虽然在将数据写入xml文件时,设置编码格式为GBK,打开文件发现,其编码还是ASCII,所以读取文件的时候,需要将编码格式设置为GBK,负责读取出来的中文会乱码。
第三步:基础操作
//DOM4j解析方式
private static void query(String name) throws Exception {
org.dom4j.Document document = getDocument();
// List<org.dom4j.Node> element = document.selectNodes("//student");
//
// for(int i = 0; i < element.size(); i++) {
// org.dom4j.Node node = element.get(i);
// System.out.println(node.toString());
// System.out.println(node.selectSingleNode("//name").getText());
// if(node.selectSingleNode("//name").getText().equals(name)) {
// System.out.println("学生姓名:" + node.selectSingleNode("//name").getText());
// System.out.println("学生出生地:" + node.selectSingleNode("//location").getText());
// System.out.println("学生成绩:" + node.selectSingleNode("//grade").getText());
//
// }
// }
List<org.dom4j.Node> element = document.selectNodes("//student/name");
for(int i = 0; i < element.size(); i++) {
org.dom4j.Node node = element.get(i);
if(node.getText().equals(name)) {
System.out.println("学生姓名:" + node.getParent().element("name").getText());
System.out.println("学生出生地:" + node.getParent().element("location").getText());
System.out.println("学生成绩:" + node.getParent().element("grade").getText());
}
}
}
private static void delete(String name) throws Exception {
org.dom4j.Document document = getDocument();
List<org.dom4j.Node> nodes = document.selectNodes("//name");
for(int i = 0; i < nodes.size(); i++) {
org.dom4j.Node node = nodes.get(i);
if(node.getText().equals(name)) {
node.getParent().getParent().remove(node.getParent());
}
}
write(document);
}
private static void add(Student student) throws Exception{
try {
org.dom4j.Document document = getDocument();
org.dom4j.Element rootElement = document.getRootElement();
org.dom4j.Element element = rootElement.addElement("student");
element.addAttribute("examid","123");
element.addAttribute("idcard", "456");
element.addElement("name").setText(student.getName());
element.addElement("location").setText(student.getLocation());
element.addElement("grade").setText(student.getGrade());
write(document);
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void write(org.dom4j.Document document) throws Exception {
//设置编码格式
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(new FileWriter("test.xml"), format);
writer.write(document);
writer.close();
}
private static org.dom4j.Document getDocument() throws Exception {
SAXReader saxReader = new SAXReader();
FileInputStream in = new FileInputStream(new File("test.xml"));
Reader reader = new InputStreamReader(in, "GBK");
org.dom4j.Document document = saxReader.read(reader);
return document;
}
感兴趣的朋友,可以试试我注释的那段代码进行查找,可以体会到,我是怎么被selectSingleNode()函数,玩死去活来的。想不明白,有点蛋疼。
我只是觉得这个函数的输出跟我想象的很不一样,贼不一样,很烦。
第四步:将数据写会xml文件
private static void write(org.dom4j.Document document) throws Exception {
//设置编码格式
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(new FileWriter("test.xml"), format);
writer.write(document);
writer.close();
}
3、DOM方法与dom4j比较
3.1 DOM
DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。DOM 是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。
使用DOM特别注意的一点就是:对于特别大的文档,解析和加载整个文档可能很慢且很耗资源,因此使用其他手段来处理这样的数据会更好。
3.2 dom4j
DOM4J 代表了完全独立的开发结果,但最初,它是 JDOM 的一种智能分支。它合并了许多超出基本 XML 文档表示的功能,包括集成的 XPath 支持、XML Schema 支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过 DOM4J API 和标准 DOM 接口具有并行访问功能。
DOM4J 是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用 DOM4J 来读写 XML,特别值得一提的是连 Sun 的 JAXM 也在用 DOM4J。
个人而言,我更喜欢dom4j一点。
附: jaxen包的导入是为了支持XPath,就是在方法中的 //student/name这样的,具体的我也说不清楚,情况很多,大家自行百度哈。