XML解析---DOM解析和SAX解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40348465/article/details/84591365

   XML是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。

一、DOM解析

  DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

  DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。

  DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

    优点:

      1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。

      2、解析过程中,树结构保存在内存中,方便修改。

    缺点:

      1、由于文件是一次性读取,所以对内存的耗费比较大。

      2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

  DOM解析示例:

项目目录结构

  1.DOM解析

  TestXML.java文件

import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

//采用DOM进行解析
//DOM的读取时是将XML整个文件装载成DOM树,即使文档中有不需要的信息时也会被装载进来,在大多数的时候DOM是非常方便好用的。
public class TestXMl {
	public static void main(String[] args) {
		// 文档构建器的工厂
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 得到XML文档构建器
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			// 1.得到XML文档对象
			// 当test.xml放在本项目的根目录时(和src bin同一目录下时)
			// db.parse("test.xml");
			// 当test.xml放在bin目录下时
			String path = FileReader.class.getResource("/").getFile();
			/// System.out.println(path);
			// 导入的是org.w3c.dom.Document;
			Document doc = db.parse(path + "test.xml");
			// 得到文档根节点
			Element root = doc.getDocumentElement();
			String rootName = root.getNodeName();
			System.out.println(rootName);
			NodeList list = doc.getElementsByTagName("People");
			// 2.获取XML中的节点
			System.out.println("当前有几个People:" + list.getLength());

			// 3.得到节点里面的有用信息
			for (int i = 0; i < list.getLength(); i++) {
				Element peopleElement = (Element) list.item(i);
				String id = peopleElement.getAttribute("id"); // 获取id的属性值
				System.out.println("id:" + id);
				// 遍历当前元素的子节点
				NodeList childNodeList = peopleElement.getChildNodes();
				// test.xml中一个People元素下有Name和Age两个标签,但是它把回车也算作一个节点,所以打印出来是五个
				// 第一个是没有回车的,第二个有
				System.out.println("子节点个数:" + childNodeList.getLength());

				// 判断这些子节点中的元素是不是有效的元素,即不为回车
				for (int j = 0; j < childNodeList.getLength(); j++) {
					// 判断是不是元素,有标签的,若是元素才把它转换为元素
					if (childNodeList.item(j) instanceof Element) {
						Element cElement = (Element) childNodeList.item(j);
						String tagName = cElement.getTagName();
						String content = cElement.getTextContent();
						System.out.println(tagName + ":" + content);
					}
				}
			}

		} 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();
		}

	}
}

2.往XML文件中写入的是Document对象

  Write.java文件


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
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.Text;

//由对象到文件,把document对象保存到文件中
//XML是磁盘文件,DOM是内存对象。
//往XML文件中写入的是Document对象,所以要编辑XML文件,实际上编辑的是Document文档对象。
public class WriteXML {
    public static void main(String[] args) {
    	//创建一个document,通过builder创建
    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    	try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.newDocument();
			
			//通过document创建节点Element
			Element stuEle = doc.createElement("Student");
			stuEle.setAttribute("stuNo","S1001");
			//给stuEle添加子节点
			Element nameEle = doc.createElement("Name");
			//方式一:创建一个文本节点
			/*Text txtName = doc.createTextNode("zhangsan");
			nameEle.appendChild(txtName);*/
			//方式二:直接添加文本
			nameEle.setTextContent("zhangsan");
			Element ageEle = doc.createElement("Age");
			ageEle.setTextContent("20");
			stuEle.appendChild(nameEle);
			stuEle.appendChild(ageEle);
			
	    	//将Element对象添加到document中
			doc.appendChild(stuEle);
			
	    	//将document对象保存到硬盘文件xml中
	    	//通过transformer进行保存
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer former = tf.newTransformer();
			former.transform(new DOMSource(doc), new StreamResult("stu.xml"));
			System.out.println("生成xml成功...");
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	
    }
}

  test.xml

<?xml version="1.0" encoding="UTF-8"?>
<PeopleList>
   <People id="1">
      <Name en="zhangsan">张三</Name>
      <Age>20</Age>
	  <Address>苏州</Address>
   </People>
   <People id="2">
      <Name en="lisi">李四</Name>
      <Age>39</Age>
	  <Address>常州</Address>
    </People>
	 <People id="3">
      <Name en="wangwu">王五</Name>
      <Age>14</Age>
	  <Address>杨州</Address>
    </People>
	 <People id="4">
      <Name en="zhaowu">赵武</Name>
      <Age>31</Age>
	  <Address>贵州</Address>
    </People>
	 <People id="5">
      <Name en="sunliu">孙刘</Name>
      <Age>26</Age>
	  <Address>广州</Address>
    </People>
</PeopleList>

二、SAX解析

  SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

    优点:

      1、采用事件驱动模式,对内存耗费比较小。

      2、适用于只处理XML文件中的数据时。

    缺点:

      1、编码比较麻烦。

      2、很难同时访问XML文件中的多处不同数据。

SAX解析示例

      XMLHandler.java

     


import java.util.ArrayList;
import java.util.List;

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

public class XMLHandler extends DefaultHandler {
	
	private String value; //读取到的文本
	private People people; //临时存放的一个人
	private List<People> peopleList;

	
	public List<People> getPeopleList() {
		return peopleList;
	}

	

	//当读到文档开始处触发事件,该方法只执行一次
	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.startDocument();
		System.out.println("开始执行startDocument,开始读取xml文档");
		peopleList = new ArrayList<People>();
	}
    
	//当读到文档结束处触发事件,该方法只执行一次
	@Override
	public void endDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.endDocument();
		System.out.println("开始执行endDocument,结束读取xml文档");
	}
    
    //当读到元素开始处触发事件
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		// TODO Auto-generated method stub
		super.startElement(uri, localName, qName, attributes);
		System.out.println("开始执行startElement,开始读取xml文档的标签,该标签为:"+qName);
		if("People".equals(qName)) {
			people = new People();
			System.out.println("当前people有属性"+attributes.getLength());
			for(int i = 0;i<attributes.getLength();i++) {
				//获取当前属性名
				if("id".equals(attributes.getQName(i))) {
					people.setId(attributes.getValue(i));
				}
			}
		}
	}
    
	//当读到元素结束处触发事件
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		// TODO Auto-generated method stub
		super.endElement(uri, localName, qName);
		System.out.println("开始执行endElement,结束读取xml文档的标签,该标签为:"+qName);
		if("People".equals(qName)) {
			peopleList.add(people);
			people = null;
		}else if("Name".equals(qName)) {  //读到Name的结束标签
			people.setName(value);
		}else if("Age".equals(qName)) {
			people.setAge(value);
		}
	}
    
	//读到内容时触发事件
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		// TODO Auto-generated method stub
		super.characters(ch, start, length);
		value = new String(ch,start,length);
		System.out.println("当前读到的文本是:"+value);
	}
  
}

   ReadXMLBySAX.java

import java.io.IOException;
import java.util.List;

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

import org.xml.sax.SAXException;

//SAX解析
//流读取的机制(SAX),Document的读取在内部也是使用流的机制去读的。
//流读取的机制是只负责读取,不进行存储,但是会给出一定的关键的事件,提示你进行相应的保存操作。
public class ReadXMLBySAX {
    public static void main(String[] args) {
    	//得到saxParser
    	SAXParserFactory  factory = SAXParserFactory.newInstance();
    	try {
			SAXParser parser = factory.newSAXParser();
			XMLHandler handler = new XMLHandler();
			//通过saxParse接卸器的parse方法,解析xml,parse需要一个处理器,handler
			parser.parse("test.xml", handler);
			List<People> list = handler.getPeopleList();
			System.out.println("一共读取倒了"+list.size()+"个人");
			for(People people : list) {
				System.out.println(people);
			}
		} 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();
		}
    	
    }
}

   People.java

   


public class People {
	private String id;
	private String name;
	private String age;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public People(String id, String name, String age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public People() {
		super();
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "Student[id="+id+",name="+name+",age="+age+"]";
	}
	
	

}

猜你喜欢

转载自blog.csdn.net/qq_40348465/article/details/84591365