XML解析的三种方式(dom,sax,dom4j)

时间:2023-02-26 20:29:03

1.Dom解析:

要解析的xml文件内容:

<?xml version="1.0" encoding="utf-8" standalone="no"?><class>
<stu id="1">
<name>小灰灰</name>
<age>23</age>
<insto>好学生</insto>
</stu>
<stu id="2" sex="女">
<name>小红</name>
<age>20</age>
<insto>学生</insto>
</stu>
<stu>
<name>小晖</name>
<age>20</age>
<insto>三好学生</insto>
</stu>
</class>

java解析代码:

package com.huihui.dom;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

//使用DOM技术对xml文件进行crud操作
public class DomXml1 {

public static void main(String[] args) throws Exception {
// 创建一个DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 通过DocumentBuilderFactory得到一个DocumentBuilder对象
DocumentBuilder dBuilder = dbf.newDocumentBuilder();
// 指定解析哪个xml文件
Document document = dBuilder.parse("src/myclass.xml");
// System.out.println(document);
// 遍历该xml文件
//list(document);

//read(document);

//add(document);

//delete(document);

//update(document);

System.out.println("OK");
}

// 更新xml文件
private static void updateXML(Document doc)
throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException {
// 得到TransformerFactory对象
TransformerFactory tff = TransformerFactory.newInstance();
// 通过TransformerFactory得到一个转化器
Transformer tf = tff.newTransformer();
// 将doc的整个在内存中的节点树写出到外部的文件中
tf.transform(new DOMSource(doc), new StreamResult("src/myclass.xml"));
}

// 遍历xml节点(也就是遍历树)
public static void list(Node node) {

// 如果该节点类型是node节点(而不是文本节点)
if (node.getNodeType() == node.ELEMENT_NODE) {
System.out.println("名字:" + node.getNodeName());
}

// 取出node的子节点
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
// 取出节点
Node n = nodeList.item(i);
// 运用递归,再去显示(节点的子节点)
list(n);
}
}

// 具体查询某个学生的信息(显示第一个学生的所有信息)
public static void read(Document doc) {
NodeList nl = doc.getElementsByTagName("stu");// 在document的级别层级上往下获取元素
// 取出第一个学生
Element stu = (Element) nl.item(0);
Element name = (Element) stu.getElementsByTagName("name").item(0);
System.out.println("学生的姓名是:" + name.getTextContent());// 取出name的值
System.out.println("学生的性别是:" + stu.getAttribute("sex"));// 取出stu的属性值
}

// 添加一个stu到xml文件中去
public static void add(Document doc) throws Exception {
// 创建一个新的学生节点
Element newstu = doc.createElement("stu");
Element newstu_name = doc.createElement("name");
newstu_name.setTextContent("小晖");
Element newstu_age = doc.createElement("age");
newstu_age.setTextContent("20");
Element newstu_insto = doc.createElement("insto");
newstu_insto.setTextContent("三好学生");

newstu.appendChild(newstu_name);
newstu.appendChild(newstu_age);
newstu.appendChild(newstu_insto);

// 把新的学生节点添加到根元素下(虽然这也添加进取了,但是查看xml文件,会发现xml文件没有任何的变化,原因是现在的整个document是解析xml文件出来的、在内存中的。所以你只是改变的是内存中的内容,并没有对文件本身产生影响)
doc.getDocumentElement().appendChild(newstu);

// 更新xml文件
updateXML(doc);

}

// 删除一个节点或者一个节点的属性(删除第一个学生或者第一个学生的性别属性)
public static void delete(Document doc) throws Exception {
// 删除第一个学生
// Node node = doc.getElementsByTagName("stu").item(0);
// node.getParentNode().removeChild(node);//获取到该节点的父节点后,从父节点中删除这个元素(也只是在内存的dom树中进行了删除,并不会影响xml文件的内容)

// 删除第一个学生的sex属性
Element node = (Element) doc.getElementsByTagName("stu").item(0);
node.removeAttribute("sex");

// 更新xml文件
updateXML(doc);

}

// 更新节点的内容(把第一个学生的名字改成小灰灰)
public static void update(Document doc) throws Exception {
Element node = (Element) doc.getElementsByTagName("stu").item(0);
Element node_name = (Element) node.getElementsByTagName("name").item(0);
node_name.setTextContent("小灰灰");

// 更新xml文件
updateXML(doc);
}

}

2.SAX解析:

要解析的xml文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<class>
<stu id="1" sex="男">
<name>小灰灰</name>
<age>23</age>
<insto>好学生</insto>
</stu>
<stu id="2" sex="女">
<name>小红</name>
<age>20</age>
<insto>学生</insto>
</stu>
<stu>
<name>小晖</name>
<age>20</age>
<insto>三好学生</insto>
</stu>
</class>

java解析代码:

package com.huihui.sax;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SaxXml1 {

// 使用sax技术解析XML文件
public static void main(String[] args) throws Exception {
// 1.使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
// 2.通过SAX解析工厂得到解析器对象
SAXParser saxParser = spf.newSAXParser();
// 3.解析器将解析对象和事件处理对象关联
saxParser.parse("src/myclass2.xml", new MyDefaultHandler1());

}

}

// 定义第二个事件处理类(如何只显示stu的name和age)
class MyDefaultHandler1 extends DefaultHandler {
private boolean isName = false;
private boolean isAge = false;

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String con = new String(ch, start, length);
if(!"".equals(con.trim())&&(isName||isAge)){
System.out.println(con);
}
isName = false;
isAge = false;
}

@Override
public void endDocument() throws SAXException {
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}

@Override
public void startDocument() throws SAXException {
}

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if("name".equals(qName)){
isName = true;
}else if("age".equals(qName)){
isAge = true;
}
}

}

// 定义事件处理类(显示stu的所有信息)
class MyDefaultHandler extends DefaultHandler {

@Override
// 发现文档开始
public void startDocument() throws SAXException {
System.out.println("startDocument()方法");
}

@Override
// 发现xml文件中的一个元素
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("属性名称:" + qName);
}

@Override
// 发现xml文件中的文本
public void characters(char[] ch, int start, int length) throws SAXException {
String con = new String(ch, start, length);
// 显示文本内容
if (!con.trim().equals("")) {
System.out.println(con);
}
}

@Override
// 发现xml文件中的一个元素结束
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}

@Override
// 发现文档结束
public void endDocument() throws SAXException {
System.out.println("endDocument()方法");
}

}

3.DOM4J解析:

要解析的xml文件内容:

<?xml version="1.0" encoding="utf-8"?>

<class>
<student>
<name myname="xiaohong">小红</name>
<sex>girl</sex>
<age>15</age>
</student>
<student>
<name myname="xiaoming">小明</name>
<sex>boy</sex>
<age>13</age>
</student>
</class>

java解析代码:

package com.huihui.dom4j;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

//使用Dom4j对xml文件进行crud操作
public class MyDom4jTest1 {

public static void main(String[] args) throws Exception {
// 得到解析器
SAXReader saxReader = new SAXReader();
// 指定解析哪个xml文件
Document document = saxReader.read(new File("src/class.xml"));

// 获取xml文件的根元素
Element root = document.getRootElement();
// list(root);

// read(document);

// add(document);

//delete(document);

//update(document);

addByIndex(document);

}




// 遍历xml文件
public static void list(Element element) {

System.out.println(element.getName());// 打印元素名称
System.out.println(element.getTextTrim());// 打印元素中的文本内容

Iterator iterator = element.elementIterator();

while (iterator.hasNext()) {
Element e = (Element) iterator.next();
// 递归
list(e);
}
}

// 指定读取某个元素(eg:读取第一个学生的信息)
public static void read(Document document) {

Element root = document.getRootElement();// 获取根元素
// root.element("student"):表示取出root元素下的一个student元素
// root.elements("student"):表示取出根元素下的所有student元素
// root.elements("student").get(0):表示取出根元素下的第一个student元素
Element e = (Element) root.elements("student").get(1);
// 取出元素下的内容值
System.out.println(e.element("name").getText());
// 取出元素中的属性值
System.out.println(e.element("name").attributeValue("myname"));

/**
* 测试能否跨层去取出元素 测试结果:IndexOutOfBoundsException 结果:不能跨层取出元素,除非使用xPath技术
*/

// Element e1 = (Element) root.elements("name").get(0);

// 从正常的数据中取出后

}

// 添加元素(eg:添加一个student元素到xml文件中去)
public static void add(Document document) throws Exception {
// 创建一个student元素对象
Element newStu = DocumentHelper.createElement("student");
Element newStu_name = DocumentHelper.createElement("name");
newStu_name.addAttribute("myname", "xiaofang");// 给元素添加属性
newStu_name.setText("小芳");// 给元素添加内容
Element newStu_sex = DocumentHelper.createElement("sex");
Element newStu_age = DocumentHelper.createElement("age");
// 把三个子元素挂载到newStu下
newStu.add(newStu_name);
newStu.add(newStu_sex);
newStu.add(newStu_age);
// 再把newStu元素加到根元素下
document.getRootElement().add(newStu);

// 把xml文件更新一下

updateXML(document);
}


// 删除元素(eg:删除第一个student元素)
public static void delete(Document document) throws Exception {
// 找到第一个student元素
Element e = (Element) document.getRootElement().elements("student").get(0);
// 删除找到的student元素
// e.getParent().remove(e);

// 删除某元素的某个属性(删除name元素的myname属性)
Element e_name = (Element) e.elements("name").get(0);
e_name.remove(e_name.attribute("myname"));

updateXML(document);
}

// 更新元素(eg:把所有student元素的age都加3)
public static void update(Document document) throws Exception {
// 得到所有student的age
List<Element> elements = document.getRootElement().elements("student");
for (Element e1 : elements) {
// 从student中取出age元素
Element age = e1.element("age");
age.setText(Integer.parseInt(age.getText()) + 3 + "");//修改age元素的内容文本

//从student中取出name元素
Element name = e1.element("name");
name.addAttribute("myname", "haha");//修改name元素的myname属性

}

updateXML(document);

}

//添加一个元素到指定的位置(添加一个student,在每个name为小红的student元素之后,在小明之前)
public static void addByIndex(Document document) throws Exception{
//创建一个student元素
Element newStu = DocumentHelper.createElement("student");
Element newStu_name = DocumentHelper.createElement("name");
newStu_name.setText("小华");
Element newStu_sex = DocumentHelper.createElement("sex");
newStu_sex.setText("男");
Element newStu_age = DocumentHelper.createElement("age");
newStu_age.setText("30");
//将name,sex,age元素挂载到student元素下面
newStu.add(newStu_name);
newStu.add(newStu_sex);
newStu.add(newStu_age);


//得到所有student元素的List(循环遍历的目的是如果有多个name是小红的student元素,那么就要在每个name为小红的student元素之后添加新的student元素)
List<Element> elements = document.getRootElement().elements("student");
for (int i = 0; i < elements.size(); i++) {
//取出各个student的name元素
Element name = elements.get(i).element("name");
if("小红".equals(name.getText())){
elements.add(i+1,newStu);//在位置1(也就是xml文档中的第二个位置)添加元素
}
}

//更新xml文档
updateXML(document);
}

//更新xml文档
private static void updateXML(Document document)
throws UnsupportedEncodingException, FileNotFoundException, IOException {
// 如果元素名称为中文,直接输出就会出现中文乱码问题,使用OutputFormat解决中文乱码的问题
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(new File("src/class.xml")), format);

xmlWriter.write(document);
xmlWriter.close();
}


}

DOM4J补充说明:

XPath:

为什么使用XPath?
1.为了我们更方便的访问某个节点,我们可以使用xpath技术,当使用xpath之后,就可以非常方便的读取到指定的节点了(可以跨层取出元素).
2.xpath往往是结合DOM4J搭配一起使用
3.注意:要引入jaxen-1.1-beta-6.jar包

Dom4j结合xpath一起使用的案例:
要解析的xml文件:

<?xml version="1.0" encoding="utf-8"?>

<class>
<student>
<name myname="xiaohong">小红</name>
<sex>girl</sex>
<age>15</age>
</student>
<student>
<name myname="xiaoming">小明</name>
<sex>boy</sex>
<age>13</age>
</student>
</class>

java解析代码:

package com.huihui.dom4j;

import java.io.File;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

//dom4j配合xpath使用的案例
public class Dom4jAndXpath {
public static void main(String[] args) {

try {
//1.得到SAXReader解析器
SAXReader saxReader = new SAXReader();
//2.指定要解析的xml文件
Document document = saxReader.read(new File("src/class.xml"));
//3.可以随心所欲的读取xml文件了

//基本的XPath语法类似于在一个文件系统中定位文件,如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径
// List<Element> list = document.selectNodes("/class/student/sex");//取出class元素下边的student元素下的所有的sex元素
// for (int i = 0; i < list.size(); i++) {
// String text = list.get(i).getText();
// System.out.println("所有的sex元素的内容:"+text);
// }

//如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)
// List<Element> list = document.selectNodes("//student");
// System.out.println(list.size());

//星号 * 表示选择所有由星号之前的路径所定位的元素
List<Element> list = document.selectNodes("/class/student/*");
System.out.println(list.size());

} catch (Exception e) {
e.printStackTrace();
}

}

}

xpath的一些相关内容的说明:
1.基本的XPath语法类似于在一个文件系统中定位文件,如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径
2.如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)
3.星号 * 表示选择所有由星号之前的路径所定位的元素
4.方块号里的表达式可以进一步的指定元素, 其中数字表示元素在选择集里的位置, 而last()函数则表示选择集中的最后一个元素.