Android 开发之 XML 解析
来源:互联网 发布:默纳克调试软件app 编辑:程序博客网 时间:2024/05/16 11:31
转载请标明出处:【Gypsophila 的博客】 http://blog.csdn.net/astro_gypsophila/article/details/60509425
三种解析 XML 方法
- DOM 解析 XML
- SAX 解析 XML
- Pull 解析XML
示例的 XML 文件
<?xml version="1.0" encoding="UTF-8"?><students show="1"> <student id="1"> <name> <firstName>张</firstName> <lastName>三</lastName> </name> <age>20</age> </student> <student id="2"> <name> <firstName>李</firstName> <lastName>四</lastName> </name> <age>22</age> </student> <student id="3"> <name> <firstName>王</firstName> <lastName>五</lastName> </name> <age>22</age> </student></students>
涉及的 Java 类:
public class StudentBean { private int id; private String firstName; private String lastName; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "StudentBean{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", age=" + age + '}'; }}public class StudentPlusBean { //是否展示列表 private int show; private List<StudentBean> students = new ArrayList<>(); public int getShow() { return show; } public void setShow(int show) { this.show = show; } public List<StudentBean> getStudents() { return students; } @Override public String toString() { return "StudentPlusBean{" + "show=" + show + ", students=" + students + '}'; }}
DOM 解析 XML
DOM 解析 XML 文件会将整个文件以文档树的形式存放到内存中,然后可以使用 DOM API 遍历 XML 树。因为加载 XML 文件所有内容到内存,所以内存消耗比较大,对于移动设备来说,建议采用 SAX 解析或者是 XML 文件内容比较小再采用 DOM。
public class DOMParseHelper { public static void parse(Context context) { StudentPlusBean studentPlusBean = new StudentPlusBean(); try { // 获取工厂实例 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 获取 DOM 解析器 DocumentBuilder builder = factory.newDocumentBuilder(); InputStream is = context.getAssets().open("config_students.xml"); // 调用 DOM 解析器解析整份文档,获取文档对象,document Document document = builder.parse(is); // 根节点 students Node root = document.getFirstChild(); Element rootElement = (Element) root; studentPlusBean.setShow(Integer.valueOf(rootElement.getAttribute("show"))); NodeList studentNodeList = document.getElementsByTagName("student"); for (int i = 0; i < studentNodeList.getLength(); i++) { // 根据 tagname 获取的全是元素节点 StudentBean student = new StudentBean(); Element studentElement = (Element) studentNodeList.item(i); // 解析属性 id student.setId(Integer.valueOf(studentElement.getAttribute("id"))); // 方式一 (更加直观) // 解析 name // 因为很确定通过 tagName 方式查找一个 student 元素下,只会找到一个对应节点,且该节点为元素节点 // 所以直接 item(0) 且转型为 Element,剩下的查找也是同理 Element nameElement = (Element) studentElement.getElementsByTagName("name").item(0); Element firstName = (Element) nameElement.getElementsByTagName("firstName").item(0); student.setFirstName(firstName.getFirstChild().getNodeValue()); Element lastName = (Element) nameElement.getElementsByTagName("lastName").item(0); student.setLastName(lastName.getFirstChild().getNodeValue()); // 解析 age Element ageElement = (Element) studentElement.getElementsByTagName("age").item(0); student.setAge(Integer.valueOf(ageElement.getFirstChild().getNodeValue())); // 方式二/* for (int j = 0; j < studentElement.getChildNodes().getLength(); j++) { Node studentContentNode = studentElement.getChildNodes().item(j); if (studentContentNode.getNodeType() == Node.ELEMENT_NODE) { Element studentContentElement = (Element) studentContentNode; if (studentContentElement.getNodeName().equals("name")) { // 解析 name 部分 NodeList nameNodeList = studentContentElement.getChildNodes(); for (int k = 0; k < nameNodeList.getLength(); k++) { Node nameDetailNode = nameNodeList.item(k); if (nameDetailNode.getNodeType() == Node.ELEMENT_NODE) { Element nameDetailElement = (Element) nameDetailNode; if (nameDetailElement.getNodeName().equals("firstName")) { student.setFirstName(nameDetailElement.getFirstChild().getNodeValue()); } else if (nameDetailElement.getNodeName().equals("lastName")) { student.setLastName(nameDetailElement.getFirstChild().getNodeValue()); } } } } else if (studentContentElement.getNodeName().equals("age")) { // 解析 age student.setAge(Integer.valueOf(studentContentElement.getFirstChild().getNodeValue())); } } }*/ System.out.println("student = " + student); studentPlusBean.getStudents().add(student); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } }}
说明:这边解析的写法方式都是因人而异,这边所谓的方式一和二不过想突出 Node 和 Element 的差别。方式二是按照文档树的层次结构,所以有很多层的循环,都是为了遍历每层元素节点,而所遍历到的节点并不都是元素节点。
DOM 解析方式至少需注意元素和节点的区别
SAX 解析 XML
Simple API for XML(简称SAX)是个循序存取XML的解析器API。
SAX 就像读取流一样做着解析工作,运行起来为单向。即无法再访问读取过的资料,除非再从头开始读取一遍。采用事件驱动,不需要解析整份文档,而是在读取文档过程中,判断读取到的字符是否符合 XML 某部分,符合就出发事件调用我们的所写回调函数。它是一个解析速度快且占用内存少的 XML 解析器,非常适合用于 Android 等移动设备。
用法:继承 DefaultHandler ,然后可选择性重写以下几个方法。
// 继承 DefaultHandler 并且重写五个方法public class SAXParseHelper extends DefaultHandler { private StudentBean student; private String tagName; private StudentPlusBean studentPlusBean; @Override public void startDocument() throws SAXException { super.startDocument(); // 判断读取到文档开始时触发,可以在此做初始化操作 studentPlusBean = new StudentPlusBean(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); // 读取到标签开始,这里可以获取所有属性 if (localName.equals("students")) { studentPlusBean.setShow(Integer.valueOf(attributes.getValue("show"))); } else if (localName.equals("student")) { student = new StudentBean(); student.setId(Integer.valueOf(attributes.getValue("id"))); } tagName = localName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); // 读取到的内容部分 if (tagName != null) { String data = new String(ch, start, length); if (tagName.equals("firstName")) { student.setFirstName(data); } else if (tagName.equals("lastName")) { student.setLastName(data); } else if (tagName.equals("age")) { student.setAge(Integer.valueOf(data)); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); // 对应标签结束 if (localName.equals("student")) { studentPlusBean.getStudents().add(student); System.out.println("student = " + student); studentPlusBean.getStudents().add(student); student = null; } tagName = null; } @Override public void endDocument() throws SAXException { super.endDocument(); //文档结束部分 }}// 外部调用方式private void parseXMLBySAX() { try { //获取文件资源建立输入流对象 InputStream is = getAssets().open("config_students.xml"); //创建解析处理器 SAXParseHelper helper = new SAXParseHelper(); //得到SAX解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器 SAXParser parser = factory.newSAXParser(); parser.parse(is, helper); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } }
说明:SAX 较为高效!由于在解析过程中没有层级深入的感觉,所有的相关数据获取都是写在同一级的判断中,所以随着 XML 结构复杂,写法应该也越难理清,一堆的 if else 判断。(但我喜欢这种 SAX 和Pull,感觉好简便!:P)
PULL 解析 XML
Pull 解析器是 Android 内置用来解析 XML 文件。它的使用与 SAX 相似,采用事件驱动来完成 XML 解析。
private void parseXMLByPULL() { StudentPlusBean studentPlusBean = null; StudentBean student = null; try { //1.直接获得实例 //XmlPullParser parser = Xml.newPullParser(); //2.使用工厂获得实例 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(getAssets().open("config_students.xml"), "utf-8"); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_DOCUMENT: studentPlusBean = new StudentPlusBean(); break; case XmlPullParser.START_TAG: if ("students".equals(parser.getName())) { studentPlusBean.setShow(Integer.valueOf(parser.getAttributeValue(0))); } else if ("student".equals(parser.getName())) { student = new StudentBean(); // 取属性值方式1.明确所取属性的 index 时 // student.setId(Integer.valueOf(parser.getAttributeValue(0))); // 取属性值方式2.直接根据属性的名称取出值 student.setId(Integer.valueOf(parser.getAttributeValue(null,"id"))); } else if ("firstName".equals(parser.getName())) { student.setFirstName(parser.nextText()); } else if ("lastName".equals(parser.getName())) { student.setLastName(parser.nextText()); }else if ("age".equals(parser.getName())) { student.setAge(Integer.valueOf(parser.nextText())); } break; case XmlPullParser.END_TAG: if ("student".equals(parser.getName())) { System.out.println("student = " + student); studentPlusBean.getStudents().add(student); student = null; } break; } // 下一个解析事件 eventType = parser.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
说明:是否感觉 SAX 与 Pull 方式很接近?都是对读取的标签事件时,做具体的逻辑处理,一般就是取出它们的属性或者值。
注意:Pull 解析中遇到若元素中含有元素和节点值都需要解析,应该 attribute 先解析,然后获取节点值。
比如 name 中的 firstName 还多了个 show 属性
...<firstName show="1">李</firstName><lastName>四</lastName>...
应当注意获取解析属性和节点值的顺序,应当是先获取属性值,然后获取节点值。否则抛出 java.lang.IndexOutOfBoundsException
// 正确顺序else if ("firstName".equals(parser.getName())) { System.out.println("show = "+parser.getAttributeValue(0)); System.out.println("firstName = "+parser.nextText());}// 错误顺序System.out.println("firstName = "+parser.nextText());System.out.println("show = "+parser.getAttributeValue(0));
点击 parser.nextText()
方法中查看注释,就可明白当解析到 eventType == TEXT
if(eventType == TEXT) { String result = getText(); eventType = next(); if(eventType != END_TAG) { throw new XmlPullParserException( "event TEXT it must be immediately followed by END_TAG", this, null); } return result;}
执行了 next()
,解析会走到 END_TAG 事件,即此时走到了</firstName>
,这边肯定是没有 show
属性的,所以parser.getAttributeValue(0)
取不到第一个属性,发生越界。
- android 开发之解析xml
- Android 开发之 XML 解析
- Android开发之XML解析——SAX解析XML
- Android开发之XML文件解析
- android开发之sax解析xml文档
- Android开发之xml解析技术
- Android开发之XML文件解析
- Android开发之XML文件的解析
- Android开发学习之Xml解析归纳
- Android开发之解析XML-SAX
- Android开发基础之XML解析
- Android开发之XML文件解析
- Android开发之xml的解析
- Android开发之XML文件解析
- android开发笔记之解析XML
- Android开发之Pull解析XML文件
- Android应用开发之XML文件解析之二
- Android之Xml解析
- php面试常用题目精解(四)
- 我的第一篇自定义view--Menu菜单
- 利用随机数来加快代码调试速度
- 面试真题(一)
- C语言的指针(我才不会说是为了理解mips语法)
- Android 开发之 XML 解析
- [面试] Oracle 11g 行列互换 pivot 和 unpivot
- codeforces 782B Round #403 Div. 2B
- ibatis简介
- git的一大优点
- ch340 win7 64位驱动下载 win10也可以用
- iOS开发小技巧总结
- What is a Proxy?
- codeforces 781A Round #403 Div. 2C