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

Android基础 基本的xml文件解析的方式

2014-11-05 21:42 288 查看

DOM解析:将整个文档载入组成一颗节点树在通过节点与节点之间的关系来解析xml文件
基础知识:
在Dom解析的过程中,是先把dom全部文件读入到内存中,然后使用dom的api遍历所有数据,检索想要的数据,这种方式显然是一种比较消耗内存的方式,对于像手机这样的移动设备来讲,内存是非常有限的,所以对于比较大的XML文件,不推荐使用这种方式,但是Dom也有它的优点,它比较直观,在一些方面比SAX方式比较简单。在xml文档比较小的情况下也可以考虑使用dom方式。
步骤1:
1、调用 DocumentBuilderFactory.newInstance() 方法得到 DOM 解析器工厂类实例。
2、调用解析器工厂实例类的 newDocumentBuilder() 方法得到 DOM 解析器对象
3、调用 DOM 解析器对象的 parse() 方法解析 XML 文档得到代表整个文档的 Document 对象。

步骤 (详细) :要拿到Document的对象document 节点树
要先拿到器Document的构建器DocumentBuilder对象通过DocumentBuilderFactory().newinstence().new DocumentBuilder()对象builder
通过builder.parse(参数)解析拿到Document对象() document;
document.getElementByTagName()来获取节点集合
Foreach遍历集合 拿到其中的每一项 转化成ELement 类型的对象
Element 通过element.getAttribute(“属性名”)来获取属性值
通过这个对象可以拿到所有的子节点
element.getChildNodes()
遍历子节点集合 判断其类型 是不是元素节点
是的话就就获取里面的文本节点

public void test() throws Exception {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File dir = Environment.getExternalStorageDirectory();// 获取sd卡路径
File file = new File(dir, "news.xml");// 创建文件对象
InputStream is = new FileInputStream(file);// 创建流
parseDom(is);
}
}

/**
* DOM解析 将整个文档都加载进来 相拿那个节点就拿哪个节点
*
* @param is
* @throws Exception
*/
public void parseDom(InputStream is) throws Exception {
// 拿到构建器 先拿到工厂类通过newinstance拿到工厂类对象在通过newDocumentBUilder拿到构建器
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document document = builder.parse(is);// 通过解析拿到document对象即文档树(document对象是文档树的根)
// 文档树调用getElementByTagName(Tagname name节点名)来获取你想要节点的信息返回一个节点集合NodeList
NodeList list = document.getElementsByTagName("news");
// 创建一个集合用来存储获取的新闻信息
List<News> data = new ArrayList<News>();
// 循环遍历节点集合分别拿到
for (int i = 0; i < list.getLength(); i++) {
News news = new News();
Element element = (Element) list.item(i);// 节点集合通过item(int
// i)的方法拿到每一项并将其转换为元素Element类型
// 转换成元素类型 元素类型调用
// 元素类型的对象通过getAttribute(属性名)获取属性的方法获取元素对应得属性值
news.id = Integer.valueOf(element.getAttribute("id"));
// 元素要获取所有器包含的子节点 通过getChildNodes()方法来得到子节点的节点集合
NodeList childs = element.getChildNodes();
// 循环拿到每一个子节点对应的属性值
for (int j = 0; j < childs.getLength(); j++) {
// 因为里面有空格也是文本节点所以我们获取没一项的节点类型如果是元素节点就取其中的属性值
if (childs.item(j).getNodeType() == Node.ELEMENT_NODE) {
if (childs.item(j).getNodeName().equals("title")) {
// 首先拿到这个节点的子节点即文本节点在拿到属性
news.title = childs.item(j).getFirstChild()
.getNodeValue();
} else if (childs.item(j).getNodeName().equals("context")) {
// 首先拿到这个节点的子节点即文本节点在拿到属性
news.context = childs.item(j).getFirstChild()
.getNodeValue();
}
}
}
data.add(news);
}
for (News news : data) {
System.out.println(news.id + " " + news.title + " "
+ news.context + " ");
}
}

SAX解析:边加载边读
这种方式解析是一种基于事件驱动的api,有两个部分,解析器和事件处理器,解析器就是XMLReader接口,负责读取XML文档,和向事件处理器发送事件(也是事件源),事件处理器ContentHandler接口,负责对发送的事件响应和进行XML文档处理。
下面是ContentHandler接口的常用方法
public abstract void characters (char[] ch, int start, int length)
这个方法来接收字符块通知,解析器通过这个方法来报告字符数据块,解析器为了提高解析效率把读到的所有字符串放到一个字符数组(ch)中,作为参数传递给character的方法中,如果想获取本次事件中读取到的字符数据,需要使用start和length属性。
public abstract void startDocument () 接收文档开始的通知
public abstract void endDocument () 接收文档结束的通知
public abstract void startElement (String uri, String localName, String qName, Attributes atts) 接收文档开始的标签
public abstract void endElement (String uri, String localName, String qName) 接收文档结束的标签
在一般使用中为了简化开发,在org.xml.sax.helpers提供了一个DefaultHandler类,它实现了ContentHandler的方法,我们只想继承DefaultHandler方法即可。
另外SAX解析器提供了一个工厂类:SAXParserFactory,SAX的解析类为SAXParser 可以调用它的parser方法进行解析。

步骤:
1、实例化一个工厂SAXParserFactory
2、实例化SAXPraser对象,创建XMLReader 解析器
3、实例化handler,处理器
4、解析器注册一个事件
4、读取文件流
5、解析文件
代码:
public void test() throws Exception {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File dir = Environment.getExternalStorageDirectory();// 获取sd卡路径
File file = new File(dir, "news.xml");// 创建文件对象
InputStream is = new FileInputStream(file);// 创建流
//parseDom(is);
parseSAX(is);
//parsePull(is);
}
}

/***
* SAX解析 从头到尾顺序读一遍 边加载边读
*
* @throws SAXException
* @throws ParserConfigurationException
* @throws IOException
****/
public void parseSAX(InputStream is) throws ParserConfigurationException,
SAXException, IOException {
//实例化SAXparser对象
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
//实例化MydefaultHandler对象 事件处理器
MyDefaultHandler dh = new MyDefaultHandler();
//解析文件
parser.parse(is, dh);
List<News> list=dh.show();
for (News news : list) {
System.out.println(news.id+" "+news.context+" "+news.title+" ");
}
}

class MyDefaultHandler extends DefaultHandler {
public List<News> list;
public News news;
public String currentName;
public List<News> show(){
return list;
}

/** 开始
*在这里创建存储数据的集合
*/

@Override
public void startDocument() throws SAXException {
super.startDocument();
list = new ArrayList<News>();
}

/*** 开始读元素节点
* localName不带前缀的名字
* qName带前缀的名字
* attributes 属性
* 先判断节点的名字是不不是你想要获取的节点的名字如果是就获取
* 并从属性中拿到属性值
* currentName用来标记节点的名字执行一次currentName就会改变
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (qName.equals("news")) {
news = new News();
news.id=Integer.parseInt(attributes.getValue("id"));//通过属性来获取属性值
}
currentName = qName;
}

/** 读到文本节点
* ch读到的文本节点的数组
* start数组开始位置
* length数组长度
* 判断currentName是那个元素节点的名字在拿到元素节点中的文本节点的内容
* */
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
if("title".equals(currentName)){
String title=new String(ch, start, length);
news.title=title;
}else if("context".equals(currentName)){
String context=new String(ch, start, length);
news.context=context;
}
}

/** 读完元素节点
* 将currentName置空以便于读取下一个元素节点
* 判断结束的时候节点带前缀的名字(qname)是不是与刚开始读到的节点名字相同
* 如果相同就将其添加到集合中
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
currentName=null;
if(("news").equals(qName)){//判断结束的节点名
list.add(news);
}
}

/** 读完文本 */
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
}

pull解析
基础知识
在android系统中,很多资源文件中,很多都是xml格式,在android系统中解析这些xml的方式,是使用pul解析器进行解析的,它和sax解析一样(个人感觉要比sax简单点),也是采用事件驱动进行解析的,当pull解析器,开始解析之后,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
代码:
public void test() throws Exception {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File dir = Environment.getExternalStorageDirectory();// 获取sd卡路径
File file = new File(dir, "news.xml");// 创建文件对象
InputStream is = new FileInputStream(file);// 创建流
//parseDom(is);
//
parseSAX(is);
parsePull(is);
}
}

/**
* pull解析
* @throws XmlPullParserException
* @throws IOException
* 要先拿到解析器 通过XmlPullParsefactory.newINstance().newPullParser
* 设置文件流
* 获得事件对应的int值
* 获取节点名在事件里进行操作
* 获取属性值的方法parser.getAttributeValue(null,"id");
* 获取下一个文本节点gettext();
*/
public void parsePull(InputStream is) throws XmlPullParserException, IOException{
XmlPullParser parser=XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(is, "UTF-8");
List<News> news = null;
News news2 = null;
int eventType=parser.getEventType();
while(eventType!=XmlPullParser.END_DOCUMENT){
String nodeName=parser.getName();
switch(eventType){
case XmlPullParser.START_DOCUMENT:
news=new ArrayList<News>();//在开始读文档的时候就创建好存储的集合
break;
case XmlPullParser.START_TAG://元素节点
if("news".equals(nodeName)){//判断读取到的元素名字是不是news
news2=new News();//是就创建一个News对象
//通过getAttributeValue拿到属性值
news2.id=Integer.valueOf(parser.getAttributeValue(0));
}else if("title".equals(nodeName)){
news2.title=parser.nextText();
}else if("context".equals(nodeName)){
news2.context=parser.nextText();
}
break;
case XmlPullParser.END_TAG://元素节点结束的时候要判断结束的节点
if("news".equals(nodeName)){
news.add(news2);
news2=null;
}
break;
}
eventType=parser.next();
}
for (News news3 : news) {
System.out.println(news3.id+" "+news3.title+" "+news3.context);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: