加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

SAX解析,生成xml文件

发布时间:2020-12-16 05:52:11 所属栏目:百科 来源:网络整理
导读:1、优缺点 优点: SAX 从根本上解决了 DOM 在解析 XML 文档时产生的占用大量资源的问题。其实现是 通过类似于流解析的技术,通读整个 XML 文档树,通过事件处理器来响应程序员对于 XML 数据解析的需求 。由于其不需要将整个 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:触发器类,里面有各种回调方法,当解析XML文档时触发了事件回调该类里相应的方法。

[java] view plain copy
  1. packagecom.andieguo.saxparserdemo;
  2. importjava.util.ArrayList;
  3. importjava.util.List;
  4. importorg.xml.sax.Attributes;
  5. importorg.xml.sax.SAXException;
  6. importorg.xml.sax.helpers.DefaultHandler;
  7. publicclassSaxHandlerextendsDefaultHandler{
  8. privateList<Book>bookList=null;
  9. privateBookbook=null;
  10. privatebooleanbTitle=false;
  11. booleanbAuthor=false;
  12. booleanbYear=booleanbPrice=publicList<Book>getBookList(){
  13. returnbookList;
  14. }
  15. @Override
  16. voidstartDocument()throwsSAXException{
  17. super.startDocument();
  18. }
  19. @Override
  20. voidstartElement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{
  21. if(qName.equalsIgnoreCase("book")){
  22. Stringcategory=attributes.getValue("category");//获取book元素的Attributes值
  23. book=newBook();
  24. book.setCategory(category);
  25. if(bookList==null){
  26. bookList=newArrayList<Book>();
  27. }elseif(qName.equalsIgnoreCase("title")){
  28. StringtitleLang=attributes.getValue("lang");//获取title元素的Attributes值
  29. book.setTitleLang(titleLang);
  30. bTitle=true;
  31. if(qName.equalsIgnoreCase("author")){
  32. bAuthor=if(qName.equalsIgnoreCase("year")){
  33. bYear=if(qName.equalsIgnoreCase("price")){
  34. bPrice=voidendElement(Stringuri,StringqName) bookList.add(book);
  35. voidcharacters(char[]ch,intstart,153); font-weight:bold; background-color:inherit">intlength)if(bTitle){
  36. book.setTitle(newString(ch,start,length));
  37. bTitle=false;//解析完后,必须关闭掉;因为解析到下一个元素Author时characters还会被执行,如果不关闭掉会首先执行进来。
  38. }if(bAuthor){
  39. if(book.getAuthor()==null){
  40. book.setAuthor(else{
  41. book.setAuthor(book.getAuthor()+"/"+//解决有多个作者的问题
  42. if(bYear){
  43. book.setYear(Integer.parseInt( bYear=if(bPrice){
  44. book.setPrice(Double.parseDouble(voidendDocument()super.endDocument();
  45. }

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

copy
importjava.io.File;
  • importjava.io.FileInputStream;
  • importjava.util.List;
  • importjavax.xml.parsers.SAXParser;
  • importjavax.xml.parsers.SAXParserFactory;
  • importorg.xml.sax.InputSource;
  • importorg.xml.sax.XMLReader;
  • classXMLParserSAX{
  • staticvoidmain(String[]args){
  • //List<Book>books=xmlReader(newFile("src/com/andieguo/saxparserdemo/books.xml"));
  • List<Book>books=saxParser(newFile("src/com/andieguo/saxparserdemo/books.xml"));
  • for(Bookbook:books){
  • System.out.println(book.toString());
  • //使用SAXParser来解析
  • staticList<Book>saxParser(Filefile){
  • try{
  • //1.创建解析工厂
  • SAXParserFactorysaxParserFactory=SAXParserFactory.newInstance();//获取单例
  • //2.得到解析器
  • SAXParsersaxParser=saxParserFactory.newSAXParser();
  • //3.得到内容处理器
  • SaxHandlersaxHandler=newSaxHandler();
  • //4.解析器绑定内容处理器,并解析xml文件
  • saxParser.parse(file,saxHandler);
  • List<Book>books=saxHandler.getBookList();
  • returnbooks;
  • catch(Exceptione){
  • e.printStackTrace();
  • return//使用XMLReader来解析
  • staticList<Book>xmlReader(Filefile){
  • //1.新建一个工厂类SAXParserFactory
  • SAXParserFactoryfactory=SAXParserFactory.newInstance();
  • //2.让工厂类产生一个SAX的解析类SAXParser
  • SAXParserparser=factory.newSAXParser();
  • //3.从SAXPsrser中得到一个XMLReader实例
  • XMLReaderreader=parser.getXMLReader();
  • //4.得到内容处理器
  • //5.把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler
  • reader.setContentHandler(saxHandler);
  • //6.将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始
  • reader.parse(newInputSource(newFileInputStream(file)));
  • }
  • 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
    1. packagecom.andieguo.saxparserdemo;
    2. importjava.io.File;
    3. importjava.io.FileOutputStream;
    4. importjava.util.List;
    5. importjavax.xml.transform.OutputKeys;
    6. importjavax.xml.transform.Transformer;
    7. importjavax.xml.transform.sax.SAXTransformerFactory;
    8. importjavax.xml.transform.sax.TransformerHandler;
    9. importjavax.xml.transform.stream.StreamResult;
    10. importorg.xml.sax.helpers.AttributesImpl;
    11. classCreateXMLFile{
    12. voidmain(String[]args){
    13. List<Book>books=XMLParserSAX.xmlReader(newFile("src/com/andieguo/saxparserdemo/books.xml"));
    14. createXML(books);
    15. }
    16. voidcreateXML(List<Book>books){
    17. try{
    18. //创建工厂
    19. SAXTransformerFactoryfactory=(SAXTransformerFactory)SAXTransformerFactory.newInstance();
    20. TransformerHandlerhandler=factory.newTransformerHandler();
    21. Transformerinfo=handler.getTransformer();
    22. //是否自动添加额外的空白
    23. info.setOutputProperty(OutputKeys.INDENT,"yes");
    24. //设置字符编码
    25. info.setOutputProperty(OutputKeys.ENCODING,"utf-8");
    26. info.setOutputProperty(OutputKeys.VERSION,"1.0");
    27. //保存创建的saxbooks.xml
    28. StreamResultresult=newStreamResult(newFileOutputStream(newFile("src/com/andieguo/saxparserdemo/saxbooks.xml")));
    29. handler.setResult(result);
    30. //开始xml
    31. handler.startDocument();
    32. AttributesImplimpl=newAttributesImpl();
    33. impl.clear();
    34. handler.startElement("","","bookstore",impl);
    35. for(inti=0;i<books.size();i++){
    36. Bookbook=books.get(i);
    37. //生成<bookcategory="xx">
    38. impl.clear();//清空属性
    39. impl.addAttribute("","category",book.getCategory());//为book元素添加category属性
    40. "book",0); background-color:inherit">//生成<titlelang="xx">xx</title>元素
    41. impl.addAttribute("","lang",book.getTitleLang());//为title元素添加lang属性
    42. handler.startElement("","title",impl);
    43. Stringtitle=book.getTitle();
    44. handler.characters(title.toCharArray(),0,title.length());//为title元素添加文本
    45. handler.endElement("","title");
    46. //生成<author>xx</author>元素
    47. String[]author=book.getAuthor().split("/");
    48. intj=0;j<author.length;j++){
    49. impl.clear();
    50. "author",108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> handler.characters(author[j].toCharArray(),author[j].length());
    51. handler.endElement("","author");
    52. }
    53. //生成<year>xx</year>元素
    54. "year",108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> Stringyear=book.getYear().toString();
    55. handler.characters(year.toCharArray(),year.length());
    56. "year");
    57. //生成<price>xx</price>元素
    58. "price",108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> Stringprice=book.getPrice().toString();
    59. handler.characters(price.toCharArray(),price.length());
    60. "price");
    61. //生成</book>
    62. "book");
    63. //生成</bookstore>
    64. "bookstore");
    65. handler.endDocument();
    66. catch(Exceptione){
    67. e.printStackTrace();
    68. }
    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://www.52php.cn/article/p-ckzzmezm-ca.html

    6、小结

    花了一天的时间,将常用的解析XML文件的两种方式总结了下,参考了不少blog和资料,总算对DOM XML Parser 和 SAX XML Parser两种解析方式有了个清晰的认识。再次明白懂技术容易,掌握技术难,将技术明明白白写出来难上加难,写blog不仅仅是个记录的过程,更是一种思路的理清过程,因为你要讲的让人听的懂。如果技术是硬实力的话,写的一手好blog是一种软实力。

    转载请注明出处:http://www.52php.cn/article/p-xbotzfgt-xp.html



    另一篇:

    1. Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。如下面的这段book.xml

    Xml代码
    1. <?xmlversion="1.0"encoding="UTF-8"?>
    2. <books>
    3. bookid="12"name>thinkinginjava</price>85.5bookbookid="15">SpringinAction>39.0>

    其中,像<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代码
      importjava.io.InputStream;
    1. importjava.util.ArrayList;
    2. importjava.util.List;
    3. importjavax.xml.parsers.SAXParser;
    4. importjavax.xml.parsers.SAXParserFactory;
    5. importorg.xml.sax.Attributes;
    6. importorg.xml.sax.SAXException;
    7. importorg.xml.sax.helpers.DefaultHandler;
    8. importcom.xtlh.cn.entity.Book;
    9. publicclassSaxParseServiceextendsDefaultHandler{
    10. privateList<Book>books=null;
    11. privateBookbook=privateStringpreTag=null;//作用是记录解析时的上一个节点名称
    12. publicList<Book>getBooks(InputStreamxmlStream)throwsException{
    13. SAXParserFactoryfactory=SAXParserFactory.newInstance();
    14. SAXParserparser=factory.newSAXParser();
    15. SaxParseServicehandler=newSaxParseService();
    16. parser.parse(xmlStream,handler);
    17. returnhandler.getBooks();
    18. }
    19. publicList<Book>getBooks(){
    20. returnbooks;
    21. @Override
    22. voidstartDocument()throwsSAXException{
    23. books=newArrayList<Book>();
    24. voidstartElement(Stringuri,Attributesattributes)if("book".equals(qName)){
    25. book=newBook();
    26. book.setId(Integer.parseInt(attributes.getValue(0)));
    27. preTag=qName;//将正在解析的节点名称赋给preTag
    28. voidendElement(Stringuri,StringqName)
    29. books.add(book);
    30. preTag=/**当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法
    31. ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图
    32. 中标记4的位置时,会执行characters(char[]ch,intstart,intlength)这个方法,而characters(....)方
    33. 法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。*/
    34. voidcharacters(char[]ch,intstart,85); font-weight:bold">intlength)if(preTag!=null){
    35. Stringcontent=newString(ch,length);
    36. if("name".equals(preTag)){
    37. book.setName(content);
    38. }elseif("price".equals(preTag)){
    39. book.setPrice(Float.parseFloat(content));
    40. }

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

    classBook{
  • privateintid;
  • privateStringname;
  • floatprice;
  • intgetId(){
  • returnid;
  • voidsetId(intid){
  • this.id=id;
  • publicStringgetName(){
  • returnname;
  • voidsetName(Stringname){
  • this.name=name;
  • floatgetPrice(){
  • returnprice;
  • voidsetPrice(floatprice){
  • this.price=price;
  • publicStringtoString(){
  • returnthis.id+":"+this.name+":"+this.price;
  • 测试是用的单元测试,测试代码如下:ParseTest

    importjunit.framework.TestCase;
  • importcom.xtlh.cn.demo.DomParseService;
  • importcom.xtlh.cn.demo.SaxParseService;
  • classParseTestextendsTestCase{
  • voidtestSAX()throwsThrowable{
  • SaxParseServicesax= InputStreaminput=this.getClass().getClassLoader().getResourceAsStream("book.xml");
  • List<Book>books=sax.getBooks(input);
  • for(Bookbook:books){
  • System.out.println(book.toString());
  • 在用Sax解析的时候最需要重视的一点就是不要把那些<节点>之间的空白忽略就好!

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

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

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    • 推荐文章
        热点阅读