【Java编程】SAX XML Parser解析、生成XML文件
1、优缺点
优点:
SAX 从根本上解决了 DOM 在解析 XML 文档时产生的占用大量资源的问题。其实现是通过类似于流解析的技术,通读整个 XML 文档树,通过事件处理器来响应程序员对于 XML 数据解析的需求。由于其不需要将整个 XML 文档读入内存当中,它对系统资源的节省是十分显而易见的,它在一些需要处理大型 XML 文档以及性能要求较高的场合有起了十分重要的作用。支持 XPath 查询的 SAX 使得开发人员更加灵活,处理起 XML 来更加的得心应手。
缺点:
但是同时,其仍然有一些不足之处也困扰广大的开发人员:首先是它十分复杂的 API 接口令人望而生畏,其次由于其是属于类似流解析的文件扫描方式,因此不支持应用程序对于 XML 树内容结构等的修改,可能会有不便之处。
适用范围:
大型 XML 文件解析、只需要部分解析或者只想取得部分 XML 树内容、有 XPath 查询需求、有自己生成特定 XML 树对象模型的需求
2、触发器工作流程
在Sax的解析过程中,读取到文档开头、结尾,元素的开头和结尾都会触发一些回调方法,你可以在这些回调方法中进行相应事件处理这四个方法是:startDocument() 、endDocument()、 startElement()、endElement。此外,我们还需要characters()方法来仔细处理元素内包含的内容将这些回调方法集合起来,便形成了一个触发器类DefaultHandler。一般从Main方法中读取文档,却在触发器中处理文档,这就是所谓的事件驱动解析方法
如上图,在触发器中,首先开始读取文档,然后开始逐个解析元素,每个元素中的内容会返回到characters()方法接着结束元素读取,所有元素读取完后,结束文档解析
DefaultHandler类:
3、SAX解析XML文件
使用XMLReader解析
// 1.新建一个工厂类SAXParserFactory
SAXParserFactory factory =SAXParserFactory.newInstance();
// 2.让工厂类产生一个SAX的解析类SAXParser
SAXParser parser = factory.newSAXParser();
// 3.从SAXPsrser中得到一个XMLReader实例
XMLReader reader = parser.getXMLReader();
// 4.得到内容处理器
SaxHandler saxHandler = new SaxHandler();
// 5.把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler
reader.setContentHandler(saxHandler);
// 6.将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始
reader.parse(newInputSource(new FileInputStream("src/com/andieguo/saxparserdemo/books.xml")));
使用SAXParser解析
// 1.创建解析工厂
SAXParserFactory saxParserFactory =SAXParserFactory.newInstance();// 获取单例
// 2.得到解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
// 3.得到内容处理器
SaxHandler saxHandler = new SaxHandler();
// 4.解析器绑定内容处理器,并解析xml文件
saxParser.parse(new File("src/com/andieguo/saxparserdemo/books.xml"),saxHandler);
实战
1) books.xml(同上一篇【Java编程】DOM XML Parser解析、遍历、创建XML)
2) Book.java(同上一篇【Java编程】DOM XML Parser解析、遍历、创建XML)
3) SaxHandler.java
package com.andieguo.saxparserdemo; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SaxHandler extends DefaultHandler { private List<Book> bookList = null; private Book book = null; private boolean bTitle = false; private boolean bAuthor = false; private boolean bYear = false; private boolean bPrice = false; public List<Book> getBookList() { return bookList; } @Override public void startDocument() throws SAXException { super.startDocument(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equalsIgnoreCase("book")) { String category = attributes.getValue("category");// 获取book元素的Attributes值 book = new Book(); book.setCategory(category); if (bookList == null) { bookList = new ArrayList<Book>(); } } else if (qName.equalsIgnoreCase("title")) { String titleLang = attributes.getValue("lang");// 获取title元素的Attributes值 book.setTitleLang(titleLang); bTitle = true; } else if (qName.equalsIgnoreCase("author")) { bAuthor = true; } else if (qName.equalsIgnoreCase("year")) { bYear = true; } else if (qName.equalsIgnoreCase("price")) { bPrice = true; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equalsIgnoreCase("book")) { bookList.add(book); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (bTitle) { book.setTitle(new String(ch, start, length)); bTitle = false;// 解析完后,必须关闭掉;因为解析到下一个元素Author时characters还会被执行,如果不关闭掉会首先执行进来。 } else if (bAuthor) { if (book.getAuthor() == null) { book.setAuthor(new String(ch, start, length)); } else { book.setAuthor(book.getAuthor() + "/" + new String(ch, start, length));// 解决有多个作者的问题 } bAuthor = false; } else if (bYear) { book.setYear(Integer.parseInt(new String(ch, start, length))); bYear = false; } else if (bPrice) { book.setPrice(Double.parseDouble(new String(ch, start, length))); bPrice = false; } } @Override public void endDocument() throws SAXException { super.endDocument(); } }
4) XMLParserSAX.java
package com.andieguo.saxparserdemo; import java.io.File; import java.io.FileInputStream; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; public class XMLParserSAX { public static void main(String[] args) { //List<Book> books = xmlReader(new File("src/com/andieguo/saxparserdemo/books.xml")); List<Book> books = saxParser(new File("src/com/andieguo/saxparserdemo/books.xml")); for (Book book : books) { System.out.println(book.toString()); } } //使用SAXParser来解析 public static List<Book> saxParser(File file) { try { // 1.创建解析工厂 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();// 获取单例 // 2.得到解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); // 3.得到内容处理器 SaxHandler saxHandler = new SaxHandler(); // 4.解析器绑定内容处理器,并解析xml文件 saxParser.parse(file, saxHandler); List<Book> books = saxHandler.getBookList(); return books; } catch (Exception e) { e.printStackTrace(); } return null; } //使用XMLReader 来解析 public static List<Book> xmlReader(File file) { try { // 1.新建一个工厂类SAXParserFactory SAXParserFactory factory = SAXParserFactory.newInstance(); // 2.让工厂类产生一个SAX的解析类SAXParser SAXParser parser = factory.newSAXParser(); // 3.从SAXPsrser中得到一个XMLReader实例 XMLReader reader = parser.getXMLReader(); // 4.得到内容处理器 SaxHandler saxHandler = new SaxHandler(); // 5.把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler reader.setContentHandler(saxHandler); // 6.将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始 reader.parse(new InputSource(new FileInputStream(file))); List<Book> books = saxHandler.getBookList(); return books; } catch (Exception e) { e.printStackTrace(); } return null; } }
5) 执行该类的main方法,console效果如下:
4、SAX生成XML文件
1)SAXTransformerFactory类
此类扩展了 TransformerFactory 以提供特定于 SAX的工厂方法。它提供两种类型的 ContentHandler,一种用于创建 Transformer,另一种用于创建 Templates 对象。
如果应用程序希望设置转换期间所使用的 XMLReader 的ErrorHandler 或 EntityResolver,那么它应使用 URIResolver 来返回提供了(通过 getXMLReader)对 XMLReader 引用的 SAXSource。
2)TransformerHandler类
侦听 SAX ContentHandler 解析事件,并将它们转换为 Result 的 TransformerHandler
实战
package com.andieguo.saxparserdemo; import java.io.File; import java.io.FileOutputStream; import java.util.List; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.xml.sax.helpers.AttributesImpl; public class CreateXMLFile { public static void main(String[] args) { List<Book> books = XMLParserSAX.xmlReader(new File("src/com/andieguo/saxparserdemo/books.xml")); createXML(books); } public static void createXML(List<Book> books) { try { // 创建工厂 SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler handler = factory.newTransformerHandler(); Transformer info = handler.getTransformer(); // 是否自动添加额外的空白 info.setOutputProperty(OutputKeys.INDENT, "yes"); // 设置字符编码 info.setOutputProperty(OutputKeys.ENCODING, "utf-8"); info.setOutputProperty(OutputKeys.VERSION, "1.0"); // 保存创建的saxbooks.xml StreamResult result = new StreamResult(new FileOutputStream(new File("src/com/andieguo/saxparserdemo/saxbooks.xml"))); handler.setResult(result); // 开始xml handler.startDocument(); AttributesImpl impl = new AttributesImpl(); impl.clear(); handler.startElement("", "", "bookstore", impl); for(int i=0;i<books.size();i++){ Book book = books.get(i); //生成<book category="xx"> impl.clear(); //清空属性 impl.addAttribute("", "", "category", "", book.getCategory());//为book元素添加category属性 handler.startElement("", "", "book", impl); //生成<title lang="xx">xx</title>元素 impl.addAttribute("", "", "lang", "", book.getTitleLang());//为title元素添加lang属性 handler.startElement("", "", "title", impl); String title = book.getTitle(); handler.characters(title.toCharArray(), 0, title.length()); //为title元素添加文本 handler.endElement("", "", "title"); //生成<author>xx</author>元素 String[] author = book.getAuthor().split("/"); for(int j=0;j<author.length;j++){ impl.clear(); handler.startElement("", "", "author", impl); handler.characters(author[j].toCharArray(), 0, author[j].length()); handler.endElement("", "", "author"); } //生成<year>xx</year>元素 impl.clear(); handler.startElement("", "", "year", impl); String year = book.getYear().toString(); handler.characters(year.toCharArray(), 0, year.length()); handler.endElement("", "", "year"); //生成<price>xx</price>元素 impl.clear(); handler.startElement("", "", "price", impl); String price = book.getPrice().toString(); handler.characters(price.toCharArray(), 0, price.length()); handler.endElement("", "", "price"); //生成</book> handler.endElement("", "", "book"); } //生成</bookstore> handler.endElement("", "", "bookstore"); handler.endDocument(); } catch (Exception e) { e.printStackTrace(); } } }
5、参考:
Java SAX Parser Example Tutorial to parseXML to List of Objects
http://www.journaldev.com/1198/java-sax-parser-example-tutorial-to-parse-xml-to-list-of-objects
Java 处理 XML 的三种主流技术及介绍
http://www.ibm.com/developerworks/cn/xml/dm-1208gub/
XML之SAX方式 解析和生成XML文件
http://gejw0623.blog.51cto.com/4532274/1137225
6、小结
花了一天的时间,将常用的解析XML文件的两种方式总结了下,参考了不少blog和资料,总算对DOM XML Parser 和 SAX XML Parser两种解析方式有了个清晰的认识。再次明白懂技术容易,掌握技术难,将技术明明白白写出来难上加难,写blog不仅仅是个记录的过程,更是一种思路的理清过程,因为你要讲的让人听的懂。如果技术是硬实力的话,写的一手好blog是一种软实力。
转载请注明出处:http://blog.csdn.net/andie_guo/article/details/24851077