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 < 10 then </note>
在XML中有五个预定义的实体引用,虽然在XML中只有字符<和&时非法的,但是还是鼓励大家把实体引用代替作为一个好习惯。
好了现在我们来说一下,在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"); }