加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

解析XML方式-DOM,SAX

发布时间:2020-12-16 08:41:17 所属栏目:百科 来源:网络整理
导读:students.xml ?xml version="1.0" encoding="UTF-8"?students student id="1" name张珊/name age22/age /student student id="2" name王航/name age25/age /student student id="3" name刘沙/name age26/age /student student id="4" name张海/name age24/ag

students.xml

<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student id="1">
        <name>张珊</name>
        <age>22</age>
    </student>
    <student id="2">
        <name>王航</name>
        <age>25</age>
    </student>
    <student id="3">
        <name>刘沙</name>
        <age>26</age>
    </student>
    <student id="4">
        <name>张海</name>
        <age>24</age>
    </student>
</students>

Person.java

package xmldom;

public class Person {
	int id;
      String name;
      int age;
      
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
      
}

一,DOM方式解析XML就是先把XML文档都读到内存中,然后在用户DOMAPI来访问树形结构,获取数据

解析的思路是:

1,将xml文件加载进来

2,获取文档的根节点

3,获取文档根节点中的所有子节点的列表

4,获取子节点列表中需要多去的节点信息

首先创建一个DocumentBuilderFactory实例,然后通过该实例来加载XML文档(Document)文档加载完毕以后,进行节点获取,先找到根节点,在找到子节点。

package xmldom;

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

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;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		    ArrayList<Person> studentslist=new ArrayList<Person>();
		    
		    DocumentBuilderFactory factory=null;//DOM解析器工厂
		    DocumentBuilder builder=null;//DOM解析器
		    Document document=null;//文档对象
		   
		    try {
		    	//1,实例化DOM解析器工厂,工厂的作用是创建具体的解析器
		    	factory=DocumentBuilderFactory.newInstance();
		    	//2,通过工厂获得DOM解析器
				builder=factory.newDocumentBuilder();
				//3,通过DOM解析器获得文档对象,可以解析File,InputStream等
				document=builder.parse(new File("students.xml"));//把这个文档放在项目的根路径下,与src目录平行,就可以使用相对路径来引用了
				
				
				//4,获取文档的根节点
				Element root=document.getDocumentElement();
				//5,由根节点获取子节点列表
				NodeList nodelist=root.getElementsByTagName("student");
				
				//遍历每个子节点
				Person person=null;
				for(int i=0;i<nodelist.getLength();i++){
					   person=new Person();
					   // 获得元素,将节点强制转换为元素。此时element就是一个具体的元素
					   Element studentelement=(Element) nodelist.item(i);					   
					   String id=studentelement.getAttribute("id");//元素获得属性值
					   person.setId(Integer.valueOf(id));
					   
					   //获取子元素:子元素name只有一个节点.所以是item(0)
					   Element Name=(Element) studentelement.getElementsByTagName("name").item(0);
					   person.setName(Name.getFirstChild().getNodeValue());//获得子元素的值,一定要加getFirstChild
					   
					   //获取子元素:子元素name只有一个节点.所以是item(0)
					   Element Age=(Element) studentelement.getElementsByTagName("age").item(0);
					   person.setAge(new Integer(Age.getFirstChild().getNodeValue()));//获得子元素的值,一定要加getFirstChild
					   
					   studentslist.add(person);
					   
			   }								
				
			} 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();
			}
		    
		    for(int i=0;i<studentslist.size();i++){
		    	  System.out.println("ID:"+studentslist.get(i).getId()+
		    			             " 姓名:"+studentslist.get(i).getName()+
		    			             " 年龄:"+studentslist.get(i).getAge());		    	 
		    }
		    
		    
	}

}
结果:

ID:1 姓名:张珊 年龄:22
ID:2 姓名:王航 年龄:25
ID:3 姓名:刘沙 年龄:26
ID:4 姓名:张海 年龄:24
DOM 的 API:
1.解析器工厂类:DocumentBuilderFactory
创建的方法:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2.解析器:DocumentBuilder
创建方法:通过解析器工厂类来获得 DocumentBuilder db = dbf.newDocumentBuilder();
3.文档树模型Document
创建方法:a.通过xml文档 Document doc = db.parse("bean.xml"); b.将需要解析的xml文档转化为输入流 InputStream is = new FileInputStream("bean.xml");
Document doc = db.parse(is);
Document对象代表了一个XML文档的模型树,所有的其他Node都以一定的顺序包含在Document对象之内,排列成一个树状结构,以后对XML文档的所有操作都与解析器无关,直接在这个Document对象上进行操作即可;

Document的方法:



4.节点列表类NodeList
NodeList代表了一个包含一个或者多个Node的列表,根据操作可以将其简化的看做为数组


5.节点类Node
Node对象是DOM中最基本的对象,代表了文档树中的抽象节点。但在实际使用中很少会直接使用Node对象,而是使用Node对象的子对象Element,Attr,Text
6.元素类Element
是Node类最主要的子对象,在元素中可以包含属性,因而Element中有存取其属性的方法




二,使用SAX解析XML

SAX是Simple API for XML的缩写,比DOM速度更快,更有效,占用内存更小。他是逐行扫描,边扫描边解析,流式处理,是基于事件驱动的,就是不用完全解析整个文档,在按内容顺序解析文档过程中,SAX会判断当前读到的字符是否符合XML文件语法的某部分,如果符合,就会触发事件,就是调用一些回调方法

使用SAX解析XML的几个步骤:

1,创建SAXParserFactory对象

2,调用SAXParserFactory的newSAXParser方法创建一个SAXParser对象

3,实例化一个继承DefaultHandler的自定义对象

4,SAXParser对象的parser方法按自定义Handler规则解析xml文档


MyHandler.java

package saxxml;

import java.util.ArrayList;

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

public class MyHandler extends DefaultHandler {

   ArrayList<Person> students;//要返回的对象集合
   StringBuilder sb;
   Person student;
    //当遇到文档开头的时候,即开始解析XML根元素时调用该方法,调用这个方法,可以做一些预处理
	@Override
	public void startDocument() throws SAXException {
		
		
		System.out.println("--startDocument--");
		students=new ArrayList<Person>();//实例化对象
		sb=new StringBuilder();
		
	}
    //当读到开始标签的时,调用这个方法。即开始解析每个元素时都会调用该方法,uri表示命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名,attributes可以得到所有属性,一般读到的标签名在qName
	@Override
	public void startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException {		
		
		System.out.println("--startElement--"+qName);
		
		//如果读到的开始标签是student,就实例化对象,设置id
		if(qName.equals("student")){
			student=new Person();
		    student.setId(new Integer(attributes.getValue("id")));	
		}
		sb.setLength(0);//每次读到开始标签将字符长度设置为0,以便重新开始读取元素内的字符节点
	}
	/*这个方法处理xml文件读到的内容,第一个参数存放文件的内容,注意是xml文件的全部内容早已经在ch中,只是每次调用此函数时start和length会变化,
	 * 后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)可以获取内容
	*/
	@Override
	public void characters(char[] ch,int start,int length) throws SAXException {		
		
		System.out.println("--characters()--"+new String(ch,length)+"start="+start+" length="+length);
		sb.append(new String(ch,length));//将读取到数字符数组追加到builder中
	}
	//遇到结束标签的时候,调用这个方法
	@Override
	public void endElement(String uri,String qName)
			throws SAXException {
		
		
		System.out.println("--endElement--"+qName);
		if(qName.equalsIgnoreCase("name")){
			student.setName(sb.toString());
		}
		else if(qName.equalsIgnoreCase("age")){
			student.setAge(new Integer(sb.toString()));
		}
		else if(qName.equalsIgnoreCase("student")){
			students.add(student);
		}
	}
	//文档结束的时候,调用这个方法,可以做一些善后工作
	@Override
	public void endDocument() throws SAXException {		
		System.out.println("--endDocument--");
	}	  
	//返回对象集合
	 public ArrayList<Person> getList(){
		 return students;
	 }
	
}

Main.java

package saxxml;

import java.io.File;
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;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
             try {
		        //1,创建一个SAXParserFactory对象
				SAXParserFactory factory=SAXParserFactory.newInstance();
				//2,调用SAXParserFactory中的newSAXParser方法创建一个SAXParser对象
				SAXParser parser=factory.newSAXParser();
				MyHandler myhandler=new MyHandler();
				//3,SAXParser对象使用自定义的Handler规则解析xml文件或xml文件流
				parser.parse(new File("students.xml"),myhandler);
				
				
				//遍历返回的对象集合
				ArrayList<Person> list=myhandler.getList();
				for(int i=0;i<list.size();i++){
					System.out.println("ID:"+list.get(i).getId()+" 姓名:"+list.get(i).getName()+" 年龄:"+list.get(i).getAge());
				}
				
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}

}
输出:

--startDocument--
--startElement--students
--characters()--
    start=13 length=5//前面的空格是回车符t.换行符n,空格,的输出
--startElement--student
--characters()--
        start=35 length=9
--startElement--name
--characters()--张珊start=50 length=2
--endElement--name
--characters()--
        start=60 length=9
--startElement--age
--characters()--22start=74 length=2
--endElement--age
--characters()--
    start=83 length=5
--endElement--student
--characters()--
    start=99 length=5
--startElement--student
--characters()--
        start=121 length=9
--startElement--name
--characters()--王航start=136 length=2
--endElement--name
--characters()--
        start=146 length=9
--startElement--age
--characters()--25start=160 length=2
--endElement--age
--characters()--
    start=169 length=5
--endElement--student
--characters()--
    start=185 length=5
--startElement--student
--characters()--
        start=207 length=9
--startElement--name
--characters()--刘沙start=222 length=2
--endElement--name
--characters()--
        start=232 length=9
--startElement--age
--characters()--26start=246 length=2
--endElement--age
--characters()--
    start=255 length=5
--endElement--student
--characters()--
    start=271 length=5
--startElement--student
--characters()--
        start=293 length=9
--startElement--name
--characters()--张海start=308 length=2
--endElement--name
--characters()--
        start=318 length=9
--startElement--age
--characters()--24start=332 length=2
--endElement--age
--characters()--
    start=341 length=5
--endElement--student
--characters()--
start=357 length=1
--endElement--students
--endDocument--
ID:1 姓名:张珊 年龄:22
ID:2 姓名:王航 年龄:25
ID:3 姓名:刘沙 年龄:26
ID:4 姓名:张海 年龄:24

分析:用SAX解析XML采用的是从上而下的基于事件驱动的解析方式,在解析过程中会视情况自动调用startDocument()、startElement()、characters()、endElement()、endDocument()等相关的方法。

由编译执行的结果来看:
1,startDocument()方法只会在文档开始解析的时候被调用,每次解析只会调用一次。,

2,startElement()方法每次在开始解析一个元素,即遇到元素标签开始的时候都会调用
3,characters()方法也是在每次解析到元素标签携带的内容时都会调用,即在startElement调用后,调用characters时读到的内容值,在endElement调用后,调用characters时读到的回车符,换行符和空格即使该元素标签的内容为空或换行。而且如果元素内嵌套元素,在父元素结束标签前, characters()方法会再次被调用,此处需要注意。

4,endElement()方法每次在结束解析一个元素,即遇到元素标签结束的时候都会调用

5,endDocument() startDocument()方法只会在文档解析结束的时候被调用,每次解析只会调用一次。
其实参数char[] ch中早已经加载了文档,每次调用的时候改变的是start,length

[,<,s,t,u,d,e,n,>,i,=,",1,a,m,张,珊,/,g,2,王,航,5,3,刘,沙,6,4,海,

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读