谨以文章记录学习历程,如有错误还请指明。
XML简介
XML 指可扩展标记语言(EXtensible Markup Language),我们从两个角度理解它:
- 可扩展:可以把它用作任何用途:配置文件、UI描述文件等等
- 标记语言:HTML(超文本标记语言)也是标记语言,可以把HTML看做是XML的子语言。
从以上两点来看,XML就是一个文档结构的规范。文档的内容根据你的需要是什么都可以。描述配置文件,比如Spring的很多配置文件;UI描述,比如HTML和Android布局文件。
XML他只定义了文档的结构:成对的标记,属性的位置等等。至于这些标记和属性你解析成什么你自己决定。
XML解析
- 目的:从XML中提取我们需要的数据
- 分类:
解析方式 | 实现原理 | 具体类型 |
---|---|---|
基于文档驱动 | 解析前,将XML文件的所有内容读取到内存中 | DOM方式 |
基于事件驱动 | 根据不同需求事件执行不同解析操作 | SAX方式 Pull方式 |
Demo地址
示例xml文件(位于项目assets路径下)
<apps>
<app>
<id>1</id>
<name>Google Maps</name>
<version>1.0</version>
</app>
<app>
<id>2</id>
<name>Chrome</name>
<version>2.1</version>
</app>
<app>
<id>3</id>
<name>Google Play</name>
<version>2.3</version>
</app>
</apps>
DOM解析
简介
- DOM的全称是
Document Object Model
,也即文档对象模型 - 基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树)
- 通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。
- 使用DOM API遍历DOM树、检索所需的数据;
- DOM的全称是
特点:
优点:- 形成了树结构,有助于更好的理解、掌握,且代码容易编写。
- 解析过程中,树结构保存在内存中,方便修改。
缺点:
- 由于文件是一次性读取,所以对内存的耗费比较大。
- 如果XML文件比较大,容易影响解析性能且可能会造成内存溢出
- 解析实例
private void xml_dom(){
StringBuilder data = new StringBuilder();
try {
//打开assets文件夹下的xml示例文件到输入流
InputStream in = getAssets().open("example.xml");
//得到Document Builder Factory对象
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//得到Document Builder对象
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//得到Document存放整个xml的Document对象数据
Document document = builder.parse(in);
//得到xml数据的根节点
Element rootElement = document.getDocumentElement();
//得到根节点下所有app节点
NodeList list = rootElement.getElementsByTagName("app");
//遍历所有节点
for (int i = 0;i < list.getLength(); i++){
//获取app节点的所有子元素
Element app = (Element) list.item(i);
//获取app节点的子元素id,name,version,并添加到StringBuilder中
data.append("id is " + app.getElementsByTagName("id").item(0).getTextContent() + "\n");
data.append("name is " + app.getElementsByTagName("name").item(0).getTextContent() + "\n");
data.append("version is " + app.getElementsByTagName("version").item(0).getTextContent() + "\n");
}
//更新UI
dataText.setText(data);
}catch (Exception e){
e.printStackTrace();
}
}
SAX解析
- 简介
- SAX的全称是Simple APIs for XML,也即XML简单应用程序接口
- SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式
- 当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问
特点
优点- 采用事件驱动模式,解析速度快,占用内存少
- 非常适合在Android移动设备中使用
缺点
- 编码比较麻烦。
- 很难同时访问XML文件中的多处不同数据。
解析实例
/**
* SAX方式解析:需要新建类继承自DefaultHandler类,并重写弗雷德5个方法,如下所示
*/
class ContentHandler extends DefaultHandler{
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
private StringBuilder text;
//在开始XML解析的时候调用
@Override
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
text = new StringBuilder();
}
//在解析某个节点的时候调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
nodeName = localName;
}
//在获取节点内容时调用
//注意:获取内容时,该方法可能会被调用多次,同时换行符也会被当作内容解析出来
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if ("id".equals(nodeName)){
id.append(ch, start, length);
}else if ("name".equals(nodeName)){
name.append(ch, start, length);
}else if ("version".equals(nodeName)){
version.append(ch, start, length);
}
}
//在对某个节点的解析完成时调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("app".equals(localName)){
text.append("id is " + id.toString() + "\n");
text.append("name" + name.toString() + "\n");
text.append("version is " + version.toString() + "\n");
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
//整个XML解析完成的时候调用
@Override
public void endDocument() throws SAXException {
dataText.setText(text);
super.endDocument();
}
}
private void xml_sax(){
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
ContentHandler mHandler = new ContentHandler();
//打开assets文件夹下的xml示例文件到输入流
InputStream in = getAssets().open("example.xml");
parser.parse(in,mHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
Pull解析
- 简介
- PULL解析器的运行方式和SAX类似,都是基于事件的模式。
- 不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
特点
优点- PULL解析器小巧轻便,解析速度快,简单易用
- 灵活性高,自由控制访问时机
- 非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
缺点
- 可扩展性差,无法修改XML树内容结构
- 解析实例
private void xml_pull(){
/*
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new StringReader(xmlData));
} catch (XmlPullParserException e) {
e.printStackTrace();
}*/
StringBuilder builder = new StringBuilder("");
XmlPullParser parser = Xml.newPullParser();
try {
//打开assets文件夹下的xml示例文件到输入流
InputStream in = getAssets().open("example.xml");
parser.setInput(in,"UTF-8");
while (parser.getEventType() != XmlPullParser.END_DOCUMENT){
String nodeName = parser.getName();
int eventType = parser.getEventType();
switch (eventType){
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
if ("id".equals(nodeName)){
builder.append("id is : " + parser.nextText() + "\n");
}else if ("name".equals(nodeName)){
builder.append("name is : "+ parser.nextText() + "\n");
}else if ("version".equals(nodeName)){
builder.append("version is : "+ parser.nextText() + "\n");
}
break;
case XmlPullParser.END_TAG:
break;
}
parser.next();
}
dataText.setText(builder.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
总结
- 本文对Android中的XML的三种解析方式作出了总结
- 后续我会介绍另外另外一种主流的数据传输格式JSON,具体请移步Android-JSON解析(Gson、org.json、Jackson、FastJson)
- 笔者水平有限,如有错漏,欢迎指正。
- 接下来我也会将所学的知识分享出来,有兴趣可以继续关注whd_Alive的Android开发笔记
- 不定期分享Android开发相关的技术干货,期待与你的交流,共勉。