您的位置:首页 > 移动开发 > Android开发

Android开发之XML文件解析

2011-05-11 10:52 656 查看
xml文件得到了越来越多的应用,我们可以用它来存储程序的配置数据,也可以在网络上以xml文件传递数据集。所以我们需要学习在Android程序中解析xml文件的方法。由于Android的开发环境是Java,所以Android程序中解析xml文件的方法和Java中解析xml文件的方法是一样的。

1、 SAX 编程技术及SAX的处理机制
SAX是Simple API for XML的缩写,其处理机制是建立在流和事件的基础之上,即将XML看作是“流(stream) ”,SAX“读取器”在遇到XML的“构件”(如Element,Text等)时,会产生相应的事件,然后再利用注册在“解析器”上的事件处理器时进行事件处理。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parse()方法来开始解析XML文档并根据文档内容产生事件。而事件处理器则是org.xml.sax包中的ContentHandler,DTDHandler,ErrorHandler,以及EntityResolver这四个接口。它们分别处理事件源在解析过程中产生的不同种类的事件(其中DTDHandler是为解析文档DTD时而用)。而事件源XMLReader和这四个事件处理器的连接是通过在XMLReader中的相应的事件处理器注册方法set***()来完成的。

xml框架结构图



SAX解析并不透明的进行存储及创建任何数据结构,而此类工作完全交给用户实现的事件处理器。

2、 解析器及主要的SAX API说明
(1)SAXParserFactory:

其为SAXParser对象的工厂对象,使应用程序能够配置和获取基于 SAX 的解析器以解析 XML 文档。

获取该类实例的方法:SAXParserFactory.newInstance()

(2)SAXParser(解析器)

利用其包装的XMLReader(包装器)解析来自文件、输入流、URL中的XML,并把解析事件报告给提定的处理器。

* 获取XMLReader方法:

XMLReader reader=SAXParserFactory.newInstance().newSAXParser().getXMLReader();

reader.parse(InputSource input);

(3)DefaultHandler

为了实现ContentHandler接口,不得不把ContentHandler中所有的抽象方法都实现,这样比较麻烦。SAX API已经考虑到这个问题,在它的org.xml.sax.helper包中为我们提供了一个方便实现各种处理器接口的帮助类DefaultHandler。其实现了四个核心 SAX2 处理程器接口中的所有回调(适配器模式),该类需要开发者自行继承,并实现“感兴趣”的方法。

四个核心的SAX2处理器接口为:

EntityResolver

DTDHandler

ContentHandler[H21] (构件)

ErrorHandler

3、 事件处理器中的各个方法定义及功能
void startDocument():在文档开始处的事件处理方法(回调方法)

void endDocument():在文档结束的事件处理方法

void startElement(String uri,String lname,String qname,Attributs attrs(属性处理)):在元素开始处的事件处理方法

void endElement(String uri,String lname,String qname):在元素结束处的事件处理方法

uri:名字空间的URI(如果支持名字空间)

lname:返回元素的限定名,<bean>返回bean,而<util:list>返回list(如果支持名字空间)

qname:带前缀元素名(如果支持名字空间),如<util:list>将返回util:list

attrs:返回该元素全部属性对象

characters(char[] data,int index,int length):当遇到字符数据时的事件处理方法。

data:为XML字符串构成的数组(每次根据缓冲区大小进行传递向后滚动)

index:当前字符串中第一个字符在data中的位置

length:当前字符串长度

4、 SAX 编程方法
4.1、 工作原理:
<bookCase>

<book id="1">

<title>spring in action(中文版)</title>

</book>

</bookCase>

当一个SAXParser遇到以上的XML时,依次会调用:startDocument,startElement,startElement,startElement,characters(如内容很长可能会有若干次),endElement, endElement, endElement,endDocument。

4.2、 实现步骤:
(1)实现继承自DefalutHandler适配器的实现类,覆写“感兴趣”的方法。

(2)获得SAXParserFactory实例。

(3)由SAXParserFactory获得XMLReader实例。

(4)注册处理文档内容解析事件的ContentHandler

(5)调用XMLReader实例的parser方法,此时需给出“XML源”

示例:新建一个Android应用程序,在main.xml中添加一个按钮,当我们点击这个按钮时将会从本地tomcat服务器上下载一个xml文件,将xml文件的内容保存在String对象中。然后用SAX解析这个String对象。

需要说明的是xml源文件中各标签之间如果要有空格、Tap键等格式字符,因为SAX会把空格、Tab键解析成一个空白节点。这样的话可能会使程序不能输出我们想要显示的内容。在ContentHandler中重写处理空格的方法可以解决这个问题。这里为了简单起见,不再重写处理空格等字符的方法。

下载的xml文件:

]<?xml version="1.0" encoding="utf-8"?>
<workers>
<worker id="No1">
<name>Mark</name>
<sex>male</sex>
<status>CEO</status>
<address>Beijing</address>
<money>200000</money>
</worker>
<worker id="No2">
<name>Bill</name>
<sex>male</sex>
<status>CTO</status>
<address>Beijing</address>
<money>180000</money>
</worker>
<worker id="No3">
<name>Lucy</name>
<sex>female</sex>
<status>CFO</status>
<address>Beijing</address>
<money>180000</money>
</worker>
</workers>


源代码:

main.xml

]<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/button"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="解析XML文件"
/>
</LinearLayout>


Android_xml.java

]package idea.org;

import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Android_xml extends Activity {
private Button button;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button=(Button)findViewById(R.id.button);
button.setOnClickListener(new buttonClickListener());
}
class buttonClickListener implements OnClickListener
{

/* (non-Javadoc)
* @see android.view.View.OnClickListener#onClick(android.view.View)
*/
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread()
{
public void run()
{
HttpDownloader httpDownloader=new HttpDownloader();
String xmlStr=httpDownloader.download("http://192.168.0.5:8080/Android/test.xml");
try {
//获得SAXParser对象的工厂实例
SAXParserFactory saxParserFactory=SAXParserFactory.newInstance();
//获得XMLReader示例
XMLReader reader=saxParserFactory.newSAXParser().getXMLReader();
//注册处理XML文档内容解析事件的ContentHandler
reader.setContentHandler(new MyContentHandler());
//开始解析string对象中所包含的XML资源
reader.parse(new InputSource(new StringReader(xmlStr)));
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}

}
}


MyContentHandler.java

]package idea.org;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class MyContentHandler extends DefaultHandler
{
private String name,sex,address,money,status,tagName;
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
System.out.println("--------开始解析--------");
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
//遇到新的标签即新的元素时执行
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
tagName=localName;//以tagName的值来判断正在解析哪个标签
if(localName.equals("worker"))
{//依次获取标签的全部属性
for(int i=0;i<attributes.getLength();i++)
System.out.println(attributes.getLocalName(i)+"="+attributes.getValue(i));
}
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
if(tagName.equals("name"))
name=new String(ch,start,length);
else if(tagName.equals("sex"))
sex=new String(ch,start,length);
else if(tagName.equals("status"))
status=new String(ch,start,length);
else if(tagName.equals("address"))
address=new String(ch,start,length);
else if(tagName.equals("money"))
money=new String(ch,start,length);

}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
//标签解析完成之后执行
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
tagName="";//清除tagName原来的值,这样在遇到空白节点时可以通过tagName识别出处理的是空白节点
if(localName.equals("worker"))
{//打印出所有得到的数据
System.out.print("name:"+name);
System.out.print("  sex:"+sex);
System.out.print("  status:"+status);
System.out.print("  address:"+address);
System.out.println("  money:"+money);
}
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endDocument()
*/
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
System.out.println("--------解析结束--------");
}

}


HttpDownloader.java

]package idea.org;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpDownloader {
private URL url=null;
public String download(String urlStr)
{
StringBuffer stringbuffer=new StringBuffer();
String line;
BufferedReader bufferReader=null;
try
{
//创建一个URL对象
url=new URL(urlStr);
//得到一个HttpURLConnection对象
HttpURLConnection httpUrlConnection=(HttpURLConnection) url.openConnection();
// 得到IO流,使用IO流读取数据
bufferReader=new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream()));
while((line=bufferReader.readLine())!=null)
{
stringbuffer.append(line);
}
}
catch(Exception e)
{
e.printStackTrace();
}
return stringbuffer.toString();

}
// 该函数返回整形 -1:代表下载文件出错 ;0:代表下载文件成功; 1:代表文件已经存在
public int download(String urlStr,String path,String fileName)
{
InputStream inputstream=null;
FileUtils fileUtils=new FileUtils();
if(fileUtils.isExist(path+fileName))
return 1;
else
{
try {
inputstream=getFromUrl(urlStr);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File file=fileUtils.writeToSDPATHFromInput(path, fileName, inputstream);
if(file!=null)
return 0;
else
return -1;
}
}
//根据url字符串得到输入流
public InputStream getFromUrl(String urlStr) throws IOException
{
url=new URL(urlStr);
HttpURLConnection httpUrlConnection=(HttpURLConnection) url.openConnection();
InputStream input=httpUrlConnection.getInputStream();
return input;
}
}


FileUtil.java

]package idea.org;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Environment;

public class FileUtils {
private String SDPATH=null;
public String getSDPATH()
{
return SDPATH;
}
public FileUtils()
{
//获得当前外部存储设备SD卡的目录
SDPATH=Environment.getExternalStorageDirectory()+"/";
}
//创建文件
public File createFile(String fileName) throws IOException
{
File file=new File(SDPATH+fileName);
file.createNewFile();
return file;
}
//创建目录
public File createDir(String fileName) throws IOException
{
File dir=new File(SDPATH+fileName);
dir.mkdir();
return dir;
}
//判断文件是否存在
public boolean isExist(String fileName)
{
File file=new File(SDPATH+fileName);
return file.exists();
}
public File writeToSDPATHFromInput(String path,String fileName,InputStream inputstream)
{
File file=null;
OutputStream outputstream=null;
try
{
createDir(path);
file=createFile(path+fileName);
outputstream=new FileOutputStream(file);
byte buffer[]=new byte[1024];
//将输入流中的内容先输入到buffer中缓存,然后用输出流写到文件中
while((inputstream.read(buffer))!=-1)
{
outputstream.write(buffer);
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try {
outputstream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return file;
}
}


AndroidManifest.xml

]<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="idea.org"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="11" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Android_xml"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>


运行结果:

界面:



点击“解析XML文件”按钮打印以下内容:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: