用SAX、DOM、JDOM和DOM4J读写XML文件

package com.mipo.xml.demo1;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
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.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jdom2.JDOMException;
import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;

public class Foo {
	//注意路径
	private static InputStream resource = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/mipo/xml/demo1/Book.xml");
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		readWithDOM();
		writeWithDOM();
	}
	
	//SAX解析XML文档*************************************************************
	/*
	 * 用于读取和 操作XML文件的标准是文档对象模型DOM。缺点:低效的、缓慢的,消耗资源。
	 * 一种替代技术就是SAX,即Simple API for XML。SAX允许您在读取文档是操作它,而不必等待整个文档被存储后才采取操作。
	 * 
	 * SAX是一个基于事件的 API。
     * 解析器向一个事件处理程序发送事件,比如元素开始和元素结束,而事件处理器则处理该信息。
     * 应用程序本身就能够处理该数据。
     * 原始的文档仍然保留完好无损
	 * 
	 * 
	 * SAX 处理涉及以下步骤: 
	 *  1、 创建一个事件处理程序。
	 *  2、创建 SAX 解析器。
	 *  3、 向解析器分配事件处理程序。
	 *  4、 解析文档,同时向事件
	 *  5、处理程序发送每个事件 
	 * 
	 * SAX优点:可以解析任意大小的文件;
	 * 		      适合创建自己的数据结构;
	 * 		      适合小信息子集;
	 *        简单、快速;
	 *    缺点:不能对文档做随机存取;
	 *        难以实现复杂的查询;
	 *        不能使用文档类型定义(DTD);
	 *        不可获取词法信息;
	 *        SAX是只读的;
	 *        当前的浏览器不支持SAX;
	 * 
	 * 
	 * SAX的核心基于两个接口:
	 * 		XMLReader接口:表示分析
	 * 			分析过程就是读取XML文档并向客户应用程序报告其内容,同时检查文档的形式合理性。
	 * 			SAX将分析器表示为XMLReader接口的实例。
	 * 			分析器是读取文档,并在发现形式合理性错误时抛出异常。
	 * 			XMLReader读取到对应的内容后就会调用ContentHandler接口中对应的方法。
	 * 
	 * 		ContentHandler接口:从分析器接收数据。
	 * 			在ContentHandler接口中定义了11个方法,这些方法都是在分析器(即 XMLReader)读取文档时被回调的,且这个类必须被客户应用程序实现。
	 * 
	 * 
	 * 
	 * 选择DOM还是SAX,取决以下因素:
	 * 		1、DOM写XML文件更方便,SAX读XML文件更方便
	 * 		2、对于容量比较大的文件,选择SAX
	 * 		3、如果只有数据中的少量部分会被使用,使用SAX将该部分数据提取到应用程序中更好。
	 * 		4、SAX实现速度通常比DOM实现速度更快。
	 * 
	 * 
	 */
	private static void readWithSAX() {
		try {
			//创建SAX解析器工厂实例
			SAXParserFactory saxPF = SAXParserFactory.newInstance();
			//根据SAX解析器工厂实例创建SAX解析器
			SAXParser saxP = saxPF.newSAXParser();
			//创建DefaultHandler文档处理程序,解析XML文件
			saxP.parse(resource, new org.xml.sax.helpers.DefaultHandler(){
				/*
				 * 文档事件
				 * 分析器开始分析新文档后,在调用ContentHandler任何方法之前,立即调用startDocument()方法。
				 * 在文档分析完毕后调用endDocument()方法,并且不在对这个文档报告任何内容。 
				 * (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#startDocument()
				 */
				@Override
				public void startDocument() throws SAXException {
					super.startDocument();
					System.out.println("###############startDocument()");
				}
				
				@Override
				public void endDocument() throws SAXException {
					super.endDocument();
					System.out.println("###############endDocument()");
				}
				
				/*
				 * 元素事件
				 * 当分析器遇到开始标志时,立即调用startElement()方法
				 * 当分析器遇到结束标志时调用endElement()方法。
				 * 如果遇到空元素标志时,调用startElement()和endElement()方法。
				 * 如果开始标志和结束标志不符,则分析器抛出SAXParseException.
				 * (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
				 */
				@Override
				public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes) throws SAXException {
					super.startElement(uri, localName, qName, attributes);
					System.out.println("节点名:"+qName);
					
					for (int i=0; i<attributes.getLength(); i++) {
						System.out.println("属性:"+attributes.getValue(i));
					}
				}
				
				@Override
				public void endElement(String uri, String localName, String qName) throws SAXException {
					super.endElement(uri, localName, qName);
				}
				
				/*
				 * 字符数据
				 * 分析器读取#PCDATA时,将这个文本以字符数组传递给characters()方法
				 * 
				 * (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
				 */
				@Override
				public void characters(char[]ch ,int start, int length) throws SAXException {
					super.characters(ch, start, length);
					System.out.println("节点内容:"+new String(ch,start,length));
				}
				
				@Override
				public void skippedEntity(String name) throws SAXException {
					super.skippedEntity(name);
				}
			});
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//SAX生成XML文件
	public void writeWithSAX() {
		try {
			SAXTransformerFactory saxTF = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
			TransformerHandler th = saxTF.newTransformerHandler();;
			th.setResult(new StreamResult(new File("src/com/mipo/xml/demo1/Book.xml")));
			Transformer transformer = th.getTransformer();
			transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			
			th.startDocument();
			th.startElement("", "", "cars", null);
            th.startElement("", "", "car", null);
            th.startElement("", "", "name", null);
			String text = "Audi";
			th.characters(text.toCharArray(), 0, text.length());
			th.endElement("", "", "name");
			th.startElement("", "", "price",null);
			String text1 ="480000";
			th.characters(text1.toCharArray(), 0, text1.length());
			th.endElement("", "", "price");
			th.endElement("", "", "car");
			th.endElement("", "", "cars");
			th.endDocument();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	//DOM解析XML文件*************************************************************
	/*
	 * DOM即Document Object Model,也即文档对象模型。
	 * 基于DOM的XML解析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对对象模型的操作,实现对XML文档数据的操作。
	 * 通过DOM接口,应用程序可以在任何时候访问XML文档中任何一部分。
	 * 在DOM接口规范中,有四个基本的接口:Document,Node,NodeList,以及NamedNodeMap
	 * 
	 * Document接口有两个作用:
	 * 1、表示XML文档本身和提供对内容、文档类型声明和其他属性的访问
	 * 2、它是个抽象工厂,负责生成文档中的节点:元素、文本、属性等等
	 * DOM是读写API,不仅可以通过分析文本文件生成DOM文档,也可以在内存中从头开始生成新的文档。
	 * 1、生成新Document对象的抽象工厂接口是DOMImplementation.
	 * 2、通过节点的ownerDocument属性,用来表明当前节点是由谁所创建的以及节点同Document之间的联系 
	 * 
	 * 在DOM树中,Node接口代表了树中一个节点。
	 * Node大致可以分为5个部分:
	 * 1、节点类型常量
	 * 2、设置与读取节点属性的方法
	 * 3、导航DOM树的方法
	 * 4、增加与删除子节点的方法
	 * 5、几个实用程序方法
	 * 
	 * DOM用NodeList对象存放节点的子节点列表。Node接口的getChildNodes()方法返回该接口的实例。
	 * 实现了NamedNodeMap接口的对象中,包含了可以通过名字来访问的一组节点的集合。
	 * NamedNodeMap并不是从NodeList继承过来的,它所包含的节点集  中 的节点是无序的。
	 * NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。
	 * 
	 * Element接口是XML文档中最重要的,定义XML文档结构的是元素,而不是其他组件。
	 * Element接口包含了很多对元素进行操作的方法。
	 * 
	 * 
	 * 为了使用XML文件信息,必须解析文件以获得Document对象。
	 * Document对象是一个接口,因而不能将它直接实例化;一般情况下,应用程序会会相应使用一个工厂(工厂模式)
	 * 
	 * 
	 * Java的DOM 2 实现允许通过以下方法控制解析器的参数:
	 * setCoalescing():决定解析器是否要将 CDATA 节点转换为文本,以及是否 要和周围的文本节点合并。其默认值为 false。
	 * setExpandEntityReferences(): 确定是否要展开外部实体引用。如果为 true,外部数据将插入文档。其默认值为 true。
	 * setIgnoringComments():确定是否要忽略文件中的注释。其默认值为 false。 
	 * setIgnoringElementContentWhitespace():确定是否要忽略元素内容中的空白。其默认值为 false。
	 * setNamespaceAware():确定解析器是否要注意名称空间信息。其默认值为 false。
	 * setValidating():默认情况下,解析器不验证文档。将这个参数设置为 true 可打开验证功能。
	 * 
	 * 
	 */
	private static void readWithDOM() {
		try {
			//创建 DocumentBuilderFactory(解析对象工厂);DocumentBuilderFactory 对象创建 DocumentBuilder
			DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
			//创建 DocumentBuilder(文档解析器对象);DocumentBuilder 执行实际的解析以创建 Document 对象
			DocumentBuilder docB = docBF.newDocumentBuilder();
			//解析文件以创建 Document 对象
			org.w3c.dom.Document doc = docB.parse(resource);
			//获得该文档对象的根元素
			org.w3c.dom.Element rootElement = doc.getDocumentElement();
			//获取节点名称
			System.out.println("根节点名:"+rootElement.getNodeName());
			
			//获取节点的孩子。一旦应用程序获得了根元素,它就把根元素的孩子的列表作为一个NodeList来检索
			org.w3c.dom.NodeList nodes = rootElement.getChildNodes();
			//遍历根节点下的孩子
			for(int i=0; i<nodes.getLength(); i++) {
				org.w3c.dom.Node bookNode = nodes.item(i);
				//如果为空白文本节点,就跳过(元素节点,属性节点,文本节点,文档节点)
				if(org.w3c.dom.Node.TEXT_NODE  == bookNode.getNodeType()) {
					continue;
				}
				System.out.println("子节点:"+bookNode.getNodeName());
				
				//获取子节点的孩子
				org.w3c.dom.NodeList records = bookNode.getChildNodes();
				for(int j=0; j<records.getLength(); j++) {
					org.w3c.dom.Node record = records.item(j);
					//如果为空白文本节点就跳过
					if(org.w3c.dom.Node.TEXT_NODE == record.getNodeType()) {
						continue;
					}
					//获得节点的第一个孩子,并获得其文本内容值
					System.out.println(record.getNodeName()+":"+record.getFirstChild().getNodeValue());
					//获得节点的属性
					org.w3c.dom.NamedNodeMap attributes = record.getAttributes();
					if(null !=attributes && attributes.getLength()>0) {
						for(int k=0; k<attributes.getLength(); k++) {
							org.w3c.dom.Node attr = attributes.item(k);
							//获取属性名及属性文本内容值
							System.out.println(attr.getNodeName()+"::"+attr.getNodeValue() );
						}
					}
				}
			}
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
	//DOM生成XML文件**************************************************************
	private static void writeWithDOM() {
		try {
			DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
			DocumentBuilder docB = docBF.newDocumentBuilder();
			org.w3c.dom.Document doc = docB.newDocument();
			
			org.w3c.dom.Element rootElement = doc.createElement("students");
			org.w3c.dom.Element subElement = doc.createElement("student");
			org.w3c.dom.Element nameElement = doc.createElement("name");
			nameElement.setTextContent("鸣人");
			nameElement.setAttribute("sex", "男");
			subElement.appendChild(nameElement);
			org.w3c.dom.Element classElement = doc.createElement("class");
			classElement.setTextContent("三年级七班");
			subElement.appendChild(classElement);
			org.w3c.dom.Element idElement = doc.createElement("id");
			idElement.setTextContent("20050307003");
			subElement.appendChild(idElement);
			
			org.w3c.dom.Element subElement1 = doc.createElement("student");
			org.w3c.dom.Element nameElement1 = doc.createElement("name");
			nameElement1.setTextContent("佐助");
			nameElement1.setAttribute("sex", "男");
			subElement1.appendChild(nameElement1);
			org.w3c.dom.Element classElement1 = doc.createElement("class");
			classElement1.setTextContent("三年级七班");
			subElement1.appendChild(classElement1);
			org.w3c.dom.Element idElement1 = doc.createElement("id");
			idElement1.setTextContent("20050307001");
			subElement1.appendChild(idElement1);
			
			rootElement.appendChild(subElement);
			rootElement.appendChild(subElement1);
			
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer trans = tf.newTransformer();
			//注意路径,相对路径
			File file = new File("src/com/mipo/xml/demo1/studentDemo.xml");
			trans.transform(new DOMSource(rootElement),new StreamResult(file));
		} catch (DOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	//JDOM解析XML文件
	/*
	 * JDOM是java document object model的简称,JDOM兼顾了DOM和SAX的优点,它会提供适配器用来选择具体的XML解析器。
	 * JDOM是一个源代码开发的项目,它基于树型结构,利用纯Java的技术对XML文件实现解析、生成、序列化以及多种操作。
	 * 
	 * 在JDOM中,XML元素就是ELement的实例,XML属性就是Attribute的实例,XML文档本身就是Document的实例。
	 * 因此创建JDOM对象就如同在Java语言中使用new操作符一样简单。
	 * 
	 * JDOM与DOM相比,主要有一下两个优势:
	 * 1、JDOM仅使用具体类而不使用接口,这就在某些方面简化了API,同时也限制了其灵活性。
	 * 2、API使用了很多Collection类,使得熟悉这些类的Java开发人员使用起来得心应手。
	 * 
	 * 
	 * JDOM是由一下几个包组成的:
	 * org.jdom.* : 包含了所有的xml文档要素的java类
	 * org.jdom.adapters.*:包含了与dom适配的java类
	 * org.jdom.filter.*:包含了xml文档的过滤器类
	 * org.jdom.input.*:包含了读取xml文档的类
	 * org.jdom.output.* :包含了写入xml文档的类
	 * org.jdom.transform.*:包含了将jdom xml文档接口转换为其他xml文档接口
	 * org.jdom.xpath.*:包含了对xml文档xpath操作的类
	 * 
	 * 
	 * 
	 * 
	 */
	private static void readWithJDOM () {
		try {
			org.jdom2.input.SAXBuilder sb = new org.jdom2.input.SAXBuilder();
			org.jdom2.Document doc = sb.build(resource);
			org.jdom2.Element rootElement = doc.getRootElement();
			System.out.println("根节点:"+rootElement.getName());
			
			List<org.jdom2.Element> nodes = rootElement.getChildren();
			for(org.jdom2.Element element:nodes) {
				System.out.println("节点::"+element.getName());				 
				for(org.jdom2.Element item:element.getChildren()) {
					System.out.println(item.getName()+"::"+item.getValue());
				}
			}
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	//JDOM生成XML文件
	/*
	 * 通过JDOM创建XML文件:
	 * 
	 * 1、创建根元素  
	 * 2、根据根元素创建文档
	 * 3、给根元素添加属性
	 * 4、添加元素或子元素
	 * 5、删除元素
	 * 6、将JDOM对象转换为xml文件
	 * 
	 */
	private static void writeWithJDOM() {
		//创建根元素
		org.jdom2.Element rootElement = new org.jdom2.Element("phones");
		//根据根元素创建文档
		org.jdom2.Document  doc = new org.jdom2.Document(rootElement);
		//创建元素phone
		org.jdom2.Element phone = new org.jdom2.Element("phone");
		//给元素phone添加子元素name,并设置文本值
		phone.addContent(new org.jdom2.Element("name").setText("iphone 7"));
		//给元素phone添加子元素price,并设置文本值及属性值
		phone.addContent(new org.jdom2.Element("price").setText("6888").setAttribute("type","CNY"));
		//将元素phone添加到根元素中
		rootElement.addContent("phone");
		//org.jdom.output.XMLOutputter类负责将JDOM对象以流的形式输出。
		org.jdom2.output.XMLOutputter xmlOutputter = new org.jdom2.output.XMLOutputter();
		try {
			//将JDOM中内容输出到指定外部文档中
			xmlOutputter.output(doc, new FileWriter(new File("/XML编程/src/com/mipo/xml/demo1/Phone.xml")));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	//dom4j解析XML文档
	private static void readWithDom4j() {
		SAXReader sr = new SAXReader();
		try {
			org.dom4j.Document doc = sr.read(resource);
			org.dom4j.Element rootElement = doc.getRootElement();
			System.out.println("根节点:"+rootElement.getName());
			
			List nodes = rootElement.elements();
			for(int i=0; i<nodes.size(); i++) {
				org.dom4j.Element bookElement = (org.dom4j.Element)nodes.get(i);
				List records = bookElement.elements();
				for(int j=0; j<records.size(); j++) {
					org.dom4j.Element item = (org.dom4j.Element)records.get(j);
					
					System.out.println(item.getName()+"::"+item.getText());
				}
				
			}
			
			
			
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	//dom4j生成XML文档
	private static void writeWithDom4j() {
		 org.dom4j.Document doc = DocumentHelper.createDocument();
		 org.dom4j.Element rootElement = doc.addElement("persons");
		 org.dom4j.Element personElement = rootElement.addElement("person");
		 org.dom4j.Element nameElement = personElement.addElement("name");
		 nameElement.addText("苏轼");
		 nameElement.addAttribute("sex","男");
		 org.dom4j.Element productionElement = nameElement.addElement("production");
		 productionElement.addText("一蓑烟雨任平生");
		 
		 
		 try {
			XMLWriter xmlWriter = new XMLWriter(new FileWriter(new File("/XML编程/src/com/mipo/xml/demo1/Book.xml")));
			xmlWriter.write(doc);
			xmlWriter.flush();
			xmlWriter.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值