SAX解析,生成xml文件
来源:互联网 发布:映美620k驱动端口 编辑:程序博客网 时间:2024/05/21 16:23
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:触发器类,里面有各种回调方法,当解析XML文档时触发了事件回调该类里相应的方法。
- 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:解析XML文件并写入到List<Book>集合,这样做的好处是实现了将任意平台都能处理的XML数据转化为了Java能处理的对象,方便在Java或Android开发中的后续数据处理,比如说:在Android中,从服务器上获取到XML文件,通过该方法解析数据并存入到对象,再将该对象绑定到适配器用于Listview的显示,一种很常用的开发需求。
- 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
另一篇:
1. Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。如下面的这段book.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <books>
- <book id="12">
- <name>thinking in java</name>
- <price>85.5</price>
- </book>
- <book id="15">
- <name>Spring in Action</name>
- <price>39.0</price>
- </book>
- </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
- 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如下:主要是用来组装数据
- 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
- 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解析的时候最需要重视的一点就是不要把那些<节点>之间的空白忽略就好!
出处:http://www.tuicool.com/articles/qiyiQbE
http://www.iteye.com/topic/763895
- SAX解析,生成xml文件
- SAX生成xml文件
- sax生成xml文件
- 【Java编程】SAX XML Parser解析、生成XML文件
- 【Java编程】SAX XML Parser解析、生成XML文件
- xml文件解析-SAX
- sax解析xml文件
- SAX解析xml文件
- SAX解析XML文件
- SAX解析XML文件
- SAX解析XML文件
- SAX解析XML文件
- SAX解析xml文件
- SAX解析xml文件
- XML文件解析 sax
- SAX解析xml文件
- SAX解析XML文件
- SAX解析XML文件
- Linux达人计划
- JavaScript是单线程运行的,但是ajax是如何实现的异步函数回调的?
- 用Kryo做EJB序列化的一些小经验
- Feelings in these days about the Student union
- 基于层次分析法的信息安全风险评估量化法的研究报告
- SAX解析,生成xml文件
- web day15 数据库概述,MySQL,SQL语句,数据查询语法DQL
- mysql的安装出现”错误 1067: 进程意外终止”问题的最终解决方案
- XAMPP:"Another web server daemon with SSL is already running"
- 新一代Android渠道打包工具:1000个渠道包只需要5秒
- 【安卓与物联网】Arduino开发板与Android之间通信
- 实验吧 web forms
- 解决library not found for -lPods-AFNetworking问题
- 发布mvc 报错403.14-Forbidden Web 服务器被配置为不列出此目录的内容