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; public class SaxParseService extends DefaultHandler{ private List<Book> books = null; private Book book = null; private String preTag = null;//作用是記錄解析時的上一個節點名稱 /** * 特殊字符數量很多時方法1顯然不實用此時可用轉義來實現 * < < * > > * & & * ' ' * " " * 即將xml中的特殊文檔全部替換為轉義字符 * 如<name><thinking in java ><name>變成<name><thinking in java><name>。 * 但是對於這種情況解析過程會發生變化不是一次性解析<thinking in java > * 而是分三步先解析<然后是thinking in java然后是> * 因此要注意想要獲得<name>中數據必須要用StringBuffer將這三部分加起來。 * */ StringBuffer sb = new StringBuffer(); 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 { sb.delete(0, sb.length()); //清除字符內容 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); sb.append(ch,start,length);//字符相加 String content =sb.toString(); if("name".equals(preTag)){ book.setName(content); }else if("price".equals(preTag)){ book.setPrice(Float.parseFloat(content)); } } } }
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; } }
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="12"> <name><thing in java ></name> <price>45.0</price> </book> <book id="15"> <name>Spring in Action</name> <price>39.0</price> </book> </books>
采用JUNIT4測試
public class Test { @org.junit.Test 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.getName()); } }}