今天我们来了解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(); } } }