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文档时触发了事件回调该类里相应的方法。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.andieguo.saxparserdemo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.xml.sax.Attributes;  
  7. import org.xml.sax.SAXException;  
  8. import org.xml.sax.helpers.DefaultHandler;  
  9.   
  10. public class SaxHandler extends DefaultHandler {  
  11.   
  12.     private List<Book> bookList = null;  
  13.     private Book book = null;  
  14.     private boolean bTitle = false;  
  15.     private boolean bAuthor = false;  
  16.     private boolean bYear = false;  
  17.     private boolean bPrice = false;  
  18.   
  19.     public List<Book> getBookList() {  
  20.         return bookList;  
  21.     }  
  22.   
  23.     @Override  
  24.     public void startDocument() throws SAXException {  
  25.         super.startDocument();  
  26.     }  
  27.   
  28.     @Override  
  29.     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  
  30.         if (qName.equalsIgnoreCase("book")) {  
  31.             String category = attributes.getValue("category");// 获取book元素的Attributes值  
  32.             book = new Book();  
  33.             book.setCategory(category);  
  34.             if (bookList == null) {  
  35.                 bookList = new ArrayList<Book>();  
  36.             }  
  37.         } else if (qName.equalsIgnoreCase("title")) {  
  38.             String titleLang = attributes.getValue("lang");// 获取title元素的Attributes值  
  39.             book.setTitleLang(titleLang);  
  40.             bTitle = true;  
  41.         } else if (qName.equalsIgnoreCase("author")) {  
  42.             bAuthor = true;  
  43.         } else if (qName.equalsIgnoreCase("year")) {  
  44.             bYear = true;  
  45.         } else if (qName.equalsIgnoreCase("price")) {  
  46.             bPrice = true;  
  47.         }  
  48.     }  
  49.   
  50.     @Override  
  51.     public void endElement(String uri, String localName, String qName) throws SAXException {  
  52.         if (qName.equalsIgnoreCase("book")) {  
  53.             bookList.add(book);  
  54.         }  
  55.     }  
  56.   
  57.     @Override  
  58.     public void characters(char[] ch, int start, int length) throws SAXException {  
  59.         if (bTitle) {  
  60.             book.setTitle(new String(ch, start, length));  
  61.             bTitle = false;// 解析完后,必须关闭掉;因为解析到下一个元素Author时characters还会被执行,如果不关闭掉会首先执行进来。  
  62.         } else if (bAuthor) {  
  63.             if (book.getAuthor() == null) {  
  64.                 book.setAuthor(new String(ch, start, length));  
  65.             } else {  
  66.                 book.setAuthor(book.getAuthor() + "/" + new String(ch, start, length));// 解决有多个作者的问题  
  67.             }  
  68.             bAuthor = false;  
  69.         } else if (bYear) {  
  70.             book.setYear(Integer.parseInt(new String(ch, start, length)));  
  71.             bYear = false;  
  72.         } else if (bPrice) {  
  73.             book.setPrice(Double.parseDouble(new String(ch, start, length)));  
  74.             bPrice = false;  
  75.         }  
  76.     }  
  77.   
  78.     @Override  
  79.     public void endDocument() throws SAXException {  
  80.         super.endDocument();  
  81.     }  
  82.   
  83. }  

4)  XMLParserSAX.java:解析XML文件并写入到List<Book>集合,这样做的好处是实现了将任意平台都能处理的XML数据转化为了Java能处理的对象,方便在Java或Android开发中的后续数据处理,比如说:在Android中,从服务器上获取到XML文件,通过该方法解析数据并存入到对象,再将该对象绑定到适配器用于Listview的显示,一种很常用的开发需求。

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.andieguo.saxparserdemo;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.util.List;  
  6.   
  7. import javax.xml.parsers.SAXParser;  
  8. import javax.xml.parsers.SAXParserFactory;  
  9.   
  10. import org.xml.sax.InputSource;  
  11. import org.xml.sax.XMLReader;  
  12.   
  13. public class XMLParserSAX {  
  14.   
  15.     public static void main(String[] args) {  
  16.         //List<Book> books = xmlReader(new File("src/com/andieguo/saxparserdemo/books.xml"));  
  17.         List<Book> books = saxParser(new File("src/com/andieguo/saxparserdemo/books.xml"));  
  18.         for (Book book : books) {  
  19.             System.out.println(book.toString());  
  20.         }  
  21.     }  
  22.     //使用SAXParser来解析   
  23.     public static List<Book> saxParser(File file) {  
  24.         try {  
  25.             // 1.创建解析工厂  
  26.             SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();// 获取单例  
  27.             // 2.得到解析器  
  28.             SAXParser saxParser = saxParserFactory.newSAXParser();  
  29.             // 3.得到内容处理器  
  30.             SaxHandler saxHandler = new SaxHandler();  
  31.             // 4.解析器绑定内容处理器,并解析xml文件  
  32.             saxParser.parse(file, saxHandler);  
  33.             List<Book> books = saxHandler.getBookList();  
  34.             return books;  
  35.         } catch (Exception e) {  
  36.             e.printStackTrace();  
  37.         }  
  38.         return null;  
  39.     }  
  40.     //使用XMLReader 来解析   
  41.     public static List<Book> xmlReader(File file) {  
  42.         try {  
  43.             // 1.新建一个工厂类SAXParserFactory  
  44.             SAXParserFactory factory = SAXParserFactory.newInstance();  
  45.             // 2.让工厂类产生一个SAX的解析类SAXParser  
  46.             SAXParser parser = factory.newSAXParser();  
  47.             // 3.从SAXPsrser中得到一个XMLReader实例  
  48.             XMLReader reader = parser.getXMLReader();  
  49.             // 4.得到内容处理器  
  50.             SaxHandler saxHandler = new SaxHandler();  
  51.             // 5.把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler  
  52.             reader.setContentHandler(saxHandler);  
  53.             // 6.将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始  
  54.             reader.parse(new InputSource(new FileInputStream(file)));  
  55.             List<Book> books = saxHandler.getBookList();  
  56.             return books;  
  57.         } catch (Exception e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.         return null;  
  61.     }  
  62.   
  63. }  

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

实战

1)CreateXMLFile.java:将对象里的数据填充到构建的XML文件中。
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.andieguo.saxparserdemo;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.util.List;  
  6.   
  7. import javax.xml.transform.OutputKeys;  
  8. import javax.xml.transform.Transformer;  
  9. import javax.xml.transform.sax.SAXTransformerFactory;  
  10. import javax.xml.transform.sax.TransformerHandler;  
  11. import javax.xml.transform.stream.StreamResult;  
  12.   
  13. import org.xml.sax.helpers.AttributesImpl;  
  14.   
  15. public class CreateXMLFile {  
  16.   
  17.   
  18.     public static void main(String[] args) {  
  19.         List<Book> books = XMLParserSAX.xmlReader(new File("src/com/andieguo/saxparserdemo/books.xml"));  
  20.         createXML(books);  
  21.           
  22.     }  
  23.   
  24.     public static void createXML(List<Book> books) {  
  25.   
  26.         try {  
  27.             // 创建工厂  
  28.             SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();  
  29.             TransformerHandler handler = factory.newTransformerHandler();  
  30.             Transformer info = handler.getTransformer();  
  31.             // 是否自动添加额外的空白  
  32.             info.setOutputProperty(OutputKeys.INDENT, "yes");  
  33.             // 设置字符编码  
  34.             info.setOutputProperty(OutputKeys.ENCODING, "utf-8");  
  35.             info.setOutputProperty(OutputKeys.VERSION, "1.0");  
  36.             // 保存创建的saxbooks.xml  
  37.             StreamResult result = new StreamResult(new FileOutputStream(new File("src/com/andieguo/saxparserdemo/saxbooks.xml")));  
  38.             handler.setResult(result);  
  39.             // 开始xml  
  40.             handler.startDocument();  
  41.             AttributesImpl impl = new AttributesImpl();  
  42.             impl.clear();  
  43.             handler.startElement("""""bookstore", impl);  
  44.             for(int i=0;i<books.size();i++){  
  45.                 Book book = books.get(i);  
  46.                 //生成<book category="xx">  
  47.                 impl.clear(); //清空属性  
  48.                 impl.addAttribute("""""category""", book.getCategory());//为book元素添加category属性  
  49.                 handler.startElement("""""book", impl);   
  50.                 //生成<title lang="xx">xx</title>元素  
  51.                 impl.addAttribute("""""lang""", book.getTitleLang());//为title元素添加lang属性  
  52.                 handler.startElement("""""title", impl);   
  53.                 String title = book.getTitle();  
  54.                 handler.characters(title.toCharArray(), 0, title.length()); //为title元素添加文本  
  55.                 handler.endElement("""""title");   
  56.                 //生成<author>xx</author>元素  
  57.                 String[] author = book.getAuthor().split("/");  
  58.                 for(int j=0;j<author.length;j++){  
  59.                     impl.clear();   
  60.                     handler.startElement("""""author", impl);   
  61.                     handler.characters(author[j].toCharArray(), 0, author[j].length());   
  62.                     handler.endElement("""""author");   
  63.                 }  
  64.                 //生成<year>xx</year>元素  
  65.                 impl.clear();   
  66.                 handler.startElement("""""year", impl);   
  67.                 String year = book.getYear().toString();  
  68.                 handler.characters(year.toCharArray(), 0, year.length());   
  69.                 handler.endElement("""""year");   
  70.                 //生成<price>xx</price>元素  
  71.                 impl.clear();   
  72.                 handler.startElement("""""price", impl);   
  73.                 String price = book.getPrice().toString();  
  74.                 handler.characters(price.toCharArray(), 0, price.length());   
  75.                 handler.endElement("""""price");   
  76.                 //生成</book>  
  77.                 handler.endElement("""""book");  
  78.             }  
  79.             //生成</bookstore>  
  80.             handler.endElement("""""bookstore");  
  81.             handler.endDocument();  
  82.         } catch (Exception e) {  
  83.             e.printStackTrace();  
  84.         }  
  85.   
  86.     }  
  87.   
  88. }  
2)生成的文件saxbooks.xml

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代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <books>  
  3.     <book id="12">  
  4.         <name>thinking in java</name>  
  5.         <price>85.5</price>  
  6.     </book>  
  7.     <book id="15">  
  8.         <name>Spring in Action</name>  
  9.         <price>39.0</price>  
  10.     </book>  
  11. </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代码  收藏代码
  1. import java.io.InputStream;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4.   
  5. import javax.xml.parsers.SAXParser;  
  6. import javax.xml.parsers.SAXParserFactory;  
  7.   
  8. import org.xml.sax.Attributes;  
  9. import org.xml.sax.SAXException;  
  10. import org.xml.sax.helpers.DefaultHandler;  
  11.   
  12. import com.xtlh.cn.entity.Book;  
  13.   
  14. public class SaxParseService extends DefaultHandler{  
  15.     private List<Book> books = null;  
  16.     private Book book = null;  
  17.     private String preTag = null;//作用是记录解析时的上一个节点名称  
  18.       
  19.     public List<Book> getBooks(InputStream xmlStream) throws Exception{  
  20.         SAXParserFactory factory = SAXParserFactory.newInstance();  
  21.         SAXParser parser = factory.newSAXParser();  
  22.         SaxParseService handler = new SaxParseService();  
  23.         parser.parse(xmlStream, handler);  
  24.         return handler.getBooks();  
  25.     }  
  26.       
  27.     public List<Book> getBooks(){  
  28.         return books;  
  29.     }  
  30.       
  31.     @Override  
  32.     public void startDocument() throws SAXException {  
  33.         books = new ArrayList<Book>();  
  34.     }  
  35.   
  36.     @Override  
  37.     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  
  38.         if("book".equals(qName)){  
  39.             book = new Book();  
  40.             book.setId(Integer.parseInt(attributes.getValue(0)));  
  41.         }  
  42.         preTag = qName;//将正在解析的节点名称赋给preTag  
  43.     }  
  44.   
  45.     @Override  
  46.     public void endElement(String uri, String localName, String qName)  
  47.             throws SAXException {  
  48.         if("book".equals(qName)){  
  49.             books.add(book);  
  50.             book = null;  
  51.         }  
  52.         preTag = null;/**当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法 
  53.         ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图 
  54.         中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方 
  55.         法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。*/  
  56.     }  
  57.       
  58.     @Override  
  59.     public void characters(char[] ch, int start, int length) throws SAXException {  
  60.         if(preTag!=null){  
  61.             String content = new String(ch,start,length);  
  62.             if("name".equals(preTag)){  
  63.                 book.setName(content);  
  64.             }else if("price".equals(preTag)){  
  65.                 book.setPrice(Float.parseFloat(content));  
  66.             }  
  67.         }  
  68.     }  
  69.       
  70. }  

  Book.java如下:主要是用来组装数据

Java代码  收藏代码
  1. public class Book {  
  2.     private int id;  
  3.     private String name;  
  4.     private float price;  
  5.     public int getId() {  
  6.         return id;  
  7.     }  
  8.     public void setId(int id) {  
  9.         this.id = id;  
  10.     }  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17.     public float getPrice() {  
  18.         return price;  
  19.     }  
  20.     public void setPrice(float price) {  
  21.         this.price = price;  
  22.     }  
  23.     @Override  
  24.     public String toString(){  
  25.         return this.id+":"+this.name+":"+this.price;  
  26.     }  
  27. }  

 测试是用的单元测试,测试代码如下:ParseTest

Java代码  收藏代码
  1. import java.io.InputStream;  
  2. import java.util.List;  
  3.   
  4. import junit.framework.TestCase;  
  5.   
  6. import com.xtlh.cn.demo.DomParseService;  
  7. import com.xtlh.cn.demo.SaxParseService;  
  8. import com.xtlh.cn.entity.Book;  
  9.   
  10. public class ParseTest extends TestCase{  
  11.   
  12.     public void testSAX() throws Throwable{  
  13.         SaxParseService sax = new SaxParseService();  
  14.         InputStream input = this.getClass().getClassLoader().getResourceAsStream("book.xml");  
  15.         List<Book> books = sax.getBooks(input);  
  16.         for(Book book : books){  
  17.             System.out.println(book.toString());  
  18.         }  
  19.     }  
  20. }  

 在用Sax解析的时候最需要重视的一点就是不要把那些<节点>之间的空白忽略就好!

出处:http://www.tuicool.com/articles/qiyiQbE

http://www.iteye.com/topic/763895




0 0
原创粉丝点击