上一篇文章中,我们使用了DOM方式解析xml文档,该方式比较符合我们日常思维方式,但是它直接把文档调入内存中,比较耗内存。在这里我们可以用另外一种方式解析xml,这个就是SAX方式。
SAX即是:Simple API for XML。SAX在概念上与DOM完全不同。它不同于DOM的文档驱动,它是事件驱动的,它并不需要读入整个文档,而文档的读入过程也就是SAX的解析过程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方法。
SAX的工作原理:简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
在用SAX解析xml文档时候,在读取到文档开始和结束标签时候就会回调一个事件,在读取到其他节点与内容时候也会回调一个事件。既然涉及到事件,就有事件源,事件处理器。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口
XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接,详细介绍请见下表:
实际上,我们并不需要都继承这4个接口,SDK提供了DefaultHandler类来处理,DefaultHandler类的一些主要事件回调方法如下:
由以上可知,我们需要XmlReader 以及DefaultHandler来配合解析xml。
SAX解析xml的步骤是:
1. 首先,实例化一个SAXParserFactory对象:
SAXParserFactory factory = SAXParserFactory.newInstance();
2. 然后,通过factory对象获得一个SAXParser对象,该对象就称做SAX 解析器:
SAXParser saxParser = factory.newSAXParser();
3. 最后,saxParser对象调用parse方法解析XML文件:
saxParser.parse(File file,DefaultHandler dh)
实例:
books.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <bookstore> 3 <book category="COOKING"> 4 <title lang="en">Everyday Italian</title> 5 <author>Giada De Laurentiis</author> 6 <year>2005</year> 7 <price>30.0</price> 8 </book> 9 <book category="CHILDREN"> 10 <title lang="en">Harry Potter</title> 11 <author>J K. Rowling</author> 12 <year>2005</year> 13 <price>29.99</price> 14 </book> 15 <book category="WEB"> 16 <title lang="en">Learing XML</title> 17 <author>Erik T. Ray</author> 18 <year>2010</year> 19 <price>48.99</price> 20 </book> 21 </bookstore>
Books抽象类:
1 package demo; 2 3 /** 4 * 根据xml “books”文档,新创建Books类 5 * Created by luts on 2015/12/19. 6 */ 7 public class Books { 8 private String category; 9 private String title; 10 private String language; 11 private String author; 12 private String year; 13 private String price; 14 15 public String getCategory() { 16 return category; 17 } 18 19 public void setCategory(String category) { 20 this.category = category; 21 } 22 23 public String getTitle() { 24 return title; 25 } 26 27 public void setTitle(String title) { 28 this.title = title; 29 } 30 31 public String getLanguage() { 32 return language; 33 } 34 35 public void setLanguage(String language) { 36 this.language = language; 37 } 38 39 public String getAuthor() { 40 return author; 41 } 42 43 public void setAuthor(String author) { 44 this.author = author; 45 } 46 47 public String getYear() { 48 return year; 49 } 50 51 public void setYear(String year) { 52 this.year = year; 53 } 54 55 public String getPrice() { 56 return price; 57 } 58 59 public void setPrice(String price) { 60 this.price = price; 61 } 62 }
BooksSAXHandle:
1 package demo; 2 3 4 5 import java.util.ArrayList; 6 7 import org.xml.sax.Attributes; 8 import org.xml.sax.SAXException; 9 import org.xml.sax.helpers.DefaultHandler; 10 11 12 13 public class BookSAXHandler extends DefaultHandler { 14 String value = null; 15 Books book = null; 16 private ArrayList<Books> bookList = new ArrayList<Books>(); 17 public ArrayList<Books> getBookList() { 18 return bookList; 19 } 20 21 int bookIndex = 0; 22 23 //用来标识解析开始 24 @Override 25 public void startDocument() throws SAXException { 26 // TODO Auto-generated method stub 27 super.startDocument(); 28 System.out.println("SAX解析开始"); 29 } 30 31 //用来标识解析结束 32 @Override 33 public void endDocument() throws SAXException { 34 // TODO Auto-generated method stub 35 super.endDocument(); 36 System.out.println("SAX解析结束"); 37 } 38 39 // 解析xml元素 40 @Override 41 public void startElement(String uri, String localName, String qName, 42 Attributes attributes) throws SAXException { 43 //调用DefaultHandler类的startElement方法 44 super.startElement(uri, localName, qName, attributes); 45 if (qName.equals("book")) { 46 bookIndex++; 47 //创建一个book对象 48 book = new Books(); 49 //开始解析book元素的属性 50 System.out.println("======================开始遍历某一本书的内容================="); 51 52 // //已知book元素下属性的名称,根据属性名称获取属性值 53 // String value = attributes.getValue("id"); 54 // System.out.println("book的属性值是:" + value); 55 //不知道book元素下属性的名称以及个数,如何获取属性名以及属性值 56 int num = attributes.getLength(); 57 for(int i = 0; i < num; i++){ 58 System.out.print("book元素的第" + (i + 1) + "个属性名是:" 59 + attributes.getQName(i)); 60 System.out.println("---属性值是:" + attributes.getValue(i)); 61 if (attributes.getQName(i).equals("category")) { 62 book.setCategory(attributes.getValue(i)); 63 } 64 } 65 } 66 67 if (qName.equals("title")){ 68 // 已知title元素下属性的名称,根据属性名获取属性值 69 String lang = attributes.getValue("lang"); 70 System.out.println( "Title的属性值是" + lang); 71 book.setLanguage(lang); 72 } 73 74 else if (!qName.equals("title") && !qName.equals("bookstore")) { 75 System.out.print("节点名是:" + qName + "---"); 76 } 77 } 78 79 @Override 80 public void endElement(String uri, String localName, String qName) 81 throws SAXException { 82 //调用DefaultHandler类的endElement方法 83 super.endElement(uri, localName, qName); 84 //判断是否针对一本书已经遍历结束 85 if (qName.equals("book")) { 86 bookList.add(book); 87 book = null; 88 System.out.println("======================结束遍历某一本书的内容================="); 89 } 90 else if (qName.equals("title")) { 91 book.setTitle(value); 92 93 } 94 else if (qName.equals("author")) { 95 book.setAuthor(value); 96 } 97 else if (qName.equals("year")) { 98 book.setYear(value); 99 } 100 else if (qName.equals("price")) { 101 book.setPrice(value); 102 } 103 else if (qName.equals("lang")) { 104 book.setLanguage(value); 105 } 106 } 107 108 109 @Override 110 public void characters(char[] ch, int start, int length) 111 throws SAXException { 112 // TODO Auto-generated method stub 113 super.characters(ch, start, length); 114 value = new String(ch, start, length); 115 if (!value.trim().equals("")) { 116 System.out.println("节点值是:" + value); 117 } 118 } 119 }
测试解析
1 package demo; 2 /** 3 * 使用SAX解析xml文档 4 * Created by luts on 2015/12/19. 5 */ 6 7 import java.io.IOException; 8 import javax.xml.parsers.ParserConfigurationException; 9 import javax.xml.parsers.SAXParser; 10 import javax.xml.parsers.SAXParserFactory; 11 import org.xml.sax.SAXException; 12 13 public class SAXTest { 14 public static void main(String[] args){ 15 //创建SAXParserFactory实例、 16 SAXParserFactory factory = SAXParserFactory.newInstance(); 17 // String xmlPath = "books.xml"; 18 try { 19 SAXParser SAXparser = factory.newSAXParser(); 20 21 //获取事件源 22 // XMLReader xmlReader = SAXparser.getXMLReader(); 23 //设置处理器,创建一个SAXParserHandler 24 BookSAXHandler handler = new BookSAXHandler(); 25 26 // InputStream inputStream = new FileInputStream(new File(xmlPath)); 27 28 SAXparser.parse("books.xml", handler); 29 System.out.println("----开始解析某一本书的" + handler.getBookList().size() 30 + " 个属性-------"); 31 for (Books book : handler.getBookList()){ 32 System.out.println(book.getCategory()); 33 System.out.println(book.getTitle()); 34 System.out.println(book.getLanguage()); 35 System.out.println(book.getAuthor()); 36 System.out.println(book.getYear()); 37 System.out.println(book.getPrice()); 38 System.out.println("----结束属性解析-----"); 39 } 40 } 41 catch (ParserConfigurationException e){ 42 e.printStackTrace(); 43 } 44 catch (SAXException e){ 45 e.printStackTrace(); 46 } 47 catch (IOException e){ 48 e.printStackTrace(); 49 } 50 } 51 }
SAX解析开始 ======================开始遍历某一本书的内容================= book元素的第1个属性名是:category---属性值是:COOKING 节点名是:book---Title的属性值是en 节点值是:Everyday Italian 节点名是:author---节点值是:Giada De Laurentiis 节点名是:year---节点值是:2005 节点名是:price---节点值是:30.0 ======================结束遍历某一本书的内容================= ======================开始遍历某一本书的内容================= book元素的第1个属性名是:category---属性值是:CHILDREN 节点名是:book---Title的属性值是en 节点值是:Harry Potter 节点名是:author---节点值是:J K. Rowling 节点名是:year---节点值是:2005 节点名是:price---节点值是:29.99 ======================结束遍历某一本书的内容================= ======================开始遍历某一本书的内容================= book元素的第1个属性名是:category---属性值是:WEB 节点名是:book---Title的属性值是en 节点值是:Learing XML 节点名是:author---节点值是:Erik T. Ray 节点名是:year---节点值是:2010 节点名是:price---节点值是:48.99 ======================结束遍历某一本书的内容================= SAX解析结束 ----开始解析某一本书的3 个属性------- COOKING Everyday Italian en Giada De Laurentiis 2005 30.0 ----结束属性解析----- CHILDREN Harry Potter en J K. Rowling 2005 29.99 ----结束属性解析----- WEB Learing XML en Erik T. Ray 2010 48.99 ----结束属性解析-----