XML即可扩展标记语言,它和HTML很类似,但是又与HTML有很多不同之处,XML用于传输和存储数据,而HTML则是为了显示数据,单从代码上来看,XML*大的特点就是标签没有被预定义,不像HTML那样必须使用固定的预定义元素集。

上面也说到了,XML是用来存储数据的,这时候就不得不与同时具有存储功能的JSON格式来进行一下对比了。

1.在可读性方面,JSON和XML的可读性基本相同。

2.在扩展性方面,XML和Json同时具有较好的扩展性,没有什么是XML能够扩展,而JSON不能的。

3.在解码难度方面,XML解析时,需考虑子节点和父节点,而JSON的解码难度几乎为0。

4.在数据体积大小方面,JSON相对于XML来说,数据的体积小,传输的速度更快些。

5.在数据交互方面,JSON和JavaScript的交互更加方便,更容易解析处理,具有更好的数据交互。

上面只是简单的挑拣了几条他们之间的区别,更多的区别希望大家在使用的过程中自己体会。

下面再给大家说一下XML严格定义的语法要求:

1.关于XML元素的命名

名称可以含字母,数字以及其他的字符,但不能够以数字或者标点符号开始,下划线除外。

名称不能够以xml(XML,Xml,xmL等)开始。

名称不能够包含空格。

可使用任何的名称,没有保留的字词。

2.XML文档必须有根元素

3.每个开始标签必须要有一个结束标签

4.所有的标签都要区分大小写

5.所有的标签都必须合理嵌套

6.所有标签的属性值必须用双引号或者单引号包括起来

7.在XML中文档中的空格不会被删除,会被原样保留下来

8.关于XML实体的问题

在XML中一些字符拥有特殊的意义,例如,若把”<“放在XML元素中,会发生错误,这是因为解析器会把它当作新元素的开始。错误如下:

<note>if count < 10 then </note>

这就是非法的,为此,需要使用实体引用来代替”<“字符。即:

<note>if count  &lt; 10 then </note>
在XML中有五个预定义的实体引用,虽然在XML中只有字符<和&时非法的,但是还是鼓励大家把实体引用代替作为一个好习惯。

%title插图%num
好了现在我们来说一下,在Android中时如何解析XM了格式的。

在Android中,XML文件解析*常用的有DOM,SAX,PULL3中解析方式,下面就分别来介绍这3中解析方式。

一、DOM解析XML

DOM解析XML文件时,会将XML文件的所有内容以文档树的方式存放在内存中,然后允许用户使用DOM API遍历XML树,检索所需的数据。

由于解析时会把所有的文件读入内存,所以内存消耗较大,尤其是在Android移动设备上。所以建议使用SAX和PULL进行解析,但是如果XML文件内容较小的话,采用DOM也是可行的。

DOM解析XML文件的基本思路如下:

1)利用DocumentBuilderFactory创建一个DocumentBuilderFactory实例。

2)利用DocumentBuilderFactory创建一个DocumentBuilder。

3)加载XML文档(Document)。

4)获取文档的根节点(Element)。

5)获取根节点中所有的列表(NodeList)。

6)获取子节点列表中所需要读取的点。

本次示例给大家解析一下assets目录下的city.xml文件,文件内容如下:

<?xml version=”1.0″?>

<citys>

<city id=”0″>

<name>Alaska</name>

<code>907</code>

</city>

<city id=”1″>

<name>Chicago</name>

<code>312</code>

</city>

<city id=”3″>

<name>Hawaii</name>

<code>808</code>

</city>

</citys>

首先先定义一个实体类City,其中包括对应属性的set和get方法,具体代码如下:

public class City {
private String name;
private String code;
private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return “City [name=”+name+”,code=”+code+”,id=”+id+”]”;
}
}

使用DOM解析的具体操作如下:

public class MainActivity extends AppCompatActivity {

private static final String TAG = “DomParseXml”;
private static final String CITY_NAME = “name”;
private static final String CITY_ID = “id”;
private static final String CITY_CODE = “code”;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parseXml();
}

private List<City> parseXml() {
List<City> Citys = new ArrayList<City>();
DocumentBuilder builder;
DocumentBuilderFactory factory = null;
Document document = null;
InputStream inputStream = null;
factory = DocumentBuilderFactory.newInstance();
try {
builder = factory.newDocumentBuilder();
inputStream = getResources().getAssets().open(“city.xml”);
document = builder.parse(inputStream);
Element root = document.getDocumentElement();
NodeList nodes = root.getElementsByTagName(“city”);
City city = null;
for (int i = 0; i < nodes.getLength(); i++) {
city = new City();
Element cityElement = (Element) nodes.item(i);
city.setId(cityElement.getAttribute(CITY_ID));
Element cityNameElement = (Element) cityElement.getElementsByTagName(CITY_NAME).item(0);
city.setName(cityNameElement.getFirstChild().getNodeValue());
Element cityCodeElement = (Element) cityElement.getElementsByTagName(CITY_CODE).item(0);
city.setCode(cityCodeElement.getFirstChild().getNodeValue());
Citys.add(city);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return Citys;
}
}

二、SAX解析XML

SAX是基于事件驱动的,边加载边解析,当然Android的事件机制是基于回调函数的,在使用SAX解析XML文档时,在读取到文档开始和结束标签时就会回调一个事件,在读取到其他节点与内容的时候也会回调一个事件。

在SAX解析XML时,需要通过XMLReader和DefaultHandler的配合,基本思路如下:

1)创建SAXParserFactory对象。

2)根据SAXParserFactory.newSAXParser()方法返回一个SAXParser解析器。

3) 根据SAXParser解析器获取事件源对象XMLReader。

4)实例化一个DefaultHandler对象。

5)连接事件源对象XMLReader到事件处理类DefaultHandler。

6)调用XMLReader的parse方法从输入源中获取XML数据。

7)通过DefaultHandler返回需要的数据集合。

这次的示例时在Raw目录下的link.xml文件。内容如下:

<?xml version=”1.0″?>

<p>

<a  href=”http://news.baidu.com” name=”tj_news”>新闻</a>

<a  href=”http://www.baidu.com” name=”tj_news”>网页</a>
<a  href=”http://tieba.baidu.com” name=”tj_news”>贴吧</a>
<a  href=”http://zhidao.baidu.com” name=”tj_news”>知道</a>
<a  href=”http://imge.baidu.com” name=”tj_news”>图片</a>
……

……

</p>

同样,像DOM解析一样,同样需要实现一个实体类Link,然后实现所有属性的set和get方法。

这里就不在赘述了。现在来看一下通过SAX方式解析XML。

private void parseXml() {
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser;
SAXParserHelper helper=null;
try {
parser=factory.newSAXParser();
XMLReader xmlReader=parser.getXMLReader();
helper=new SAXParserHelper();
xmlReader.setContentHandler(helper);
InputStream stream=getResources().openRawResource(R.raw.link);
InputSource is=new InputSource(stream);
xmlReader.parse(is);

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
helper.getLinks();

}

上面代码中自定义的SAX解析的帮助类SAXParserHelper

public class SAXParserHelper extends DefaultHandler {
private static final String TAG = “SAXParserHelper”;
List<Link> Links;
Link link;
int currentState = 0;

public List<Link> getLinks() {
for (int i = 0; i < Links.size(); i++) {
Log.d(TAG, Links.toString());
}
return Links;
}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
String theString = String.valueOf(ch, start, length);
if (currentState != 0) {
link.setText(theString);
currentState = 0;
}
return;
}

@Override
public void endDocument() throws SAXException {
super.endDocument();
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if (localName.equals(“a”)) {
Links.add(link);
}
}

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

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
link = new Link();
if (localName.equals(“a”)) {
for (int i = 0; i < attributes.getLength(); i++) {
if (attributes.getLocalName(i).equals(“href”)) {
link.setHref(attributes.getValue(i));
} else if (attributes.getLocalName(i).equals(“name”)) {
link.setName(attributes.getValue(i));
}
}
currentState = 1;
return;
}
currentState = 0;
return;
}
}

三、PULl解析XML

PULL解析XML的方式与SAX解析XML的方式是一样的,都是基于事件驱动的,使用PULL解析器解析时应注意一下几点:

1)通过xml.newPullParser()获得解析器

2)通过parser.setInput(in,”UTF-8″)设置输入流以及编码方式

3)通过parser.next()获取下一个元素并触发相应事件

此次示例使用的是

<?xml version=”1.0″?>

<poem lang=”chinese”>

<title>静夜思</title>

<author>李白</author>

<content>床前明月光,疑是地上霜。举头望明月,低头思故乡。</content>

</poem>

针对上面的XML文本,使用PuLL那个是解析的代码如下:

private void parseXml() {
XmlPullParserFactory factory;
try {
factory = XmlPullParserFactory.newInstance();
//设置支持名称空间
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
//xmlString为xml中的内容,格式为String
xpp.setInput(new StringReader(xmlString));
int eventType = xpp.getEventType();
while (eventType == XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
Log.d(TAG,”start document”);
}else if(eventType==XmlPullParser.START_TAG){
Log.d(TAG,”start tag”+xpp.getName());
}else if(eventType==XmlPullParser.END_TAG){
Log.d(TAG,”End tag”+xpp.getName());
}else if(eventType==XmlPullParser.TEXT){
Log.d(TAG,”Text “+xpp.getText());
}
eventType=xpp.next();

}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(“TAG”,”End document”);

}