1 sax 解析 xml
     SAX是Simple API for XML的缩写,它并不是由W3C官方所提出的标准,虽然如此,使用SAX的还是不少,几乎所有的XML解析器都会支持它。与DOM比较而言,SAX是一种轻量型的方法。我们知道,在处理DOM的时候,我们需要读入整个的XML文档,然后在内存中创建DOM树,生成DOM树上
的每个Node对象。当文档比较小的时候,这不会造成什么问题,但是一旦文档大起来,处理DOM就会变得相当费时费力。特别是其对于内存的需求,也将是成
倍的增长,以至于在某些应用中使用DOM是一件很不划算的事(比如在applet中)。这时候,一个较好的替代解决方法就是SAX。
2  事件驱动机制
      SAX 解析xml原理SAX在概念上与DOM完全不同。首先,不同于DOM的文档驱动,它是事件驱动的,也就是说,它并不需要读 入整个文档, 而文档的读入 过程也就 是SAX的解析过 程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方 法。在XMLReader接 受XML文档,在读 入XML文档的过程中 就进行解析,也就是 说读入文 档的过程 和解析 的过 程是同时进行的,这和DOM区别很大.解析开始之前,需要向XMLReader注册一ContentHandler,也就是相当于一个事件监听器,在ContentHandler中定义了很多方法,比如startDocument(),它定制了当在解析过程中,遇到文档开始时应该处理的事情。当XMLREADER读到合 适的内容,就会抛出相应的事件,并把这个事件的处理权代理给ContentHandler, 调用其相应的方法进行响应。xml文件被Sax解析器载入,由于Sax解析是按照xml文件的顺序来解析,当读入<?xml.....>时,会调用
startDocument()方法,当读入<books>的时候,由于它是个ElementNode,所以会调用
startElement(String uri, String localName, String qName, Attributes 
attributes) 方法,其中第二个参数就是节点的名称,注意:由于
有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用,第4个参数是这个节点的属性。这里我们
不需要这个节点,所以从<book>这个节点开始,也就是图中1的位置,当读入时,调用startElement(....)方法,由于只有
一个属性category,可以通过attributes.getValue(0)来得到,然后在图中标明2的地方会调用characters(char[] ch,
 int start, int 
length)方法,不要以为那里是空白,Sax解析器可不那么认为,Sax解析器会把它认为是一个TextNode。但是这个空白不是我们想要的数据,
我们是想要<title>节点下的文本信息。这就要定义一个记录当上一节点的名称的TAG,在characters(.....)方法中,判断
当前节点是不是title,是再取值,才能取到Everyday Italian。
Java代码  。

3 具体代码
Book.java类
package com.wnq.sk.saxXML01;
import java.util.Set;
public class Book
{
    // 与books.xml中的节点对应
    private String category;
    private String titleLang;
    private String title;
    
    private Set<String> author;// 用sax解析,auther是一个集合,因为一本书可能有读个作者
    private Integer year;
    private Double price;
    
    @Override
    public String toString()
    {
        return "Book [category=" + category + ", titleLang=" + titleLang + ", title=" + title + ", author=" + author
            + ", year=" + year + ", price=" + price + "]";
    }
    public Set<String> getAuthor()
    {
        return author;
    }
    
    public void setAuthor(Set<String> author)
    {
        this.author = author;
    }
    public String getCategory()
    {
        return category;
    }
    
    public void setCategory(String category)
    {
        this.category = category;
    }
    
    public String getTitleLang()
    {
        return titleLang;
    }
    
    public void setTitleLang(String titleLang)
    {
        this.titleLang = titleLang;
    }
    
    public String getTitle()
    {
        return title;
    }
    
    public void setTitle(String title)
    {
        this.title = title;
    }
    
    public Integer getYear()
    {
        return year;
    }
    
    public void setYear(Integer year)
    {
        this.year = year;
    }
    
    public Double getPrice()
    {
        return price;
    }
    
    public void setPrice(Double price)
    {
        this.price = price;
    }
}
解析xml类 SaxReadXMLFile.java
package com.wnq.sk.saxXML01;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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;
public class SaxReadXMLFile extends DefaultHandler
{
    private List<Book> books = null;
    private Book book = null;
    private Set<String> authors = null;
    private String author = null;
    private String preTag = null;// 记录解析时的上一个节点名称    
    public List<Book> getBooks(String fileName)
        throws Exception
    {
        SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
        SAXParser parser = sParserFactory.newSAXParser();
        SaxReadXMLFile saxReadXMLFile = new SaxReadXMLFile();
        parser.parse(fileName, saxReadXMLFile);
        return saxReadXMLFile.getBooks();
        
    }
    private List<Book> getBooks()
    {
        return books;
    }
    // 开始解析文档
    public void startDocument()
        throws SAXException
    {
        books = new ArrayList<Book>();
        authors = new HashSet<String>();
    }
    // 解析文档结束
    public void endDocument()
        throws SAXException
    {
        System.out.println("文档解析完毕!");
    }
    
    // 开始解析元素
    public void startElement(String uri, String localName, String qName, Attributes attributes)
        throws SAXException
    {
        if ("book".equals(qName))
        {
            book = new Book();
            book.setCategory(attributes.getValue(0));
        }
        if (book != null && "title".equals(qName))
        {
            book.setTitleLang(attributes.getValue("lang"));
        }
        preTag = qName;// 将正在解析的节点名称赋给preTag
    }   
    // 解析元素结束
    public void endElement(String uri, String localName, String qName)
        throws SAXException
    {
        if (book != null && "book".equals(qName))
        {
            books.add(book);
            book.setAuthor(authors);
            book = null;
            authors = new HashSet<String>();
        }
        if (author != null && "author".equals(qName))
        {
            authors.add(author);
            author = null;
        }
        preTag = null;
        /**
         * 当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法 ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图
         * 中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方
         * 法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。
         */
    }  
    public void characters(char[] ch, int start, int length)
        throws SAXException
    {
        if (preTag != null)
        {
            String content = new String(ch, start, length);
            if ("title".equals(preTag))
            {
                book.setTitle(content);
            }
            
            else if ("author".equals(preTag))
            {
                author = content;
            }
            else if ("year".equals(preTag))
            {
                book.setYear(Integer.valueOf(content));
            }
            else if ("price".equals(preTag))
            {
                book.setPrice(Double.valueOf(content));
            }
        }
    }
}测试类 SaxTest.java
package com.wnq.sk.saxXML01;
import java.util.List;
public class SaxTest
{   
    public static void main(String[] args)
        throws Throwable
    {
        SaxReadXMLFile sax = new SaxReadXMLFile();
        String fileName = "books.xml";
        List<Book> books = sax.getBooks(fileName);
        for (Book book : books)
        {
            System.out.println(book.toString());
        }
    }
}4 运行结果

该贴被蜀山战纪编辑于2016-2-1 10:43:29