SAX解析xml全解
1 <?xml version="1.0" encoding="UTF-8"?> 2 <books index="1">aa 3 <book index="2" id="12" color="red" >xx 4 <name index="3" color="green" type="嘿嘿">thinking in java</name> 5 <price index="4">85.5</price><price index="4">86.5</price> 6 </book>nn 7 <book index="5" id="15" color="blue" > 8 <name index="6" value="xx" type="哈哈" ><![CDATA[&haha<>]]> Spring in Action</name> 9 <price index="7">39.0</price> 10 </book>mm 11 </books>
下面这个是解析类,需要导入jar包xercesImpl.jar
首先要获得解析器,然后要将解析器注册到处理器
1 package com.Sax.demo; 2 3 import org.xml.sax.Attributes; 4 import org.xml.sax.Locator; 5 import org.xml.sax.SAXException; 6 import org.xml.sax.XMLReader; 7 import org.xml.sax.ext.LexicalHandler; 8 import org.xml.sax.helpers.DefaultHandler; 9 import org.xml.sax.helpers.XMLReaderFactory; 10 /** 11 * http://docs.oracle.com/javaee/1.4/tutorial/doc/JAXPIntro4.html 12 * @author ibn 13 * LexicalHandler是拓展接口 必须通过XMLReader属性进行注册 14 * 通过属性注册,将拓展接口传递给处理器 15 * reader.setPropeerty("属性名",this) 这个属性名是固定的 16 * 而在DefalutHandler里面,可以直接setContentHandler进行注册 17 * 18 */ 19 public class BookReader extends DefaultHandler implements LexicalHandler{ 20 private boolean isColor; 21 private String bookType; 22 private StringBuffer bookColor=new StringBuffer(); 23 private Locator bookLocator; 24 public static void main(String[]args)throws Exception{ 25 StringBuffer sb=new StringBuffer(); 26 sb.append(false); 27 sb.append(true); 28 System.out.println("sb"+sb); 29 System.out.println("Running Start...."); 30 BookReader tr=new BookReader(); 31 tr.read("src/Book.xml"); 32 } 33 /** 34 * 利用XMLReaderFactory创建一个XMLReader对象 35 * 将已注册的解析器名传给XMLReaderFactory 得到XMLReader 36 * 解析前通知XMLreader接收与解析xml文档内容有关的事件处理器 37 * 然后给需要解析的文档名传递给解析器 38 * 解析器不能保存前一事件的数据 39 * 这个文档路径默认相对路径是在功能目录下 40 * 解析xml开始时机会将startDocument事件传给事件解析器 即这个TrainReader,执行startDocument()函数 41 * @param fileName 42 * @throws Exception 43 */ 44 public void read(String fileName) throws Exception{ 45 //驱动 46 XMLReader reader=XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); 47 reader.setContentHandler(this); 48 reader.setErrorHandler(this);//将验证属性呢设置为true 49 /* 50 *dafaultHandler并没有为LexicalHandler提供了实现程序 51 *所以使用这些拓展接口的时候需要通过属性注册 52 */ 53 reader.setProperty("http://xml.org/sax/properties/lexical-handler", this); 54 //reader.setFeature(name, value); 55 reader.parse(fileName); 56 } 57 public void startDocument(){ 58 System.out.println("Start of the train..."); 59 } 60 public void endDocument(){ 61 System.out.println("End of the trail..."); 62 } 63 /** 64 * 处理元素和属性 65 * 名称空间URI http://example.com 66 * 局部名(localname) myElement 67 * 限定名(qname) myPrefix:myElement 68 * <myPrefix:myElement xmlns:myPrefix="http://example.com"> 69 * 如果uri不为空 利用uri+localname而不是利用qname来确定元素 具体原因:不同文档同一uri的前缀可能不同 70 * Attributes接口 可以访问每个元素的属性和初始值 71 */ 72 public void startElement(String uri,String localName,String qName,Attributes atts){ 73 System.err.println("TestA"); 74 System.err.println(atts.getValue("index")); 75 System.out.println("index:"+atts.getIndex(qName)+" qName:"+qName); 76 // if("book".equals(localName)){ 77 // if(atts!=null){ 78 // System.out.println("Book:"+atts.getValue("id")); 79 // String color=atts.getValue("color"); 80 // System.out.println("color:"+color); 81 // if(color.equals("red")){ 82 // System.out.println("红书"); 83 // } 84 // } 85 // }else 86 if("name".equals(localName)){ 87 if(atts!=null){ 88 isColor=true; 89 bookType=atts.getValue("type"); 90 System.out.println("name:"+atts.getValue("value")); 91 String color=atts.getValue("color"); 92 System.out.println("color:"+color); 93 } 94 }else{ 95 isColor=false; 96 } 97 } 98 /** 99 * 元素结束 100 */ 101 public void endElement(String uri,String localName,String qName){ 102 System.err.println("testC:"+localName); 103 //if(isColor){ 104 // System.out.println("The color of name:"+bookColor+" type:"+bookType); 105 //} 106 } 107 /** 108 * 处理元素中间的文本内容 109 * 该方法在元素由文本内容会调用一次 110 * 在每次换行也会调用一次 111 * ch处理的文本字符串 112 * start 开始的位置index 113 * len 文本字符串长度 114 */ 115 public void characters(char[]ch,int start,int len)throws SAXException{ 116 System.err.println("testB:"+new StringBuffer().append(ch, start, len)); 117 if(isColor){ 118 bookColor.append(ch, start, len); 119 System.out.println("start:"+ch[0]); 120 System.out.println("len:"+len); 121 } 122 } 123 /** 124 * 在元素开始解析之前,将该接口传递给了本程序 125 * 解析器把Locator接口传递给程序 126 * 在出错位置可以利用如下的两个方法定位出错的行号和列号 127 * 在endElement里面将异常抛出,异常信息利用Locator接口得到行号和列号 128 * 129 */ 130 public void setDocumentLocator(Locator locator){//ContenHandler 131 System.out.println("Locator接口"); 132 locator.getLineNumber();//当前事件的行号 133 locator.getColumnNumber();//当前事件的列号 134 bookLocator=locator; 135 } 136 public void comment(char[] ch, int start, int length) throws SAXException { 137 // TODO Auto-generated method stub 138 139 } 140 public void endCDATA() throws SAXException { 141 // TODO Auto-generated method stub 142 143 } 144 public void endDTD() throws SAXException { 145 // TODO Auto-generated method stub 146 147 } 148 public void endEntity(String name) throws SAXException { 149 // TODO Auto-generated method stub 150 151 } 152 /** 153 * 上面已经通过setProperty进行了属性注册 154 * 当解析器访问CDATA段的开始标签就会将里面的内容传递给应用程序 155 */ 156 public void startCDATA() throws SAXException { 157 System.out.println("注册cddata"); 158 159 } 160 public void startDTD(String name, String publicId, String systemId) 161 throws SAXException { 162 // TODO Auto-generated method stub 163 164 } 165 public void startEntity(String name) throws SAXException { 166 // TODO Auto-generated method stub 167 168 } 169 170 171 }
我打印了一下这个index,发现顺序是1,2,3,4,5,6,7所以这个解析element的顺序是从上往下进行的。
我们写的类继承了DefaultHandler,这个处理器本身已经实现了四个接口
我们要先获得一个解析器
我们需要做的就是将这个解析器给他注册到我们的处理器上,然后在处理器的各个相应方法里面处理xml文档
如果我们需要拓展接口时,就需要通过setProperty("uri形式的固定属性",处理器);将解析器注册到处理器
基本的步骤是:
首先startDocument开始处理xml,setDocumentLocator(Lacator)将这个接口传递给处理器(此接口能获得当前处理的行号和列号),
startElement(...)解析每个元素触发该方法(获得其namespace的uri和局部名和限定名及元素属性),characters(...)当元素之间有文本内容,当遇到</...>触发endElement方法
这个character()方法在每次换行会调用一次在解析每个元素内容时也会调用一次!
因为解析器会将开始标签和结束标签之间的字符当做一个文本块来处理,因此需要多次characters事件才能生成一个文本块
现在有个问题在整个Books里面 如果在多个地方有文本块,怎么将这些文本块合在一起啊?