今天我们来了解Androidd的xml解析方式,首先我们先在web端模拟一组数据,并将它发送到请求域当中去,代码如下:
public class FQAcgtion extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* XAX
* @return 返回值
* @throws Exception
*
*/
public String getXML() throws Exception {
// 获取数据
// 调用数据库查询数据,返回对象集合(....)
List<FQ> fqs = new ArrayList<FQ>();
for (int i = 1; i <= 100; i++) {
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
fqs.add(new FQ("小" + i, "今天心情很nice", year + "-" + month + "-" + day));
}
// 将对象集合存放到请求域中
//ServletActionContext.getRequest().setAttribute("fqs", fqs);
return "dataResult";
}
}
然后我们再来一个XML(dataresult)返回我们模拟的数据(注意:上面不要留有空格,不然写空格,要不然我们这在Android端解析的时候会解析不到数据)
<?xml version="1.0" encoding="UTF-8" ?><%@ page language="java" contentType="text/xml; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><fqs><c:forEach items="${fqs}" var="fq">
<fq name="${fq.name}">
<content>${fq.content}</content>
<time>${fq.time}</time>
</fq>
</c:forEach>
</fqs>
web端我们准备好了,现在我们开始在Android端解析数据,我们将数据解析到Android端,并用listview展示出来:如下图所示:
数据展示出来了:先在我们来解析xml,
XML解析数据有三种方式:
Activity_main.xml
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取XML"
android:onClick="getXML"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lv_main_list"
>
</ListView>
item_listview.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/tv_item_listview_name" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/tv_item_listview_content" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/tv_item_listview_time" />
</LinearLayout>
fq.class(里面放的是你的XML标签名,web端和Android端都需要有)
public class FQ {
private String name;
private String content;
private String time;
public FQ() {
super();
}
public FQ(String name, String content, String time) {
super();
this.name = name;
this.content = content;
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
itemtag.class(listview优化)public class ItemTag {
public TextView tv_name;
public TextView tv_content;
public TextView tv_time;
}
1.DOM解析
Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。
DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。
由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。
常用的DoM接口和类:
Document:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。
Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。
Node:该接口提供处理并获取节点和子节点值的方法。
NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。
DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。
下面是DOM的解析流程:
<p><span style="background-color: rgb(240, 240, 240);">public class MainActivity extends AppCompatActivity {</span></p><p></p> private ProgressDialog progressDialog;
private ListView lv_main_list;
private List<FQ> lists=new ArrayList<>();
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_main_list = (ListView) findViewById(R.id.lv_main_list);
myAdapter = new MyAdapter();
lv_main_list.setAdapter(myAdapter);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在拼命loading中...");
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return lists.size();
}
@Override
public Object getItem(int i) {
return lists.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if(view==null){
view=LayoutInflater.from(MainActivity.this).inflate(R.layout.item_listview,null);
ItemTag itemTag=new ItemTag();
itemTag.tv_content= (TextView) view.findViewById(R.id.tv_item_listview_content);
itemTag.tv_name= (TextView) view.findViewById(R.id.tv_item_listview_name);
itemTag.tv_time= (TextView) view.findViewById(R.id.tv_item_listview_time);
view.setTag(itemTag);
}
ItemTag itemTag= (ItemTag) view.getTag();
itemTag.tv_name.setText(lists.get(i).getName());
itemTag.tv_content.setText(lists.get(i).getContent());
itemTag.tv_time.setText(lists.get(i).getTime());
return view;
}
}
public void getXML(View view){
new MyTask().execute();
}
class MyTask extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
@Override
protected Object doInBackground(Object[] objects) {
List<FQ> fqs=new ArrayList<>();
//获取网络数据
//01.定义获取网络的数据的路径
String path=getString(R.String.server_name)<span style="font-family:Arial, Helvetica, sans-serif;">+</span>"fqActiongetXML.action";
try {
//02.实例化Url
URL url=new URL(path);
//03.获取连接对象
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
//04.设置请求方式
conn.setRequestMethod("GET");
//05.设置请求连接超时的时间
conn.setConnectTimeout(5000);
//06.获取响应码
int code=conn.getResponseCode();
if(code==200){
//07.获取返回过来的数据(XML)
InputStream is =conn.getInputStream();
//08.测试(删除-注释)
//缓冲字符流
String str=null;
// BufferedReader br=new BufferedReader(new InputStreamReader(is));
// while((str=br.readLine())!=null){
// Log.i("test",str);
// }
//09.解析XML
//方式:DOM SAX PULL
//09.1 使用DOM解析
//设计模式:
//单例模式(饿汉 懒汉)
try {
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
Document document=documentBuilder.parse(is);
//获取跟标签
Element root=document.getDocumentElement();
Log.i("test","跟标签:"+root.getTagName());
//Node Element
NodeList nodeList=root.getElementsByTagName("fq");
for (int i = 0; i <nodeList.getLength() ; i++) {
Element element= (Element) nodeList.item(i);
//获取属性name
String name=element.getAttribute("name");
//获取子标签<content><time>
Element elementContent= (Element) element.getElementsByTagName("content").item(0);
String content=elementContent.getTextContent();
Element elementTime= (Element) element.getElementsByTagName("time").item(0);
String time=elementTime.getTextContent();
Log.i("test",name+" "+content+" "+time);
FQ fq=new FQ(name,content,time);
fqs.add(fq);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return fqs;
}
//更新UI
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
List<FQ> fqs= (List<FQ>) o;
lists.addAll(fqs);
myAdapter.notifyDataSetChanged();
progressDialog.cancel();
}
}
}
2.SAX
SAX(Simple API for XML)解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,
不可暂停或倒退。它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,
一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,
还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。
SAX的工作原理:SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)
开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,
由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
实现方法如下:
public class MainActivity extends AppCompatActivity {
private ProgressDialog progressDialog;
private ListView lv_main_list;
String currentTag=null;
private List<FQ> lists=new ArrayList<>();
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_main_list = (ListView) findViewById(R.id.lv_main_list);
myAdapter = new MyAdapter();
lv_main_list.setAdapter(myAdapter);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在拼命loading中...");
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return lists.size();
}
@Override
public Object getItem(int i) {
return lists.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if(view==null){
view=LayoutInflater.from(MainActivity.this).inflate(R.layout.item_listview,null);
ItemTag itemTag=new ItemTag();
itemTag.tv_content= (TextView) view.findViewById(R.id.tv_item_listview_content);
itemTag.tv_name= (TextView) view.findViewById(R.id.tv_item_listview_name);
itemTag.tv_time= (TextView) view.findViewById(R.id.tv_item_listview_time);
view.setTag(itemTag);
}
ItemTag itemTag= (ItemTag) view.getTag();
itemTag.tv_name.setText(lists.get(i).getName());
itemTag.tv_content.setText(lists.get(i).getContent());
itemTag.tv_time.setText(lists.get(i).getTime());
return view;
}
}
public void getXML(View view){
new MyTask().execute();
}
class MyTask extends AsyncTask{
private FQ fq;
private FQ fq1;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
@Override
protected Object doInBackground(Object[] objects) {
final List<FQ> fqs=new ArrayList<>();
//获取网络数据
//01.定义获取网络的数据的路径
String path=getString(R.string.server_name)+"fqActiongetXML.action";
try {
//02.实例化Url
URL url=new URL(path);
//03.获取连接对象
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
//04.设置请求方式
conn.setRequestMethod("GET");
//05.设置请求连接超时的时间
conn.setConnectTimeout(5000);
//06.获取响应码
int code=conn.getResponseCode();
if(code==200){
//07.获取返回过来的数据(XML)
InputStream is =conn.getInputStream();
//08.测试(删除-注释)
//缓冲字符流
String str=null;
// BufferedReader br=new BufferedReader(new InputStreamReader(is));
// while((str=br.readLine())!=null){
// Log.i("test",str);
// }
//09.解析XML
//02.使用SAX解析:特点:边读边解析 基于事件(方法)驱动方式
//开始文档 开始标签 结束标签 结束文档 文本
//<name>张三</name>
// try {
// SAXParserFactory saxParserFactory=SAXParserFactory.newInstance();
// SAXParser saxParser=saxParserFactory.newSAXParser();
//
// saxParser.parse(is,new DefaultHandler(){
// @Override
// public void startDocument() throws SAXException {
// super.startDocument();
// }
//
// @Override
// public void endDocument() throws SAXException {
// super.endDocument();
// }
//
// @Override
// public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// super.startElement(uri, localName, qName, attributes);
// currentTag=localName;
// if("fq".equals(localName)){
// //实例化对象
// fq = new FQ();
// String name=attributes.getValue(0);
// fq.setName(name);
// }
//
// }
//
// @Override
// public void endElement(String uri, String localName, String qName) throws SAXException {
// super.endElement(uri, localName, qName);
// //细节:
// currentTag=null;
// if("fq".equals(localName)){
// fqs.add(fq);
// }
// }
//
// @Override
// public void characters(char[] ch, int start, int length) throws SAXException {
// super.characters(ch, start, length);
// if("content".equals(currentTag)){
// String content=new String(ch,start,length);
// fq.setContent(content);
// } else if("time".equals(currentTag)){
// String time=new String(ch,start,length);
// fq.setTime(time);
// }
// }
// });
// } catch (ParserConfigurationException e) {
// e.printStackTrace();
// } catch (SAXException e) {
// e.printStackTrace();
// }
//更新UI
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
List<FQ> fqs= (List<FQ>) o;
lists.addAll(fqs);
myAdapter.notifyDataSetChanged();
progressDialog.cancel();
}
}
}
3.PULL解析器:
Android并未提供对Java StAX API的支持。但是,Android附带了一个pull解析器,其工作方式类似于StAX。它允许用户的应用程序代码从解析器中获取事件,这与SAX解析器自动将事件推入处理程序相反。
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
读取到xml的声明返回 START_DOCUMENT;
读取到xml的结束返回 END_DOCUMENT ;
读取到xml的开始标签返回 START_TAG
读取到xml的结束标签返回 END_TAG
读取到xml的文本返回 TEXT
PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。
常用的XML pull的接口和类:
XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口。
XmlSerializer:它是一个接口,定义了XML信息集的序列。
XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。
XmlPullParserException:抛出单一的XML pull解析器相关的错误。
实现方法如下:
public class MainActivity extends AppCompatActivity {
private ProgressDialog progressDialog;
private ListView lv_main_list;
String currentTag=null;
private List<FQ> lists=new ArrayList<>();
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_main_list = (ListView) findViewById(R.id.lv_main_list);
myAdapter = new MyAdapter();
lv_main_list.setAdapter(myAdapter);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在拼命loading中...");
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return lists.size();
}
@Override
public Object getItem(int i) {
return lists.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if(view==null){
view=LayoutInflater.from(MainActivity.this).inflate(R.layout.item_listview,null);
ItemTag itemTag=new ItemTag();
itemTag.tv_content= (TextView) view.findViewById(R.id.tv_item_listview_content);
itemTag.tv_name= (TextView) view.findViewById(R.id.tv_item_listview_name);
itemTag.tv_time= (TextView) view.findViewById(R.id.tv_item_listview_time);
view.setTag(itemTag);
}
ItemTag itemTag= (ItemTag) view.getTag();
itemTag.tv_name.setText(lists.get(i).getName());
itemTag.tv_content.setText(lists.get(i).getContent());
itemTag.tv_time.setText(lists.get(i).getTime());
return view;
}
}
public void getXML(View view){
new MyTask().execute();
}
class MyTask extends AsyncTask{
private FQ fq;
private FQ fq1;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
@Override
protected Object doInBackground(Object[] objects) {
final List<FQ> fqs=new ArrayList<>();
//获取网络数据
//01.定义获取网络的数据的路径
String path=getString(R.string.server_name)+"fqActiongetXML.action";
try {
//02.实例化Url
URL url=new URL(path);
//03.获取连接对象
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
//04.设置请求方式
conn.setRequestMethod("GET");
//05.设置请求连接超时的时间
conn.setConnectTimeout(5000);
//06.获取响应码
int code=conn.getResponseCode();
if(code==200){
//07.获取返回过来的数据(XML)
InputStream is =conn.getInputStream();
//08.测试(删除-注释)
//缓冲字符流
String str=null;
// BufferedReader br=new BufferedReader(new InputStreamReader(is));
// while((str=br.readLine())!=null){
// Log.i("test",str);
// }
//09.解析XML
try {
//03.使用PULL解析
XmlPullParser pullParser=Xml.newPullParser();
pullParser.setInput(is,"UTF-8");
int type=pullParser.getEventType();
while(type!=XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG:
//获取开始标签的名字
String startTagName=pullParser.getName();
if("fq".equals(startTagName)){
fq1 = new FQ();
String name=pullParser.getAttributeValue(0);
fq1.setName(name);
}else if("content".equals(startTagName)){
String content= pullParser.nextText();
fq1.setContent(content);
}else if("time".equals(startTagName)){
String time= pullParser.nextText();
fq1.setTime(time);
}
break;
case XmlPullParser.END_TAG:
//获取结束标签的名字
String endTagName=pullParser.getName();
if("fq".equals(endTagName)){
fqs.add(fq1);
}
break;
}
type=pullParser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return fqs;
}
//更新UI
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
List<FQ> fqs= (List<FQ>) o;
lists.addAll(fqs);
myAdapter.notifyDataSetChanged();
progressDialog.cancel();
}
}
}