数据解析1:XML解析(1)
Http网络传输中的数据组织格式主要有三种:
1.HTML方式
2.XML方式
3.JSON方式
其中XML方式的数据解析有三种:DOM解析,SAX解析,Pull解析。
下面主要讲解SAX解析。
因为SAX解析是解析XML格式的数据的,那么首先要大致了解下什么是XML,以及XML数据有什么特点。
下面是一个XML数据文件:
分析:XML文件和HTML文件很相似,都是由标签构成,但是XML比HTML更灵活,XML被称为可扩展性标记语言。其中第一行的是固定的格式,文件主体全部有双标签构成,且标签是自定义的,非常灵活。
总结:XML数据是网络传输数据的一种组织格式,其格式可以说灵活,但是也可以说非常固定,因为其中的每条数据的结构是完全相同的,这样做的目的是当从网络获取数据时,总是重复的采取相同的操作解析数据(循环遍历结构+选择对结构的不同部分采取不同的操作)。怎么说呢,如果从网络获取数据,那么数据一定是有一定格式的,如果是返回多条数据,那么每条数据的结构一定是完全相同的或者所有数据一定有一个结构且这个结构是每条数据结构的父集,这样的目的是方便客户端解析接收到的数据。
根据XML格式的定义我们可以写出各种XML数据:
以上代码可以很容易看出它们的结构可以说是固定可扩展,固定指的是每条数据的结构完全相同,可扩展是这些结构是自定义的,同时数据的条数是任意的。
SAX解析以事件通知的形式通知程序,对xml解析。
那么何为事件通知的形式呢?
SAX的解析是从文档的开头依次解析到文档的结尾的,当解析到上图第一行时,发生的事件就是解析到文档开头,当解析到文档结尾时,发生的事件就是解析到文档结尾,当解析到第二行<books>标签时,发生的事件是解析到开始标签,其中这里的开始标签就是books,对应的</books>发生的事件就是解析到结束标签,其中结束标签就是books,其中标签里还可能含有属性,如<book id ="1">中的id就是属性,当解析到english,15.5f等文本时,发生的事件就是解析到内容。
SAX解析的步骤:
1.定义数据的封装类,将要解析的数据封装到这个实体类中。
2.定义一个执行具体解析操作的类,即定义一个类继承DefaultHandler,实现这个类的五个方法,对不同的标签执行不同的操作。
2.1 public void startDocument():解析到文档开头时执行该方法
2.2 public void startElement(String uri, String localName, String qName,Attributes attributes):解析到开始标签时执行该方法
2.3 public void characters(char[] ch, int start, int length):解析到标签内容时执行该方法
2.4 public void endElement(String uri, String localName, String qName):解析到结束标签时执行该方法
2.5 public void endDocument():解析到文档结束时执行该方法
3.开始解析,具体的操作
3.1 创建SAX解析的工厂类
SAXParserFactory factory = SAXParserFactory.newInstance();
根据factory对象,创建 SAX解析对象
SAXParser parser = factory.newSAXParser();
3.2 创建读取xml文件的文件读取流
FileInputStream fis = new FileInputStream("user.xml");
创建Handler对象(即上面提到的一个执行具体解析操作的类的对象,其中Handler不是安卓中的Handler)
MyHandler handler = new MyHandler(); (MyHandler是一个自定义类,必须继承DefaultHandler)
解析
parser.parse(fis,handler)
3.3 获取解析的结果,是一个List<Object>集合
List<Person> list = handler.getList(); (getList()是Handler的一个自定义方法,用来返回解析的结果,且这个结果是Handler内部定义的一个成员变量,具体看示例)
示例1:解析person.xml文件
1 <?xml version = "1.0" encoding = "UTF-8"?> 2 <persons> 3 <person id = "23"> 4 <name>张老师</name> 5 <age>21</age> 6 </person> 7 <person id = "20"> 8 <name>李老师</name> 9 <age>25</age> 10 </person> 11 </persons>
1 package com.qianfeng.sax1; 2 3 public class Person { 4 5 private String name; 6 private int age; 7 private String sex; 8 9 public Person(){} 10 11 public Person(String name, int age, String sex) { 12 super(); 13 this.name = name; 14 this.age = age; 15 this.sex = sex; 16 } 17 18 public String getName() { 19 return name; 20 } 21 22 public void setName(String name) { 23 this.name = name; 24 } 25 26 public int getAge() { 27 return age; 28 } 29 30 public void setAge(int age) { 31 this.age = age; 32 } 33 34 public String getSex() { 35 return sex; 36 } 37 38 public void setSex(String sex) { 39 this.sex = sex; 40 } 41 42 @Override 43 public String toString() { 44 return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]"; 45 } 46 47 48 49 }
1 package com.qianfeng.sax1; 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 MyHandler extends DefaultHandler { 11 12 private List<Person> list; 13 private Person person; 14 private String tagName;//存储标签名 15 16 //解析到文档开头时执行该方法 17 @Override 18 public void startDocument() throws SAXException { 19 System.out.println("解析到文档开头...."); 20 list = new ArrayList<Person>(); 21 } 22 //解析到开始标签时执行该方法 23 //qName接收的是开始标签的名字 24 @Override 25 public void startElement(String uri, String localName, String qName, 26 Attributes attributes) throws SAXException { 27 tagName = qName; 28 System.out.println("解析到开始标签....."+qName); 29 if("person".equals(qName)) 30 { 31 person = new Person(); 32 } 33 34 } 35 //解析到标签内容时执行该方法 36 //解析到到标签数据传给了ch 37 @Override 38 public void characters(char[] ch, int start, int length) 39 throws SAXException { 40 String data = new String(ch,start,length); 41 System.out.println("解析到标签内容..."+data); 42 if("name".equals(tagName)) 43 { 44 person.setName(data); 45 } 46 else if("age".equals(tagName)) 47 person.setAge(Integer.parseInt(data)); 48 else if("sex".equals(tagName)) 49 person.setSex(data); 50 51 } 52 //解析到结束标签时执行该方法 53 //qName接收结束标签的名字 54 @Override 55 public void endElement(String uri, String localName, String qName) 56 throws SAXException { 57 tagName = null;//结束标签后边的空白也被看成标签内容,所以会去执行characters()方法 58 System.out.println("解析到结束标签...."+qName); 59 if("person".equals(qName)) 60 { 61 list.add(person); 62 } 63 } 64 //解析到文档结束时执行该方法 65 @Override 66 public void endDocument() throws SAXException { 67 System.out.println("解析到文档结束....."); 68 } 69 70 public List<Person> getList() { 71 return list; 72 } 73 74 75 76 }
1 package com. qianfeng.sax1; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.util.List; 7 8 import javax.xml.parsers.ParserConfigurationException; 9 import javax.xml.parsers.SAXParser; 10 import javax.xml.parsers.SAXParserFactory; 11 12 import org.xml.sax.SAXException; 13 14 public class Test { 15 16 /** 17 * @param args 18 * @throws SAXException 19 * @throws ParserConfigurationException 20 * @throws IOException 21 */ 22 public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { 23 24 //创建SAX解析的工厂类 25 SAXParserFactory factory = SAXParserFactory.newInstance(); 26 27 //创建 SAX解析对象--负责读取xml文件,并去调用handler中的方法 28 SAXParser parser = factory.newSAXParser(); 29 30 //创建读取xml文件的文件读取流 31 FileInputStream fis = new FileInputStream("user.xml"); 32 33 //创建Handler对象 34 MyHandler handler = new MyHandler(); 35 36 //解析 37 parser.parse(fis, handler); 38 39 List<Person> list = handler.getList(); 40 41 for(Person person:list) 42 { 43 System.out.println(person); 44 } 45 } 46 47 }
分析:总的来说SAX解析就涉及到3个类或者合并为更少的类,第一个是数据封装类,用来保存解析后得到的数据;第二个就是具体解析的类,必须继承DefaultHandler类,重写5个方法,执行具体的解析;第三个是执行解析的过程,核心方法就是parser.parse(fis,handler),"parser"是解析器,parser的获取先要获得解析器的工厂,然后由工厂对象获取SAXParser类对象,fis是一个文件字节输入流,指向xml文件的位置,handler是第二个类创建的一个对象,即具体解析类的对象,这就是SAX解析的主要框架。下面是解析一些XML文件中一些其他数据的示例。
示例2:解析worker.xml文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <workers> 3 <worker id="AQ01"> 4 <name>Mark</name> 5 <sex>男</sex> 6 <status>经理</status> 7 <address>北京</address> 8 <money>4000</money> 9 </worker> 10 <worker id="AD02"> 11 <name>Luch</name> 12 <sex>女</sex> 13 <status>员工</status> 14 <address>上海</address> 15 <money>1000</money> 16 </worker> 17 <worker id="AD03"> 18 <name>Lily</name> 19 <sex>女</sex> 20 <status>员工</status> 21 <address>北京</address> 22 <money>2000</money> 23 </worker> 24 <worker> 25 <name>Lily</name> 26 <sex>女</sex> 27 <status>员工</status> 28 <address>北京</address> 29 <money>2000</money> 30 </worker> 31 </workers>
1 package com.qianfeng.sax2; 2 3 public class Worker { 4 5 private String id; 6 private String name; 7 private char sex; 8 private String status; 9 private String address; 10 private double money; 11 12 public Worker(){} 13 14 public Worker(String id, String name, char sex, String status, 15 String address, double money) { 16 super(); 17 this.id = id; 18 this.name = name; 19 this.sex = sex; 20 this.status = status; 21 this.address = address; 22 this.money = money; 23 } 24 25 public String getId() { 26 return id; 27 } 28 29 public void setId(String id) { 30 this.id = id; 31 } 32 33 public String getName() { 34 return name; 35 } 36 37 public void setName(String name) { 38 this.name = name; 39 } 40 41 public char getSex() { 42 return sex; 43 } 44 45 public void setSex(char sex) { 46 this.sex = sex; 47 } 48 49 public String getStatus() { 50 return status; 51 } 52 53 public void setStatus(String status) { 54 this.status = status; 55 } 56 57 public String getAddress() { 58 return address; 59 } 60 61 public void setAddress(String address) { 62 this.address = address; 63 } 64 65 public double getMoney() { 66 return money; 67 } 68 69 public void setMoney(double money) { 70 this.money = money; 71 } 72 73 @Override 74 public String toString() { 75 return "Worker [id=" + id + ", name=" + name + ", sex=" + sex 76 + ", status=" + status + ", address=" + address + ", money=" 77 + money + "]"; 78 } 79 80 81 82 }
1 package com.qianfeng.sax2; 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 MyHandler extends DefaultHandler { 11 12 private List<Worker> list; 13 private Worker worker; 14 private String tagName; 15 16 @Override 17 public void startDocument() throws SAXException { 18 list = new ArrayList<Worker>(); 19 } 20 21 22 @Override 23 public void startElement(String uri, String localName, String qName, 24 Attributes attributes) throws SAXException { 25 //attributes参数用来接收属性的 26 tagName = qName; 27 if("worker".equals(tagName)) 28 { 29 worker = new Worker(); 30 if(attributes!=null) 31 { 32 for(int i=0;i<attributes.getLength();i++) 33 { 34 //得到属性名 35 String attrName = attributes.getQName(i); 36 //得到属性值 37 String attrValue = attributes.getValue(i); 38 if("id".equals(attrName)) 39 { 40 worker.setId(attrValue); 41 } 42 } 43 } 44 } 45 46 } 47 48 @Override 49 public void characters(char[] ch, int start, int length) 50 throws SAXException { 51 String data = new String(ch,start,length); 52 if("name".equals(tagName)) 53 worker.setName(data); 54 else if("sex".equals(tagName)) 55 worker.setSex(data.charAt(0)); 56 else if("status".equals(tagName)) 57 worker.setStatus(data); 58 else if("address".equals(tagName)) 59 worker.setAddress(data); 60 else if("money".equals(tagName)) 61 worker.setMoney(Double.parseDouble(data)); 62 63 } 64 65 @Override 66 public void endElement(String uri, String localName, String qName) 67 throws SAXException { 68 tagName = null; 69 if("worker".equals(qName)) 70 { 71 list.add(worker); 72 } 73 74 } 75 76 @Override 77 public void endDocument() throws SAXException { 78 79 } 80 81 82 public List<Worker> getList() { 83 return list; 84 } 85 86 87 88 }
1 package com.qianfeng.sax2; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.util.List; 7 8 import javax.xml.parsers.ParserConfigurationException; 9 import javax.xml.parsers.SAXParser; 10 import javax.xml.parsers.SAXParserFactory; 11 12 import org.xml.sax.SAXException; 13 14 public class Test { 15 16 /** 17 * @param args 18 * @throws SAXException 19 * @throws ParserConfigurationException 20 * @throws IOException 21 */ 22 public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { 23 24 SAXParserFactory factory =SAXParserFactory.newInstance(); 25 26 SAXParser parser = factory.newSAXParser(); 27 28 FileInputStream fis = new FileInputStream("worker.xml"); 29 MyHandler handler = new MyHandler(); 30 31 parser.parse(fis, handler); 32 33 List<Worker> list = handler.getList(); 34 35 for(Worker worker:list) 36 { 37 System.out.println(worker); 38 } 39 40 41 42 } 43 44 }
分析:该示例解决了当标签中还有属性该如何解析的问题。
未完,待续。