Android 之xml解析
在网络上传输数据常用的格式有xml还有json。
常见的xml解析方式有Pull解析,SAX解析以及DOM解析。在Android中一般采用的是Pull解析以及SAX解析。
三种解析简述
- SAX(Simple API for XML) 使用流式处理的方式。它是一种基于事件模型的XML API,解析速度快,占用内存少。使用回调函数来实现。 缺点是不能倒退
- DOM(Document Object Model)一种用于XML文档的对象模型,可用于直接访问XML文档的各个部分。它是一次性全部将内容加载在内存中,生成DOM树。 缺点是加载大文档时效率低下。
- Pull与SAX有点类似,都提供了类似的事件,如开始元素和结束元素。不同的是,SAX的事件驱动是回调相应方法,需要提供回调的方法,而后在SAX内部自动调用相应的方法。而Pull解析器并没有强制要求提供触发的方法。因为他触发的事件不是一个方法,而是一个数字。它使用方便,效率高。
SAX和Pull解析区别
SAX解析器的工作方式是自动将事件推入注册的事件处理器处理,不能控制事件主动结束,会对整一个文档进行解析。pull的解析解析器允许代码出动从解析器获取事件,允许主动中断事件。
pull解析步骤
- 获取XmlPullParserFactory对象
- 通过XmlPullParserFactoru得到XmlParser对象
- 调用XmlPullParser对象的setInput方法将服务器的Xml数据进行解析
- 获取当前解析对象,指导解析事件为XmlPullParser.END_DOCUMENT,解析完成
/**
* Pull解析
* @param xmlData
*/
private void parseXMLWithPull(String xmlData) {
try {
// 获取XmlPullParserFactory对象
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
// 通过XmlPullParserFactoru得到XmlParser对象
XmlPullParser xmlPullParser = factory.newPullParser();
// 调用XmlPullParser对象的setInput方法将服务器的Xml数据进行解析
xmlPullParser.setInput(new StringReader(xmlData));
// 获取当前解析事件
int eventType = xmlPullParser.getEventType();
String id = "";
String name = "";
while (eventType != XmlPullParser.END_DOCUMENT){
String nodeName = xmlPullParser.getName();
switch (eventType){
case XmlPullParser.START_TAG:{
if ("id".equals(nodeName)){
id = xmlPullParser.nextText();
} else if ("name".equals(nodeName)){
name = xmlPullParser.nextText();
}
break;
}
case XmlPullParser.END_TAG:{//结束标志
if("app".equals(nodeName)){
Log.d("ok", "id is " + id);
Log.d("ok", "name is " + name);
}
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
pull是最常用也是最方便使用的xml的解析方式
SAX解析步骤
- 创建继承于DefaultHander类的处理类
- 创建SAXparserFactory对象
- 获取XMLReader对象
- 将新建的处理类放置到XMLReader中
- 通过parse()方法进行解析
public class SaxHandler extends DefaultHandler {
private StringBuilder id ;
private StringBuilder name;
private String nodeName;
@Override
// 在开始XML解析的时候会调用
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
}
// 在开始解析某个结点的时候会调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
nodeName = localName;
}
// 在获取某个结点内容的时候会调用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if ("id".equals(nodeName)){
id.append(ch,start,length);
} else if ("name".equals(nodeName)){
name.append(ch, start, length);
}
}
// 在完成某个节点内容的时候会调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("app".equals(localName)){
Log.d("ok", "id is" + id.toString().trim());
Log.d("ok", "name is" + name.toString().trim());
id.setLength(0);
name.setLength(0);
}
}
// 在完成某个XML文件解析的时候调用
@Override
public void endDocument() throws SAXException {
}
}
以上是第一步,创建继承DefaultHander的处理类
private void paresXMLWithSAX(String xmlData) {
try{
// 获取SAXParserFactory对象
SAXParserFactory factory = SAXParserFactory.newInstance();
// 获取XMLReader对象
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
// 将新建的处理类放入XMLReader中
SaxHandler handler = new SaxHandler();
xmlReader.setContentHandler(handler);
// 通过parse方法进行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e){
e.printStackTrace();
}
}
DOM解析步骤
- 创建DocumentBuilderFactory对象
- 获取DocumentBuilder对象
- 获取根节点root
- 对DOM进行遍历解析
/**
* xmlData为xml文件的数据流
* @param xmlData
*/
private void parasXMLWithDOM(InputStream xmlData) {
// 创建DOcumentBuilderFactory对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
// 创建DocumentBuilder对象
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
// 解析xml文件
Document document = documentBuilder.parse(xmlData);
// 获取文件的根节点
Element root = document.getDocumentElement();
NodeList personNodes = root.getElementsByTagName("app");
// 遍历DOM树
for (int i = 0;i < personNodes.getLength();i++){
Element personElement = (Element) personNodes.item(i);
NodeList chileNodes = personElement.getChildNodes();
for (int y = 0;y < chileNodes.getLength();y++){
if (chileNodes.item(y).getNodeType() == Node.ELEMENT_NODE){
if ("id".equals(chileNodes.item(y).getNodeName())){
String id = chileNodes.item(y).getFirstChild().getNodeValue();
Log.d("ok", "id is " + id);
} else if ("name".equals(chileNodes.item(y).getNodeName())){
String name = chileNodes.item(y).getFirstChild().getNodeValue();
Log.d("ok","name is "+ name);
}
}
}
}
xmlData.close();
} catch (Exception e){
e.printStackTrace();
}
}
当然在遍历DOM树的时候也能通过递归的方式进行遍历
最后尽然忘记了,以上只给了函数的主体,解析的xml文件为
<apps>
<app>
<id>i</id>
<name>first</name>
</app>
<app>
<id>2</id>
<name>second</name>
</app>
</apps>
传入参数的方式为
private void sendRequsetWithHttpURLConnection() {
// 开启线程发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
String path = "http://10.0.2.2/get_data.xml";
try{
URL url = new URL(path);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder iresponse = new StringBuilder();
String line;
while ((line = reader.readLine()) != null){
iresponse.append(line);
}
String response = iresponse.toString();
//pull解析
parseXMLWithPull(response);
} catch (Exception e){
e.printStackTrace();
} finally {
if(connection != null){
connection.disconnect();
}
}
}
}).start();
}
这里偷懒使用了以前的代码,通过服务器的方式传递参数,如果进行DOM的话,直接将inputStream传进去就好啦~
(当然xml解析还有很多种方式,像JDOM,DOM4J等,只是Android不经常用而已)