使用jdk DOM,SAX和第三方jar包DOM4J创建,解析xml文件

1. 什么是xml文件

1.1 什么是xml文件

可标记的扩展语言(文本文件) 类似html文件,xml标签有头有尾部。可读性高。
xml的实际用途:
1.数据存储和传递的媒介
2.作为配置文件

  • XML中的相关概念(叫法)
  • 按级别来分
    a:根节点(有且只能有一个)
    b:父节点
    c:子节点
    d:兄弟节点
  • 按类型来分
    a:元素节点
    b:属性节点
    c:文本节点
  • 如下就是一个xml文件

1.2 解析xml的方式,优缺点

  • 使用Java操作xml文件,有DOM和SAX
  • 优缺点比较

DOM的特点:

  1. 在操作xml文档时需要将整个文档加载到内存,操作灵活方便,但对内存消耗过大
  2. 功能齐全,能创建/解析xml文档,能删除/添加/修改节点信息
    SAX的特点:(事件驱动模式)
  3. 在操作xml文档时是从上到下来加载xml,操作没有dom那么灵活,但内存消耗较dom要小
  4. 功能没有dom齐全,只能创建/解析xml

dom4j:

  1. 集dom和sax的特点于一起
  2. 功能更强大

2. 使用dom操作xml文件

2.1 使用dom创建xml文件

  • 下面创建了person.xml 和 stu.xml
  • 直接用排版印刷怼 和 封装好排版和印刷
package test;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
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.NodeList;

/**
 * 
 * @author echo lovely
 * 
 * dom模式下的
 * 		xml文件的解析,读取,增删改
 * 
 * 		优缺点:
 * 			1. 消耗内存大,把整个xml读到内存,适合数据少的读取
 * 			2. 灵活,可对整个xml文档进行操作,操作父子,兄弟,第一个,最后一个结点
 * 
 * 		排版:
 * 			DocumentBuliderFactory BuilderFactory Document
 * 
 * 		印刷:
 * 			TransformerFactory Transformer transfome
 *  */
public class DocumentXMLNode {

	public static void main(String[] args) throws Exception {
		// createNew();
		// parserXML();
		// DOMAddXML();
		// DOMUpdateXML();
		DOMDeleteXML();
	}
	
	// one by one
	static void createXML() throws Exception {
		// 创建一个排版工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();	
		
		// 创建一个排版机器
		DocumentBuilder db = factory.newDocumentBuilder();
		// 准备好空白文档,准备排版
		Document doc = db.newDocument();
		
		// 创建根节点
		Element root = doc.createElement("Student");
		
		// 把根结点挂载到文档中
		doc.appendChild(root);
			
		for (int i = 0; i < 3; i ++) {
			// 创建stu结点
			Element stu = doc.createElement("stu" + (i + 1));
			// 把元素结点添加到stu结点下
			root.appendChild(stu);
			
			// 设置element的属性
			stu.setAttribute("id",(i + 1) + "");
			
			// 创建学生的姓名结点
			Element name = doc.createElement("name");
			name.setTextContent("小明" + i);
			stu.appendChild(name);
			
			// 学生的年龄结点
			Element age = doc.createElement("age");
			age.setTextContent("" + (18 + i));
			stu.appendChild(age);
			
		}
		
		// 印刷
		// 创建印刷工场
		TransformerFactory tff = TransformerFactory.newInstance();
		// 印刷机器
		Transformer tf = tff.newTransformer();
		// 开始印刷
		// 创建xml数据源
		DOMSource source = new DOMSource(doc);
		// 确定输出位置
		StreamResult res = new StreamResult("stu.xml");
		tf.transform(source, res);		
	}
	
	// 排版 or 解析
	static Document DOMComposing(String path) throws Exception {
		// 排版工场
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 排版机器
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = null;
		// 空白文档,准备排版
		if (path == "" || path == null)
			doc = db.newDocument();
		else 
			doc = db.parse(path); // 解析xml
		
		return doc;
	}
	
	/**
	 * @param doc 排版文档
	 * @param xml文件输出路径
	 * @throws Exception 
	 */
	static void DOMPrinting(Document doc, String outputPath) throws Exception {
		
		// 排版工场
		TransformerFactory tff = TransformerFactory.newInstance();
		// 排版机器
		Transformer tf = tff.newTransformer();
		// 数据源
		DOMSource xmlSource = new DOMSource(doc);
		// 输出地址,开始排版 file:/// 中文路径乱码
		StreamResult res = new StreamResult(new File(outputPath));
		tf.transform(xmlSource, res);
	}
	
	// hide difficulties
	static void createNew() {
		try {
			Document doc = DOMComposing("");
			
			Element root = doc.createElement("person");
			
			doc.appendChild(root);
		
			for (int i = 0; i < 3; i ++) {
				Element teacher = doc.createElement("teacher");
				teacher.setAttribute("id", "" + (i + 1));
				
				root.appendChild(teacher);
				
				Element name = doc.createElement("name");
				// 设置name结点的文本内容
				name.setTextContent("cici" + (i + 1));
				Element age = doc.createElement("age");
				age.setTextContent((24 + i) + "");
				
				// 把姓名和年龄添加到teacher结点
				teacher.appendChild(name);
				teacher.appendChild(age);
	
			}
			
			DOMPrinting(doc, "person.xml");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	static void parserXML() throws Exception {
		// 排版解析
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		// 解析xml
		Document doc = db.parse(new File("stu.xml"));
		
		// Element root = (Element) doc.getFirstChild();
		Element root = doc.getDocumentElement();
		
		NodeList nodes = root.getChildNodes();
		System.out.println(nodes.item(0));
		for (int i = 0; i < nodes.getLength(); i++) {
			Element stu = (Element) nodes.item(i);
			String text = nodes.item(i).getFirstChild().getTextContent();
			System.out.println(stu.getAttribute("id") + "\t" + text);
		}
		
	}
}
  • element获取结点的其它方式
		Element root = doc.getDocumentElement();
		root.getFirstChild();//获得当前节点第一个子节点
		root.getLastChild();//获得当前节点最后一个子节点
		root.getNextSibling();//获得当前节点下一个兄弟节点
		root.getPreviousSibling();//获得当前节点上一个兄弟节点
		root.getParentNode();//获得当前节点父节点

2.2 使用dom解析xml文件

  • 对books.xml解析
	static void domParse() {
		Document doc = docComposing("books.xml");
		Element root = (Element) doc.getFirstChild();
		
		NodeList list = root.getChildNodes();
		for (int i = 0; i < list.getLength(); i++) {
			Element book = (Element) list.item(i);
			System.out.println(book.getAttribute("id") + "\t" + book.getTextContent());
		}
	}

/**
1001	java
1002	c#
*/

2.3 使用dom对xml文件增删改

  • 如图
	static void DOMAddXML() {
		try {
			Document doc = DOMComposing("person.xml");
		   
			// 得到第二个name结点下面的第一个结点
		    Element name = (Element) doc.getFirstChild().getFirstChild().getNextSibling().getFirstChild();
		    // System.out.println(name.getTextContent() + "--" + name.getAttribute("id"));
		    // 创建gender结点
		    Element gender = doc.createElement("gender");
		    name.getParentNode().appendChild(gender);
		    gender.setTextContent("female");
		    
		    DOMPrinting(doc, "person.xml");
		    
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	static void DOMUpdateXML() {
		try {
			Document doc = DOMComposing("person.xml");
			doc.getDocumentElement().getLastChild().setTextContent("null");
			
			DOMPrinting(doc, "person.xml");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	static void DOMDeleteXML() {
		try {
			Document doc = DOMComposing("person.xml");
			Element beRemoved = (Element) doc.getDocumentElement().getLastChild();
			beRemoved.getParentNode().removeChild(beRemoved);
			
			DOMPrinting(doc, "person.xml");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

3. 使用SAX解析xml文件

  • 继承DefaultHander类
package test;

import java.util.ArrayList;

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

import entity.Person;

public class MyDefaultHandler extends DefaultHandler {
	
	private ArrayList<Person> list;
	private Person p;
	
	private String tagName;
	
	// 重写
	public MyDefaultHandler(ArrayList<Person> list) {
		this.list = list;
	}
	
	@Override
	public void startDocument() throws SAXException {
		System.out.println("解析根节点");
	}
	
	@Override
	public void endDocument() throws SAXException {
		System.out.println("根结点解析结束");
	}
	
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		this.tagName = qName; // 标记元素结点的值
		if ("teacher".equals(qName)) { // 开始解析第一个teacher结点 准备进行数据封装
			p = new Person(); // 有几个结点便会产生几个person 对象
			System.out.println(p);
			list.add(p);
			p.setId(Integer.parseInt(attributes.getValue("id")));
		}
		
		System.out.println("元素结点解析开始 " + qName);
	}
	
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		// System.out.println("元素结点解析结束... ");
	}
	
	// 文本结点值
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		
		String value = new String(ch, start, length);
		
		if ("name".equals(tagName)) {
			p.setName(value);
		} else if ("age".equals(tagName)) {
			p.setAge(Integer.parseInt(value));
		} else if ("gender".equals(tagName)) {
			p.setGender(value);
		}	
		
		System.out.println("文本元素值 " + value);
	}
}

  • person实体
package entity;

public class Person {
	
	// 用于存储xml集合保存的数据
	
	private Integer id;
	private Integer age;
	private String name;
	private String gender;
	
	public Person() {}
		
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override 
	public String toString() {
		return "Person [id=" + id + ", age=" + age + ", name=" + name
				+ ", gender=" + gender + "]";
	}
	

}

  • sax解析
package test;

import java.io.IOException;
import java.util.ArrayList;

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

import org.xml.sax.SAXException;

import entity.Person;

public class SAXParseXML {

	public static void main(String[] args) {
		// 使用sax解析xml
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = null;
		
		ArrayList<Person> list = new ArrayList<Person>();
		
		try {
			sp = spf.newSAXParser();
			
			sp.parse("person.xml", new MyDefaultHandler(list));
		} catch (ParserConfigurationException | SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {

			e.printStackTrace();
		}
		
		System.out.println(list);

	}

}

/**
*[Person [id=1, age=24, name=cici1, gender=female], 
Person [id=2, age=25, name=cici2, gender=female], 
Person [id=3, age=26, name=cici3, gender=null]]

*/

4. 使用DOM4J操作xml文件

4.1 使用DOM4J创建xml文件

  • 创建如图所示的xml

  • 使用dom4j前提

  • coding…
package test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

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

public class Dom4jCreateXML {

	public static void main(String[] args) {
	
		// xml文档对象
		Document doc = DocumentHelper.createDocument();
		// 根节点对象
		Element root = doc.addElement("Students");
		
		// 第一个学生结点
		Element stu1 = root.addElement("student");
		stu1.addAttribute("id", "1");
		// 添加姓名结点
		stu1.addElement("name").addText("rye");
		// 添加性别结点
		stu1.addElement("gender").addText("female");
		
		// 可以在创建学生结点的同时添加id属性
		Element stu2 = root.addElement("student").addAttribute("id", 2 + "");
		stu2.addElement("name").addText("jack");
		stu2.addElement("gender").addText("male");
		
		Element stu3 = root.addElement("student").addAttribute("id", 3 + "");
		stu3.addElement("name").addText("rose");
		stu3.addElement("gender").addText("male");
		
		
		// 利用XMLWriter把内存中的xml 写入文件
		XMLWriter w = null;
		try {
			w = new XMLWriter(new OutputStreamWriter(new FileOutputStream("student.xml"), "utf-8"));
			w.write(doc);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (w != null)
					w.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}

}

4.2 使用DOM4J解析xml文件

package test;

import java.util.List;

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

public class DOM4jParseXML {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		// SAXReader 读取xml文件
		SAXReader reader = new SAXReader();
		Document doc = null;
		try {
			doc = reader.read("student.xml");
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		
		// 根节点students
		Element root = doc.getRootElement();
		
		List<Element> list = root.elements();
		// 拿到每个学生结点的名字和姓名
		for (Element stu : list) {
			// stu.element("name"); 拿到name结点
			// 获取属性值id
			System.out.println(stu.attributeValue("id"));
			System.out.println(stu.elementText("name") + "\t" + stu.elementText("gender"));
		}
		
		// 记住! 语法有 有斜杠 必须导入jaxen-1.1.6.jar 
		List<Element> nameNodes = root.selectNodes("//name");
		nameNodes = doc.selectNodes("//student/name");
		nameNodes = doc.selectNodes("//student/gender");
		for (Element name : nameNodes) {
			System.out.println(name.getName() + "\t" + name.getText());
		}
		
		// 拿到单个结点
		Node stuNode1 = doc.selectSingleNode("//Students/student[@id='1']/name");
		System.out.println(stuNode1.getName() + "\t " + stuNode1.getText());
	}

}

/**
1
rye	female
2
jack	male
3
rose	male
gender	female
gender	male
gender	male
name	 rye
*/

最后使用dom4j工具类虽然能给我们简化大量解析xml的代码,但是还是得了解jdk提供的api解析原理。

猜你喜欢

转载自blog.csdn.net/qq_44783283/article/details/106985390