Java解析XML(二)——通过SAX方式解析XML

              在上篇文章里,我介绍了如何通过DOM的方法解析XML文件,但是呢,用DOM解析XML太过繁琐,这里我们用另外一种更简洁的方式——SAX,来解析XML文件

            

              通过SAX方式解析XML步骤如下:

              1,获取SAXParserFactory实例

              SAXParserFactory saxFactory = SAXParserFactory.newInstance();

              2,通过SAXParserFactory实例获取SAXParser实例

              SAXParser parser= saxFactory.newSAXParser();

              3,创建一个handler对象,通过parse(uri, dh)方法传入一个handler对象来解析xml

              parser.parse("books.xml",new DefaultHandler);


              这里传入的handler是一个DefaultHandler对象,在本实例中我们自己写一个类(MySAXParserHandler)通过继承DefaultHandler并实现其中的一些必要的方法来解析XML

              

              再解析的同时,我们再写一个Book实体类,用来保存xml数据的结构        

              Book类

             

package xml.sax.entity;

/**
 * Book实体类,用来保存xml数据的结构
 * @author Lowp
 *
 */
public class Book {
	
	private String id;
	private String name;
	private String author;
	private String year;
	private String price;
	private String language;
	
	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 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;
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

}


              MySAXParserHandler类代码:

             

package xml.sax.handler;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.events.StartElement;

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

import xml.sax.entity.Book;

public class MySAXParserHandler extends DefaultHandler {
	
	int bookIndex = 0; //用来记录book标签中属性的索引值
	String nodeValue = null; 
	Book book = new Book();
	private ArrayList<Book> bookList = new ArrayList<Book>();
	
	


	/**
	 * 用来标识解析开始
	 */
	public void startDocument() throws SAXException {
		super.startDocument();
		System.out.println("SAX解析XML开始");
		
	}
	
	
	
	
	/**
	 * 用来标识解析结束
	 */
	public void endDocument() throws SAXException {
		super.endDocument();
		System.out.println("SAX解析XML结束");
	}
		
	
	
	/**
	 * 用来遍历xml的开始标签
	 * qName:标签名(节点名)
	 * 
	 */
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		super.startElement(uri, localName, qName, attributes);
		
		
		//如果解析到book标签,开始解析book标签的属性
		if(qName.equals("book")){
			System.out.println("================第"+ bookIndex + "本书遍历开始================" );
			bookIndex++;
			
			//创建一个book对象
			book = new Book();
			
			
//			/**
//			 * 【1】已知book标签下属性的名称和个数,通过属性名获取对应的属性值
//			 */
//			String value = attributes.getValue("id");
//			System.out.println("book标签“id”属性的属性值是" + value);
			
			/**
			 * 【2】不知道book标签下属性的名称和个数,
			 */
			//获取book标签中,属性的个数
			int valueSum = attributes.getLength();
			
			for (int i = 0; i < valueSum; i++) {
				//通过索引值获取对应的属性名
				String valueName = attributes.getQName(i);
				System.out.print("book标签的第" + (i+1) + "个属性名是:" + valueName);
				//通过索引值获取对应的属性值
				String value = attributes.getValue(i);
				System.out.println("--->属性值为:" + value);
				
				//将数据保存到Book实体类中
				if(valueName.equals("id")){
					book.setId(value);
				}
				
			}
			
			//
		}else if(!qName.equals("bookstore") && !qName.equals("book")){
			System.out.print("节点名:" + qName);
		}
		
	}
	
	
	
	/**
	 * 用来遍历xml的结束标签
	 */
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		super.endElement(uri, localName, qName);
		
		if(qName.equals("book")){
			//将遍历完的书保存到list中
			bookList.add(book);
			//清空book,开始下一次遍历
			book = null;
			System.out.println("================第"+ bookIndex + "本书遍历结束================" + "\n");
		}else if(qName.equals("name")){
			book.setName(nodeValue);
		}
		else if(qName.equals("author")){
			book.setAuthor(nodeValue);
		}
		else if(qName.equals("year")){
			book.setYear(nodeValue);
		}
		else if(qName.equals("price")){
			book.setPrice(nodeValue);
		}
		else if(qName.equals("language")){
			book.setLanguage(nodeValue);
		}
		
		
		
	}
	
	
	/**
	 * 
	 * char[] ch:整个xml文本内容
	 * int start:开始标签后的第一个位置
	 * int length:开始标签后的第一个位置到结束标签间的片段
	 */
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		super.characters(ch, start, length);
		//获取节点值
		nodeValue = new String(ch, start, length);
		//去空格换行
		if(!nodeValue.trim().equals("")){
			
			System.out.println("--->节点值:" + nodeValue);
		}
		
	}


	
	
	public ArrayList<Book> getBookList() {
		return bookList;
	}
	
	
}

             具体的各个方法有什么用处,我已经在注释中写的很详细了,在这里我想重点说一下
                  public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)  throws SAXException {}
   
             可能对于初学者,很多人都会困惑这个方法在什么时候会被调用,这里我们用一个小小例子来帮大家理解
 

             首先,我们先创建一个简单的XML文件
            
             (1) sax 标签的内容为空
<?xml version="1.0" encoding="UTF-8" ?>
<sax></sax>

            然后在 public void characters(char[] ch, int start, int length)方法中:
           
......
 public void characters(char[] ch, int start, int length)
   throws SAXException {

  System.out.println("run.....");
  System.out.print(new String(ch,start,length));
 }
......

           运行结果:
          
            characters 方法不执行

               

           (2)sax 标签的内容为一个空字符串

            .......

            <sax> </sax>

            ......

            运行结果:

            run ......

            characters方法执行一次

         

           (3)有嵌套子标签

             <sax>
                 <name>123</name>
            </sax>

            

             分析:

             当解析到<sax> 时候,

             遇到一个位于 sax 与 name 标签之间的“回车符”

             characters 被执行,输出 run ...

             遇到“123”的时候被执行 输出 “run .... 123”

             遇到</name> 与 </sax> 之间的回车符 输出 “run..... ”


            

             运行结果:

             run .....

             run ..... 123

             run ......

            characters 方法执行三次

          

            总结:<></>  之间遇到任何 "回车符" "空格符"或其他"不为空"的字符都将触发characters 方法



            测试类:

           

package xml.sax.test;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.sun.xml.internal.ws.api.ha.HaInfo;

import xml.sax.entity.Book;
import xml.sax.handler.MySAXParserHandler;

/**
 * 通过SAX方式解析xml文件
 */
public class SAXTest {
	public static void main(String[] args) {
		/**
		 * 1.获取SAXParserFactory实例
		 */
		SAXParserFactory saxFactory = SAXParserFactory.newInstance();
		
		try {
			/**
			 * 2.通过SAXParserFactory实例获取SAXParser实例(工厂模式)
			 */
			 SAXParser parser= saxFactory.newSAXParser();
			/**
			 * 3.创建一个handler对象,通过parse(uri, dh)方法传入一个handler对象来解析xml
			 */
			 
			 MySAXParserHandler handler = new MySAXParserHandler();
			 parser.parse("books.xml",handler);
			 parser.parse(uri,new DefaultHandler())
			 
			 System.out.println("共有" + handler.getBookList().size() + "本书" + "\n");
			 
			 for (Book book : handler.getBookList()) {
				 System.out.println("Id:" + book.getId());
				 System.out.println("Language:" + book.getLanguage());
				 System.out.println("Name:" + book.getName());
				 System.out.println("Price:" + book.getPrice());
				 System.out.println("Year:" + book.getYear());
				 System.out.println("Author:" + book.getAuthor());
				 System.out.println("======finish======");
			}
			 
			 
			
		} 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开始
================第0本书遍历开始================
book标签的第1个属性名是:id--->属性值为:1
节点名:name--->节点值:冰与火之歌
节点名:author--->节点值:乔治马丁
节点名:year--->节点值:2014
节点名:price--->节点值:89
================第1本书遍历结束================

================第1本书遍历开始================
book标签的第1个属性名是:id--->属性值为:2
节点名:name--->节点值:安徒生童话
节点名:year--->节点值:2004
节点名:price--->节点值:77
节点名:language--->节点值:English
================第2本书遍历结束================

SAX解析XML结束
共有2本书

Id:1
Language:null
Name:冰与火之歌
Price:89
Year:2014
Author:乔治马丁
======finish======
Id:2
Language:English
Name:安徒生童话
Price:77
Year:2004
Author:null
======finish======

          


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值