Java Sax解析xml(轉載)
出處: http://www.iteye.com/topic/763895
1. Java Sax解析是按照xml檔案的順序一步一步的來解析,在解析xml檔案之前,我們要先了解xml檔案的節點的種類,一種是ElementNode,一種是TextNode。如下面的這段book.xml
Xml程式碼- <?xml version="1.0" encoding="UTF-8"?>
- <books>
- <book id="12">
- <name>thinking in java</name>
- <price>85.5</price>
- </
- <book id="15">
- <name>Spring in Action</name>
- <price>39.0</price>
- </
- </books>
其中,像<books>、<book>這種節點就屬於ElementNode,而thinking in java、85.5這種就屬於TextNode。
下面結合一張圖來詳細講解Sax解析。
xml檔案被Sax解析器載入,由於Sax解析是按照xml檔案的順序來解析,當讀入<?xml.....>時,會呼叫startDocument()方法,當讀入<books>的時候,由於它是個ElementNode,所以會呼叫startElement(String uri, String localName, String qName, Attributes attributes) 方法,其中第二個引數就是節點的名稱,注意:由於有些環境不一樣,有時候第二個引數有可能為空,所以可以使用第三個引數,因此在解析前,先呼叫一下看哪個引數能用,第4個引數是這個節點的屬性。這裡我們不需要這個節點,所以從<book>這個節點開始,也就是圖中1的位置,當讀入時,呼叫startElement(....)方法,由於只有一個屬性id,可以通過attributes.getValue(0)來得到,然後在圖中標明2的地方會呼叫characters(char[] ch, int start, int length)方法,不要以為那裡是空白,Sax解析器可不那麼認為,Sax解析器會把它認為是一個TextNode。但是這個空白不是我們想要的資料,我們是想要<name>節點下的文字資訊。這就要定義一個記錄當上一節點的名稱的TAG,在characters(.....)方法中,判斷當前節點是不是name,是再取值,才能取到thinking in java。具體見程式碼:SaxParseService.java
Java程式碼- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.List;
- import javax.xml.parsers.SAXParser;
- import javax.xml.parsers.SAXParserFactory;
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
- import com.xtlh.cn.entity.Book;
- public class SaxParseService extends DefaultHandler{
- private List<Book> books = null;
- private Book book = null;
- private String preTag = null;//作用是記錄解析時的上一個節點名稱
- public List<Book> getBooks(InputStream xmlStream) throws Exception{
- SAXParserFactory factory = SAXParserFactory.newInstance();
- SAXParser parser = factory.newSAXParser();
- SaxParseService handler = new SaxParseService();
- parser.parse(xmlStream, handler);
- return handler.getBooks();
- }
- public List<Book> getBooks(){
- return books;
- }
- @Override
- public void startDocument() throws SAXException {
- books = new ArrayList<Book>();
- }
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
- if("book".equals(qName)){
- book = new Book();
- book.setId(Integer.parseInt(attributes.getValue(0)));
- }
- preTag = qName;//將正在解析的節點名稱賦給preTag
- }
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- if("book".equals(qName)){
- books.add(book);
- book = null;
- }
- preTag = null;/**當解析結束時置為空。這裡很重要,例如,當圖中畫3的位置結束後,會呼叫這個方法
- ,如果這裡不把preTag置為null,根據startElement(....)方法,preTag的值還是book,當文件順序讀到圖
- 中標記4的位置時,會執行characters(char[] ch, int start, int length)這個方法,而characters(....)方
- 法判斷preTag!=null,會執行if判斷的程式碼,這樣就會把空值賦值給book,這不是我們想要的。*/
- }
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- if(preTag!=null){
- String content = new String(ch,start,length);
- if("name".equals(preTag)){
- book.setName(content);
- }else if("price".equals(preTag)){
- book.setPrice(Float.parseFloat(content));
- }
- }
- }
- }
Book.java如下:主要是用來組裝資料
Java程式碼- public class Book {
- private int id;
- private String name;
- private float price;
- 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 float getPrice() {
- return price;
- }
- public void setPrice(float price) {
- this.price = price;
- }
- @Override
- public String toString(){
- return this.id+":"+this.name+":"+this.price;
- }
- }
測試是用的單元測試,測試程式碼如下:ParseTest
Java程式碼- import java.io.InputStream;
- import java.util.List;
- import junit.framework.TestCase;
- import com.xtlh.cn.demo.DomParseService;
- import com.xtlh.cn.demo.SaxParseService;
- import com.xtlh.cn.entity.Book;
- public class ParseTest extends TestCase{
- public void testSAX() throws Throwable{
- SaxParseService sax = new SaxParseService();
- InputStream input = this.getClass().getClassLoader().getResourceAsStream("book.xml");
- List<Book> books = sax.getBooks(input);
- for(Book book : books){
- System.out.println(book.toString());
- }
- }
- }
在用Sax解析的時候最需要重視的一點就是不要把那些<節點>之間的空白忽略就好!