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

Android解析压缩的xml文件

2017-03-19 01:31 239 查看

Android解析压缩的xml文件

本文主要介绍xml文件解析,主要是想讲手机内压缩文件xml的解析,但是也顺便讲一下在目录assets中的xml文件的解析。

这里压缩文件的解析,一般做法是把压缩文件解析到相同目录下,得到File对象后,对xml文件进行解析。

Xml文件解析是有三种方法的,这里使用的是sax解析,其他的还有pull解析和DOM解析,关于使用哪种解析方法好,在本文最后会说一下的。

要解析的文件cd.xml(压缩文件:cd.zip):

<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
。。。(后面还有几个CD!)
</CATALOG>


数据解析后的界面设计效果:



点击删除可以删除相应的条目。但是只是视图上面的,文件内容没有做删除操作!

关键代码:

(一)从assets中得到文件的输入流

// 从assets里面获取文件,
// 通过getAssets获取到的是读取流
InputStream   is = context.getAssets().open(assetXmlName);


(二)解压文件的方法,直接拿来用就可以!

/*
* 这个是解压ZIP格式文件的方法
*
* @zipFileName:是传进来你要解压的文件路径,包括文件的名字;
*
* @outputDirectory:选择你要保存的路劲;
*
*/
public void  unzip(String zipFileName, String outputDirectory)
throws Exception {
ZipInputStream in = new ZipInputStream(new FileInputStream(zipFileName));

Log.e("TAG", "in==null"+(in==null));

ZipEntry z;
String name = "";
String extractedFile = "";
int counter = 0;

while ((z = in.getNextEntry()) != null) {
name = z.getName();
Log.d("TAG", "unzipping file: " + name);
if (z.isDirectory()) {
Log.d("TAG", name + "is a folder");
// get the folder name of the widget
name = name.substring(0, name.length() - 1);
File folder = new File(outputDirectory + File.separator + name);
folder.mkdirs();
if (counter == 0) {
extractedFile = folder.toString();
}
counter++;
Log.d("TAG", "mkdir " + outputDirectory + File.separator + name);
} else {
Log.d("TAG", name + "is a normal file");
File file = new File(outputDirectory + File.separator + name);
file.createNewFile();
// get the output stream of the file
FileOutputStream out = new FileOutputStream(file);
int ch;
byte[] buffer = new byte[1024];
// read (ch) bytes into buffer
while ((ch = in.read(buffer)) != -1) {
// write (ch) byte from buffer at the position 0
out.write(buffer, 0, ch);
out.flush();
}
out.close();
}
}

in.close();

}


程序设计的全部代码:

(一)布局文件activity_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:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="CD资料"
android:padding="10dp"
android:textSize="40sp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#f00"

>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="歌名"
android:textSize="20sp"
/>

<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="作者"
android:textSize="20sp"
/>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="国籍"
android:textSize="20sp"
/>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="公司"
android:textSize="20sp"
/>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="价格"
android:textSize="20sp"
/>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="出版年"
android:textSize="20sp"
/>
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="编辑"
android:textSize="20sp"
/>
</LinearLayout>

<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView"
/>
</LinearLayout>


(二)ListView中条目的布局文件item_data.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_title"
android:textSize="10sp"
android:gravity="center"
/>

<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_artist"
android:textSize="10sp"
android:gravity="center"
/>

<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_country"
android:textSize="20sp"
android:gravity="center"
/>

<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_company"
android:textSize="10sp"
android:gravity="center"
/>

<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_price"
android:textSize="20sp"
android:gravity="center"
/>
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/tv_year"
android:textSize="20sp"
android:gravity="center"
/>

<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="60dp"
android:id="@+id/btn_delete"
android:textSize="20sp"
android:gravity="center"
android:text="删除"
/>

</LinearLayout>


(三)XmlBean文件

package com.example.seeview;

/**
*  Bean文件,定义数据原型
*/
public class XmlBean {

//定义属性
private  String  title;
private  String  artist;
private  String  country;
private  String  company;
private  float  price;
private  int  year;

//定义get和set方法
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}

//定义toString方法
@Override
public String toString() {
return "XmlBean [title=" + title + ", artist=" + artist
+ ", country=" + country + ", company=" + company
+ ", price=" + price + ", year=" + year + "]";
}

}


(四)解压工具类ZipToFileUtil

package com.example.seeview;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import android.util.Log;

public class ZipToFileUtil {

/*
* 这个是解压ZIP格式文件的方法
*
* @zipFileName:是传进来你要解压的文件路径,包括文件的名字;
*
* @outputDirectory:选择你要保存的路劲;
*
*/
static void  unzip(String zipFileName, String outputDirectory)
throws Exception {
ZipInputStream in = new ZipInputStream(new FileInputStream(zipFileName));

Log.e("TAG", "in==null"+(in==null));

ZipEntry z;
String name = "";
String extractedFile = "";
int counter = 0;

while ((z = in.getNextEntry()) != null) {
name = z.getName();
Log.d("TAG", "unzipping file: " + name);
if (z.isDirectory()) {
Log.d("TAG", name + "is a folder");
// get the folder name of the widget
name = name.substring(0, name.length() - 1);
File folder = new File(outputDirectory + File.separator + name);
folder.mkdirs();
if (counter == 0) {
extractedFile = folder.toString();
}
counter++;
Log.d("TAG", "mkdir " + outputDirectory + File.separator + name);
} else {
Log.d("TAG", name + "is a normal file");
File file = new File(outputDirectory + File.separator + name);
file.createNewFile();
// get the output stream of the file
FileOutputStream out = new FileOutputStream(file);
int ch;
byte[] buffer = new byte[1024];
// read (ch) bytes into buffer
while ((ch = in.read(buffer)) != -1) {
// write (ch) byte from buffer at the position 0
out.write(buffer, 0, ch);
out.flush();
}
out.close();
}
}

in.close();

}

}


(五)解析xml文件类

package com.example.seeview;

import android.content.Context;
import android.util.Log;

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

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
* 解析xml文件的类,这里使用sax解析数据
*
*/
public class ParseXml {
Context context;  //上下文
File xmlFileName;
String assetXmlName;//assets文件的名字
// 要解析文件的输入流
InputStream is;
// 创建一个List集合存放从XML文件获取到的数据
List<XmlBean> list = null;
XmlBean xmlBean = null;

//定义构造方法传人上下文
ParseXml(Context context,File xmlFileName){
this.context=context;
this.xmlFileName=xmlFileName;
}

//定义构造方法传人上下文
ParseXml(Context context,String assetXmlName){
this.context=context;
this.assetXmlName=assetXmlName;
}

// 使用SAX方法解析的结果  ,并返回集合对象
public  List<XmlBean> saxXmlToList() {
try {

if (assetXmlName!=null) {
// 从assets里面获取文件,
// 通过getAssets获取到的是读取流
is = context.getAssets().open(assetXmlName);
}else if (xmlFileName!=null) {
//从文件对象
is=new FileInputStream(xmlFileName);
}

// 取得SAXParserFactory实例
SAXParserFactory factory = SAXParserFactory.newInstance();
// 从factory获取SAXParser实例
SAXParser parser = factory.newSAXParser();
// 实例化定义的Handler
Myhandler handler = new Myhandler();
// 根据Handler规则解析输入流
parser.parse(is, handler);
// 打印信息
handler.showMessage();

//返回集合对象
return    list;

} catch (Exception e) {
e.printStackTrace();
}

return null;
}

//实现SAX方法解析数据必须要借助DefaultHandler 类的实现
class Myhandler extends DefaultHandler {

StringBuffer sb = null;

// 根标签开始时
@Override
public void startDocument() throws SAXException {
super.startDocument();
list = new ArrayList<XmlBean>();
sb = new StringBuffer();
}

// 节点开始时
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// 当遍历到Car节点就新建Car对象
if (localName.equals("CD")) {
xmlBean = new XmlBean();
//                car.id = attributes.getValue(0);// 获取第一个属性值,节点值在后面获取
}
// 将字符长度设置为零,以便从新开始读取元素内就字符节点
sb.setLength(0);
}

// 读取字符流
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
sb.append(ch, start, length);

}

// 节点结束时
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);

//判断节点并给对象赋值
if (localName.equals("TITLE")) {
xmlBean.setTitle( sb.toString());
} else if (localName.equals("ARTIST")) {
xmlBean.setArtist( sb.toString());
}else if (localName.equals("COUNTRY")) {
xmlBean.setCountry( sb.toString());
}else if (localName.equals("COMPANY")) {
xmlBean.setCompany( sb.toString());
}else if (localName.equals("PRICE")) {
xmlBean.setPrice( Float.parseFloat(sb.toString()));
}else if (localName.equals("YEAR")) {
xmlBean.setYear( Integer.parseInt(sb.toString()));
}else if (localName.equals("CD")) {//当一个回合结束再添加数据,很关键
list.add(xmlBean);
}

}

public void showMessage() {
// 打印获得的数据
for (XmlBean c : list) {
Log.e("TAG", c.toString());
}

}

}

//上面是SAX方法解析数据的过程

}


(六)ListView的适配器类

package com.example.seeview;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;

import java.util.List;

/**
*    ListView的适配器,传人集合数据
*/
public class DataAdapter extends BaseAdapter{
// 创建一个List集合存放从XML文件获取到的数据
List<XmlBean> list = null;
Context context;
//构造器传人集合对象
DataAdapter(Context context,List<XmlBean> list){
this.list=list;
this.context=context;
}

//返回集合的数据量
public int getCount() {
return list.size();
}

//每一条数据对于的对象
public  XmlBean getItem(int position) {
return list.get(position);
}

//条码的ID
public long getItemId(int position) {
return position;
}

//每个条目的试图对象
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView==null){
convertView=View.inflate(context,R.layout.item_data,null);
viewHolder=new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else{
viewHolder= (ViewHolder) convertView.getTag();
}
//给ListView的条码设置内容
viewHolder.tv_title.setText(list.get(position).getTitle());
viewHolder.tv_artist.setText(""+list.get(position).getArtist());
viewHolder.tv_country.setText(""+list.get(position).getCountry());
viewHolder.tv_company.setText(""+list.get(position).getCompany());
viewHolder.tv_price.setText(""+list.get(position).getPrice());
viewHolder.tv_year.setText(""+list.get(position).getYear());
//给按钮设置点击事件
viewHolder.btn_delete.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//list.remove(position); //删除这个条目,在主方法操作
if(iDeleteData!=null){
iDeleteData.deleteData(position);//传递数据(点击的条目的序列号)
}
}
});
return convertView;
}

//创建ViewHolder类
class ViewHolder{
TextView tv_title;
TextView tv_artist;
TextView tv_country;
TextView tv_company;
TextView tv_price;
TextView tv_year;
Button btn_delete;
ViewHolder(View view){
tv_title= (TextView) view.findViewById(R.id.tv_title);
tv_artist= (TextView) view.findViewById(R.id.tv_artist);
tv_country= (TextView) view.findViewById(R.id.tv_country);
tv_company= (TextView) view.findViewById(R.id.tv_company);
tv_price= (TextView) view.findViewById(R.id.tv_price);
tv_year= (TextView) view.findViewById(R.id.tv_year);
btn_delete= (Button) view.findViewById(R.id.btn_delete);
}

}

//设置一个回调接口
interface  IDeleteData{
void deleteData(int position);
}

//定义接口对象
IDeleteData iDeleteData;
//设置监听对象

public void setiDeleteData(IDeleteData iDeleteData) {
this.iDeleteData = iDeleteData;
}
}


(七)主方法类

package com.example.seeview;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import android.app.Activity;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
// 创建一个List集合存放从XML文件获取到的数据
List<XmlBean> list = null;
//布局的ListVIew
ListView listView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView= (ListView) findViewById(R.id.listView);
//创建解析对象
//解析Assets文件,输入文件名即可
ParseXml parseXml=new ParseXml(this,"cd.xml");
//解析本地的也是文件,要先解压文件
//        String outputDirectory="mnt/sdcard/";
//        String zipFileName="cd.zip";
//        String outputFileName="cd.xml";
//        try {
//          ZipToFileUtil.unzip(outputDirectory+zipFileName, outputDirectory);
//          ParseXml parseXml=new ParseXml(this,new File(outputDirectory+outputFileName));
//      } catch (Exception e) {
//          Toast.makeText(this, "解压文件失败", Toast.LENGTH_LONG).show();
//          finish();
//          e.printStackTrace();
//      }
//解析数据,并返回结果
list= parseXml.saxXmlToList();

//创建Adapter,使用BaseAdapter
final DataAdapter adapter=new DataAdapter(this,list);
listView.setAdapter(adapter);

//设置删除的监听
adapter.setiDeleteData(new DataAdapter.IDeleteData() {
public void deleteData(int position) {
list.remove(position);//删除条目数据
adapter.notifyDataSetChanged(); //刷新适配器

}
});
}

}


如果要解析手机中的压缩文件,要保证路径是正确的,并且要添加读写权限。上面解析压缩文件的代码已经注释调了,反注释后,并注释解析assets文件夹的文件的代码,运行,即可得到下面相同的效果。

手机运行后的效果;



这里说一下,三种解析数据的应用场合:

Sax解析,适合读取整个文件的所有内容,并且是读取一次,速度较快。

Pull解析,适合读取文件中某些节点的数据,速度最快。

DOM解析,适合读取读取整个文件,并且可以反复获取,适合对一个文件的数据进行反复读取时使用,但是DOM耗时较多,它是把整个文档缓存下来!

本文中的xml文件,读取一次全部内容,并存储到集合中,是最有效的处理方法!也就是sax文件解析方式的使用。

这里有我之前专门解析xml数据的三种方法的总结和它们的使用示例:

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