常识:<?为XML的文档开始标签,<为元素开始标签,</为元素结束标签。SAX就是根据<?、<、</、>这几个标签来解析XML的。


  • startDocument()方法只会在文档开始解析的时候遇到<?被调用,故每次解析只会调用一次。
  • startElement()方法每次在开始解析一个元素,即遇到元素标签开始<的时候都会调用。
  • characters()方法也是在每次解析到元素标签携带的内容时都会调用,即使该元素标签的内容为空或换行。而且如果元素内嵌套元素,在父元素结束标签前, characters()方法会再次被调用,此处需要注意。(简单理解,两个标签之间都会调用,当然,这两个标签肯定是紧挨着的两个标签)
  • endElement()方法每次在结束解析一个元素,即遇到元素标签结束</的时候都会调用。
  • endDocument() startDocument()方法只会在文档解析结束的时候被调用,每次解析只会调用一次。

例一:


现F盘有class.xml文件,内容如下:


<?xml version="1.0" encoding="gbk"?>
<class>
    <stu id="001">
       <name>Allen</name>
       <sex>男</sex>
       <age>20</age>
    </stu>
    <stu id="001">
       <name>Allen</name>
       <sex>男</sex>
       <age>20</age>
    </stu>
    <stu id="002">
       <name>namy</name>
       <sex>女</sex>
       <age>18</age>
    </stu>
    <stu id="003">
       <name>lufy</name>
       <sex>男</sex>
       <age>18</age>
     </stu>
</class>


(1)工具类:


package com.school.handler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

public class Myhandler extends DefaultHandler {
	// 存储正在解析的元素的数据
	private Map<String, String> map = null;
	// 存储所有解析的元素的数据
	private List<Map<String, String>> list = null;
	// 正在解析的元素的名字
	String currentTag = null;
	// 正在解析的元素的元素值
	String currentValue = null;
	// 开始解析的元素
	String nodeName = null;

	public Myhandler(String nodeName) {
		// TODO Auto-generated constructor stub
		this.nodeName = nodeName;
	}

	public List<Map<String, String>> getList() {
		return list;
	}

	// 开始解析文档,即开始解析XML根元素时调用该方法
	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		System.out.println("--startDocument()--");
		// 初始化Map
		list = new ArrayList<Map<String, String>>();
	}

	// 开始解析每个元素时都会调用该方法
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		// TODO Auto-generated method stub
		// 判断正在解析的元素是不是开始解析的元素
		System.out.println("--startElement()--" + qName);
		if (qName.equals(nodeName)) {
			map = new HashMap<String, String>();
		}

		// 判断正在解析的元素是否有属性值,如果有则将其全部取出并保存到map对象中,如:<person id=" "></person>
		if (attributes != null && map != null) {
			
			for (int i = 0; i < attributes.getLength(); i++) {
				map.put(attributes.getQName(i), attributes.getValue(i));
				//System.err.println(attributes.getQName(i)+attributes.getValue(i));
			}
		}
		currentTag = qName; // 正在解析的元素
	}

	// 解析到每个元素的内容时会调用此方法
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		// TODO Auto-generated method stub
		System.out.println("--characters()--");
		if (currentTag != null && map != null) {
			currentValue = new String(ch, start, length);
			// 如果内容不为空和空格,也不是换行符则将该元素名和值和存入map中
			if (currentValue != null && !currentValue.trim().equals("") && !currentValue.trim().equals("\n")) {
				map.put(currentTag, currentValue);
				System.out.println("-----" + currentTag + " " + currentValue);
			}
			// 当前的元素已解析过,将其置空用于下一个元素的解析,去掉也对
			//currentTag = null;
			//currentValue = null;
		}
	}

	// 每个元素结束的时候都会调用该方法
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		// TODO Auto-generated method stub
		System.out.println("--endElement()--" + qName);
		// 判断是否为一个节点结束的元素标签
		if (qName.equals(nodeName)) {
			list.add(map);
			
		}
	}

	// 结束解析文档,即解析根元素结束标签时调用该方法
	@Override
	public void endDocument() throws SAXException {
		// TODO Auto-generated method stub
		System.out.println("--endDocument()--");
		super.endDocument();
	}
}



(2)服务应用类:


package com.school.service;

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

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

import com.school.handler.Myhandler;

public class SaxService {

	public static List<Map<String, String>> ReadXML(File uri, String NodeName) {
		try {
			// 创建一个解析XML的工厂对象
			SAXParserFactory parserFactory = SAXParserFactory.newInstance();
			// 创建一个解析XML的对象
			SAXParser parser = parserFactory.newSAXParser();
			// 创建一个解析助手类
			Myhandler myhandler = new Myhandler("stu");
			parser.parse(uri, myhandler);
			return myhandler.getList();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
		return null;

	}
}



(3)测试类:


package com.school.main;

import java.io.File;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.school.service.SaxService;

public class XmlSaxTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		File file=new File("F:"+File.separator+"class.xml");
		ArrayList<Map<String, String>> list = (ArrayList<Map<String, String>>) SaxService
				.ReadXML(file, "class");
		/*
		 * for(int i=0 ;i<list.size();i++){ HashMap<String, String>
		 * temp=(HashMap<String, String>) list.get(i); Iterator<String>
		 * iterator=temp.keySet().iterator(); while(iterator.hasNext()){ String
		 * key=iterator.next().toString(); String value=temp.get(key);
		 * System.out.print(key+" "+value+"--"); } }
		 */
		System.out.println(list.toString());
	}

}



运行,控制台输出如下:


--startDocument()--
 --startElement()--class
 --characters()--
 --startElement()--stu
 --characters()--
 --startElement()--name
 --characters()--
 -----name Allen
 --endElement()--name
 --characters()--
 --startElement()--sex
 --characters()--
 -----sex 男
 --endElement()--sex
 --characters()--
 --startElement()--age
 --characters()--
 -----age 20
 --endElement()--age
 --characters()--
 --endElement()--stu
 --characters()--
 --startElement()--stu
 --characters()--
 --startElement()--name
 --characters()--
 -----name Allen
 --endElement()--name
 --characters()--
 --startElement()--sex
 --characters()--
 -----sex 男
 --endElement()--sex
 --characters()--
 --startElement()--age
 --characters()--
 -----age 20
 --endElement()--age
 --characters()--
 --endElement()--stu
 --characters()--
 --startElement()--stu
 --characters()--
 --startElement()--name
 --characters()--
 -----name namy
 --endElement()--name
 --characters()--
 --startElement()--sex
 --characters()--
 -----sex 女
 --endElement()--sex
 --characters()--
 --startElement()--age
 --characters()--
 -----age 18
 --endElement()--age
 --characters()--
 --endElement()--stu
 --characters()--
 --startElement()--stu
 --characters()--
 --startElement()--name
 --characters()--
 -----name lufy
 --endElement()--name
 --characters()--
 --startElement()--sex
 --characters()--
 -----sex 男
 --endElement()--sex
 --characters()--
 --startElement()--age
 --characters()--
 -----age 18
 --endElement()--age
 --characters()--
 --endElement()--stu
 --characters()--
 --endElement()--class
 --endDocument()--
 [{sex=男, name=Allen, id=001, age=20}, {sex=男, name=Allen, id=001, age=20}, {sex=女, name=namy, id=002, age=18}, {sex=男, name=lufy, id=003, age=18}]


例二、


现F盘有一个book.xml文件:


<?xml version="1.0" encoding="GB2312"?>
<bookstore>
   <book category="COOKING">
     <title lang="en">西游记</title>

     <author>吴承恩</author>

     <year>2005</year>

     <price>30.00</price>

  </book>

 
  <book category="COOKING">

     <title lang="en">水浒传</title>

     <author>施耐庵</author>

     <year>2003</year>

     <price>29.00</price>

   </book>

</bookstore>



现在把每个book解析成一个BookInfo类,用List来保存所有的BookInfo对象。


(1)实体类:


package com.booksax.entity;

import java.io.Serializable;

public class BookInfo implements Serializable{
	private String title;
	private String author;
	private String year;
	private String price;
	private String id;

	@Override
	public String toString() {
		return "BookInfo [title=" + title + ", author=" + author + ", year=" + year + ", price=" + price + ", id=" + id
				+ "]";
	}

	public String getId() {
		return id;
	}

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

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getYear() {
		return year;
	}

	public void setYear(String year) {
		this.year = year;
	}

	public String getPrice() {
		return price;
	}

	public void setPrice(String price) {
		this.price = price;
	}

}



(2)service:


package com.booksax.service;

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

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

import com.booksax.entity.BookInfo;

public class BookInfoSaxService extends DefaultHandler {
	private List<BookInfo> bookList;//最后想要的结果,所有书的集合
	private String preTag;//当前解析的元素名称
	private BookInfo book;
	private String nodeName;//目标标签
	public BookInfoSaxService(String nodeName){
		bookList=new ArrayList<>();
		this.nodeName=nodeName;
	}
	public List<BookInfo> getBookList() {
		return bookList;
	}

	@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 {
		System.out.println("开始解析元素"+qName);
		if(qName.equals(nodeName)){//如果解析到目标标签,new 一个新的BookInfo对象
			book=new BookInfo();
			if(attributes!=null){
				String id=attributes.getValue(0);
				book.setId(id);
			}
		}
		preTag=qName;
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		//System.out.println("结束"+qName);
		if(qName.equals(nodeName)){
			bookList.add(book);
		}
	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		String str=new String(ch, start, length).trim();
		if(str!=null && !str.equals("")){//不是空的时候,说明是文本
			if(preTag.equals("title")){
				//是title标签
				book.setTitle(str);
			}
			if(preTag.equals("author")){
				//是title标签
				book.setAuthor(str);
			}
			if(preTag.equals("year")){
				book.setYear(str);
			}
			if(preTag.equals("price")){
				book.setPrice(str);
			}
		}
	}

}



(3)测试类:


package com.booksax.main;

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

import com.booksax.entity.BookInfo;
import com.booksax.service.BookInfoSaxService;
public class BookManagerXmlTester {
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		SAXParserFactory factory=SAXParserFactory.newInstance();
		SAXParser parser=factory.newSAXParser();
	    File file=new File("F:"+File.separator+"book.xml");
	    BookInfoSaxService service=new BookInfoSaxService("book");
		parser.parse(file, service);
		List<BookInfo> bookList=service.getBookList();
		for(BookInfo book:bookList){
			System.out.println(book);
		}
	}
}



控制台输出如下:


开始解析元素bookstore
 开始解析元素book
 开始解析元素title
 开始解析元素author
 开始解析元素year
 开始解析元素price
 开始解析元素book
 开始解析元素title
 开始解析元素author
 开始解析元素year
 开始解析元素price
 BookInfo [title=西游记, author=吴承恩, year=2005, price=30.00, id=COOKING]
 BookInfo [title=水浒传, author=施耐庵, year=2003, price=29.00, id=COOKING]