SAX(Simple API for XML)SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理方法,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。SAX解析方式适用于大型文档,因为他的解析是逐行进行不用像DOM中那样为所有节点创建对象,这样效率大大提高,所以虽然它不是W3C标准,但它却得到了广泛认可。
这是一个需要解析的XML文件:
<?xmlversion="1.0"encoding="utf-8"?> <bookstore> <bookid="2"type="长篇小说"> <name>《平凡的世界》</name> <author>路遥</author> <year>2014</year> <price>22</price> <outline>《平凡的世界》是中国作家路遥创作的一部百万字的小说。 </outline>> </book> <bookid="7"type="外文小说"> <name>"GonewiththeWind"</name> <author>Margaret.Mitchell</author> <price>99</price> <language>English</language> <outline>《飘》是美国女作家玛格丽特・米切尔(1900―1949)十年磨一剑的作品,也是惟一的作品。</outline> </book> <bookid="13"type="中文小说"> <name>《秦腔》</name> <author>贾平凹</author> <price>99</price> <language>汉语</language> <outline>《秦腔》以两条线展开,一条线是秦腔戏曲,一条线是农民与土地的关系。</outline>> </book> </bookstore>
如上所示,我们将从首行开始逐一进行解析,SAX解析时会识别开始标签和结束标签,这些用相应的方法进行实现,具体如下:
需要注意的是:DefaultHandler类是SAX2事件处理程序的默认基类。它实现了EntityResolver、DTDHandler、ContentHandler和ErrorHandler这四个接口。包含这四个接口的所有方法,所以我们在编写事件处理程序时,可以不用直接实现这四个接口,而继承该类,然后重写我们需要的方法即可
我们SAX方法解析XML文件时需要一个Handler类来提供解析的方法,里面包含了重写的继承于DefaultHandler类的两种方法,分别有开始和结束的方法
packageHandler; importjava.util.ArrayList; importorg.xml.sax.Attributes; importorg.xml.sax.SAXException; importorg.xml.sax.helpers.DefaultHandler; importentity.Book; publicclassSAXParserHandlerBookextendsDefaultHandler{ intbookIndex=0; Bookbook=null; privateArrayList<Book>bookList=newArrayList<Book>(); publicArrayList<Book>getBookList(){ returnbookList; } //用来标识解析开始和结束 @Override publicvoidstartDocument()throwsSAXException{ super.startDocument(); System.out.println("SAX解析开始"); } @Override publicvoidendDocument()throwsSAXException{ super.startDocument(); System.out.println("SAX解析开始"); } //用来遍历XML文件的开始标签 @Override publicvoidstartElement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{ super.startElement(uri,localName,qName,attributes); //开始解析book节点的属性 //注意:这种方法是知道节点名为book且其属性只有id一个属性,只需获取其属性值的情况 if(qName.equals("book")){ //在清空之前保存 bookList.add(book); //保证每次运行到这里的时候book都是null以便保存其他子节点的值 book=null; //创建book对象 book=newBook(); //这边我们需要一个全局变量来记录遍历进行到哪本书 bookIndex++; // Stringvalue=attributes.getValue("id"); //【注意这种方法是知道了属性的属性名来获取属性值的简便方法】 // System.out.println("book的属性值:"+attributes.getValue("id")); //在不知道book节点的属性数量以及属性名和属性值的情况下进行解析 intlen=attributes.getLength(); System.out.println("*************************开始遍历第"+(bookIndex)+"本书*************************"); for(inti=0;i<len;i++){ System.out.println("第"+(i+1)+"个属性:"); System.out.println("属性名是:"+attributes.getQName(i)); System.out.println("属性值是:"+attributes.getValue(i)); System.out.println(); if(attributes.getQName(i).equals("id")){ book.setId(attributes.getQName(i)); }elseif(attributes.getQName(i).equals("type")){ book.setId(attributes.getQName(i)); } } } //获取book节点的所有子节点节点名 if(qName!="book"){ System.out.println("节点名:"+qName); }elseif(qName.equals("author")){ book.setAuthor(value); }elseif(qName.equals("year")){ book.setYear(value); }elseif(qName.equals("lauguage")){ book.setLauguage(value); }elseif(qName.equals("price")){ book.setPrice(value); }elseif(qName.equals("outline")){ book.setOutline(value); }elseif(qName.equals("name")){ book.setName(value); } } //以上部分用switch语句实现代码开起来应该会相对整洁一点, Stringvalue=null; @Override publicvoidcharacters(char[]ch,intstart,intlength)throwsSAXException{ super.characters(ch,start,length); value=newString(ch,length); if(!value.trim().equals("")){ System.out.println("节点值:"+value); System.out.println(); } } //用来遍历XML结束标签(non-Javadoc) @seeorg.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,java.lang.String,java.lang.String) @Override publicvoidendElement(Stringuri,StringqName)throwsSAXException{ super.endElement(uri,qName); //判断针对一本书是否已经遍历结束 if(qName.equals("book")){ System.out.println("===========================结束遍历==========================="); } } }
Handler类准备好之后我们来编写测试程序看一下解析结果:
packagetest_XML; importjava.io.IOException; importjavax.xml.parsers.ParserConfigurationException; importjavax.xml.parsers.SAXParser; importjavax.xml.parsers.SAXParserFactory; importorg.xml.sax.SAXException; importHandler.SAXParserHandlerBook; publicclassTestSAX{ publicstaticvoidmain(String[]args)throwsParserConfigurationException,SAXException{ try{ //是创建一个Handler处理类,去逐个分析每一个节点,并且是顺序的 //1.通过SAXParseFactory的静态方法newInstance()来获取SAXParseFactory的实例对象factory SAXParserFactoryfactory=SAXParserFactory.newInstance(); //2.通过SAXParserFactory静态方法NewSAXParser()方法返回一个SAXParser类的实例; SAXParserHandlerBookhandler=newSAXParserHandlerBook(); //3.重写startElement、endElement、startDocument、endDocument方法 /* *可以将其保存在继承了DefaultHandler类的SAXParserHandler类中 *然后创建SAXParserHandler类的对象并将其传入SAXParser类的对象parser的parser方法; */ SAXParserparser=factory.newSAXParser(); parser.parse("book.xml",handler); }catch(SAXExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); } } }
以下是解析结果:
SAX解析开始
节点名:bookstore
*************************开始遍历第1本书*************************
第1个属性:
属性名是:id
属性值是:2
第2个属性:
属性名是:type
属性值是:长篇小说
节点名:name
节点值:《平凡的世界》
节点名:author
节点值:路遥
节点名:year
节点值:2014
节点名:price
节点值:22
节点名:outline
节点值:《平凡的世界》是中国作家路遥创作的一部百万字的小说。
===========================结束遍历===========================
*************************开始遍历第2本书*************************
第1个属性:
属性名是:id
属性值是:7
第2个属性:
属性名是:type
属性值是:外文小说
节点名:name
节点值:"Gone with the Wind"
节点名:author
节点值:Margaret.Mitchell
节点名:price
节点值:99
节点名:language
节点值:English
节点名:outline
节点值:《飘》是美国女作家玛格丽特・米切尔(1900―1949)十年磨一剑的作品,也是惟一的作品。
===========================结束遍历===========================
*************************开始遍历第3本书*************************
第1个属性:
属性名是:id
属性值是:13
第2个属性:
属性名是:type
节点名:name
节点值:《秦腔》
节点名:author
节点值:贾平凹
节点名:price
节点值:99
节点名:language
节点值:汉语
节点名:outline
节点值:《秦腔》以两条线展开,一条线是秦腔戏曲,一条线是农民与土地的关系。
节点值:>
===========================结束遍历===========================
DOM(Document Object Model)是表示和处理一个HTML或XML文档的常用方法,DOM的优势是易用性强,使用DOM这种解析方法的时候,将把所有的XML文档信息都存于内存中,遍历操作简单快速。SAX(Simple API for XML)不是W3C的标准,但是对于大型XML文件的解析效率要高与DOM。
原文链接:https://www.f2er.com/xml/295674.html