XML的解析
XML结构示意图:
<?xmlversion="1.0" encoding="UTF-8"?>
<persons>
<personid="23">
<name>jack</name>
<age>30</age>
</person>
<personid="20">
<name>rose</name>
<age>25</age>
</person>
</persons>
Ø XML的结构解析如下:
Ø 1、节点
Ø 2、元素
Ø 3、属性和属性值
Ø 由于XML的扩展性强,致使它需要有稳定的基础规则来支持扩展,该语法规则是:
Ø 1、开始和结束标签匹配
Ø 2、嵌套标签不能互相嵌套
Ø 3、区分大小写
Java解析XML的三种方式
Ø Android中,解析Xml数据的三种方式:
Ø 1、DOM(org.w3c.dom)
Ø “文档对象模型”方式,解析完的Xml将生成一个树状结构的对象。
Ø 2、SAX(org.xml.sax)
Ø SimpleAPI for XML,以事件的形式通知程序,对Xml进行解析。
Ø 3、XMLPULL(org.xmlpull.v1)
Ø 类似于SAX方式,程序以“拉取”的方式对Xml进行解析。
SAX是一种以事件驱动的XML api,由它定义的事件流可以指定从解析器传到专门的处理程序的代码的XML结构,简单的讲,它解析速度快,占用内存少的解析器。这种解析器比较适合android 等移动设备。
使用SAX的优点是:
因为SAX的优势是流的方式处理,当遇到一个标签的时候,并不会记录下当前所碰到的标签。
也就是说,startEelment方法中,你所知道的信息,仅仅是当前的签名的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元素与其他结构相关的信息,都是不知道的。
代码:
package com.nsz.saxparser; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class MyHandler extends DefaultHandler { private HashMap<String, String> map = null; //存储单个解析的完整对象 private List<HashMap<String, String>> list = null; //存储所有的解析对象 private String currentTag = null; //正在解析的元素的标签 private String currentValue = null; //解析当前元素的值 private String nodeName = null; //解析当前的节点名称 public MyHandler(String nodeName) { super(); this.nodeName = nodeName; } public List<HashMap<String, String>> getList() { return list; } /** * 当读到第一个开始标签的时候,会触发这个方法 */ @Override public void startDocument() throws SAXException { list = new ArrayList<HashMap<String, String>>(); } /** * 当遇到文档的开头的时候,调用这个方法 */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(qName.equals(nodeName)){ map = new HashMap<String, String>(); } if(attributes != null && map != null){ for (int i = 0; i < attributes.getLength(); i++) { String tagAttr = attributes.getQName(i); String tafAttrValue = attributes.getValue(i); map.put(tagAttr, tafAttrValue); } } currentTag = qName; } /** * 这个方法是用来处理xml文件所读取到的内容 */ @Override public void characters(char[] ch, int start, int length) throws SAXException { if(currentTag != null && map != null){ currentValue = new String(ch, start, length); if(currentValue != null && !currentValue.trim().equals("") && !currentValue.trim().equals("\n")){ map.put(currentTag, currentValue); } } currentTag = null; // 把当前的节点的对应的值和标签设置为空 currentValue = null; } /** * 遇到结束标记的时候,会调用这个方法 */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { if(qName.equals(nodeName)){ list.add(map); map = null; } super.endElement(uri, localName, qName); } } package com.nsz.saxparser; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * 联网请求访问对象 * @author TF * */ public class HttpUtils { public static InputStream getXML(String path){ InputStream inputStream = null; try { URL url = new URL(path); if(url != null){ HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(5000); connection.setDoInput(true); connection.setRequestMethod("GET"); int code = connection.getResponseCode(); if(code == 200){ inputStream = connection.getInputStream(); } } } catch (Exception e) { e.printStackTrace(); } return inputStream; } } package com.nsz.saxparser; import java.io.InputStream; import java.util.HashMap; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public class SAXService { public static List<HashMap<String, String>> readXML(InputStream inputStream, String nodeName){ try { // 创建一个解析xml的工厂对象 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); // 解析xml SAXParser saxParser = saxParserFactory.newSAXParser(); MyHandler myHandler = new MyHandler(nodeName); saxParser.parse(inputStream, myHandler); inputStream.close(); return myHandler.getList(); } catch (Exception e) { e.printStackTrace(); } return null; } } 测试 package com.nsz.saxparser; import java.io.InputStream; import java.util.HashMap; import java.util.List; public class Test { public static void main(String[] args) { String path = "http://localhost:8080/test/person.xml"; InputStream in = HttpUtils.getXML(path); try { List<HashMap<String, String>> list = SAXService.readXML(in, "person"); for (HashMap<String, String> map : list) { System.out.println(map.toString()); } } catch (Exception e) { e.printStackTrace(); } } }
PULL技术介绍
除了可以使用以上两种解析XML文件之外,我们也可以使用Java自带的PULL来解析XML文件。
PULL解析器的运行方式和sax解析器很相似,它提供了类似的事件。
如开始元素和结束元素,使用parser.next()可以进行下一个元素并且触发相应的事件,事件将作为代码被发送,因此可以使用一个switch来对事件进行选择,然后进行相应的处理。当开始解析元素时候,调用parser.nextText()方法可以获得下一个Text类型的元素。
PULL特点:
简单的结构:一个接口,一个例外,一个工厂组成的PULL解析器
简单易用:PULL解析器只有一个重要的方法next方法,他被用来检索下一个事件,而它只有5个常用的属性:
START DOCUMENT
START_TAG
TEXT
END_TAG
END_DOCUMENT
代码:
<span style="font-size:14px;">package com.nsz.pullparser; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; /** * 主要是使用PULL解析xml * @author TF * */ public class PullXMLTools { public static List<Person> parseXML(InputStream inputStream, String encode) throws Exception{ List<Person> list = null; Person person = null; //装载解析每一个person节点的内容 // 创建一个xml解析的工厂 XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance(); // 获得xml解析类的引用 XmlPullParser parser = xmlPullParserFactory.newPullParser(); parser.setInput(inputStream, encode); // 获得事件的类型 int eventType = parser.getEventType(); while(eventType != XmlPullParser.END_DOCUMENT){ switch (eventType) { case XmlPullParser.START_DOCUMENT: list = new ArrayList<Person>(); break; case XmlPullParser.START_TAG: if("person".equals(parser.getName())){ person = new Person(); // 取出属性值 int id = Integer.parseInt(parser.getAttributeValue(0)); person.setId(id); }else if("name".equals(parser.getName())){ String name = parser.nextText(); // 获取该节点的内容 person.setName(name); }else if("age".equals(parser.getName())) { int age = Integer.parseInt(parser.nextText()); person.setAge(age); } break; case XmlPullParser.END_TAG: if ("person".equals(parser.getName())) { list.add(person); person = null; } break; } eventType = parser.next(); } return list; } } 测试 package com.nsz.pullparser; import java.io.InputStream; import java.util.List; import android.test.AndroidTestCase; public class Test extends AndroidTestCase{ public static void test() { String path = "http://localhost:8080/test/person.xml"; InputStream inputStream = HttpUtils.getXML(path); List<Person> list = null; try { list = PullXMLTools.parseXML(inputStream, "utf-8"); for (Person person : list) { System.out.println(person.toString()); } } catch (Exception e) { e.printStackTrace(); } } } </span>
DOM技术介绍
DOM是一种用于XML文档对象模型,可用于直接访问XML文档的各个部位,在DOM中文档被模拟为树状,其中XML语法的每一个组成部分都表示一个节点,DOM允许用户遍历文档树,从父节点移动到子节点和兄弟节点。并利用某节点类型特有的属性(元素具有属性,文本节点具有文本数据)
节点(XML文档中的每一个成分都是一个节点)
DOM是这样规定的:
整个文档是一个节点文档
每一个XML标签是一个元素节点
包含在XML元素中的文本是文本节点
每一个XML属性是一个属性节点
SAX、DOM和PULL的比较
从内存占用率来说:
SAX和PULL比DOM占用的更少的内存解析方式,更加适合Android 手机开发。
代码:
<span style="font-size:14px;">package com.nsz.domparser; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DomService { public List<Person> getPersons(InputStream inputStream) throws Exception{ List<Person> list = new ArrayList<Person>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbf.newDocumentBuilder(); Document document = builder.parse(inputStream); Element element = document.getDocumentElement(); NodeList personNodes = element.getElementsByTagName("person"); for(int i=0; i<personNodes.getLength(); i++){ Element personElement = (Element) personNodes.item(i); Person p = new Person(); p.setId(Integer.parseInt(personElement.getAttribute("id"))); NodeList childNodes = personElement.getChildNodes(); System.out.println("*****"+childNodes.getLength()); for (int j = 0; j < childNodes.getLength(); j++) { if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) { if ("name".equals(childNodes.item(j).getNodeName())) { p.setName(childNodes.item(j).getFirstChild() .getNodeValue()); } else if ("age".equals(childNodes.item(j).getNodeName())) { p.setAge(Integer.parseInt(childNodes.item(j) .getFirstChild().getNodeValue())); } } } list.add(p); } return list; } } 测试 package com.nsz.domparser; import java.io.InputStream; import java.util.List; public class Test { public static void main(String[] args) throws Exception { String path = "http://localhost:8080/test/person.xml"; InputStream input = HttpUtils.getXML(path); DomService dom = new DomService(); List<Person> persons = dom.getPersons(input); for (Person p : persons) { System.out.println(p.toString()); } } } </span>