三种解析无论哪一个,第一步都是校验xml文件 将xml文件在浏览器中打开校验正误 然后观察结构
第二步根据xml文件创建javabean类
第三部:根据不同方法进行解析
虽然每种解析方法所用到的类或者工具方法不同,但是解析的本质还是很相像的,理解一个其他基本都能看懂
前两两种是在Android studio环境下解析在raw文件中的xml文件
第三种的dom解析是在java环境在解析在文件夹conf中的xml文件
pull解析
//三级联动省市区 public List<Province> pullXmlProvince() { List<Province> list_pro =null; //获取解析的文件 InputStream inputStream = getResources().openRawResource(R.raw.citys_weather); try { //获取XmlPullFactory XmlPullParserFactory factory =XmlPullParserFactory.newInstance(); //获取解析器 XmlPullParser parser = factory.newPullParser(); //关联需要解析的文件 parser.setInput(inputStream,"utf-8"); //获取事件类型 int eventType = parser.getEventType(); //标签名称 String tagName=null; //省市区 Province province=null; List<City> lists_city=null; City city =null; List<Distribute> lists_distribute=null; Distribute distribute=null; while (eventType!=XmlPullParser.END_DOCUMENT) { //获取开始标签名称 tagName =parser.getName(); switch (eventType) { //开始标签 case XmlPullParser.START_DOCUMENT: //创建省份集合 list_pro =new ArrayList<>(); break; //开始标签 case XmlPullParser.START_TAG: if("p".equals(tagName)) { province =new Province(); //获取标签内属性 p_id String p_id = parser.getAttributeValue(0); //设置标签内属性p_id province.setP_id(p_id); } //如果是省份名字的话 else if("pn".equals(tagName)) { //获取省份名称 String name =parser.nextText(); province.setP_name(name); } else if("c".equals(tagName)) { lists_city =new ArrayList<>(); city =new City(); city.setCity_id(parser.getAttributeName(0)); }else if ("cn".equals(tagName)) { city.setCity_name(parser.nextText()); }else if("d".equals(tagName)) { lists_distribute =new ArrayList<>(); distribute =new Distribute(); distribute.setDis_id(parser.getAttributeName(0)); distribute.setDis_name(parser.nextText()); } break; case XmlPullParser.END_TAG: if ("d".equals(tagName)) { lists_distribute.add(distribute); distribute =null; }else if("c".equals(tagName)) { lists_city.add(city); city.setLists_dis(lists_distribute); city =null; }else if ("p".equals(tagName)) { province.setList_city(lists_city); list_pro.add(province); } break; } eventType =parser.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return list_pro; } }
SAX解析
//saX解析XML数据的方法 定义一个继承自DefaultHandler的子类 重写里面的4个方法
DOM解析 在java项目中class SaxXmlUser extends DefaultHandler{ //创建集合对象装user private List<User> lists_user=new ArrayList<>(); //当前解析的对象 private User user; //记录解析时候上一个节点的名称 private String preTagName =null; public List<User> getUsers (InputStream xmlStream) { //获取SAX解析XML的工厂 SAXParserFactory factory =SAXParserFactory.newInstance(); try { //由SAX解析的工厂对象创建SAX解析器 有异常处理异常 SAXParser parser =factory.newSAXParser(); //创建DefaultHandle对象 SaxXmlUser handler =new SaxXmlUser(); //将xml文件的输入流 关联上自定义的DefaulHandler子类 处理异常 parser.parse(xmlStream,handler);//自动回调SaxXmlUser中起其中重写的方法 Log.i("UUUUU","---------->"+lists_user.size());//为什么这个地方输出0呢 很不理解 return handler.getData(); } catch (ParserConfigurationException e) { e.printStackTrace(); Log.i("异常1","................"+e.toString()); } catch (SAXException e) { e.printStackTrace(); Log.i("异常2","................"+e.toString()+e.toString()); } catch (IOException e) { e.printStackTrace(); Log.i("异常3","................"+e.toString()+e.toString()); } return null; } public List<User> getData() { return lists_user; } //开始文档 @Override public void startDocument() throws SAXException { //开始文档初始化装载解析对象的集合 lists_user =new ArrayList<>(); } //开始元素节点 /* *每个参数含义 * @param 第一个参数 * @param 第二个参数 * @param 第三个参数 qName 指的是开始标签的标签名 * @param 第四个参数的含义 指的是标签与标签之间的值 * * */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("user".equals(qName)) { //创建user对象 user =new User(); user.setId(attributes.getValue(0)); user.setBirthday(attributes.getValue(1)); } //将正在解析的节点赋给preTag preTagName =qName; } //结束元素节点 @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("user".equals(qName)) { //将一个对象解析完了 放入集合中 lists_user.add(user); //并且清空这个对象名 用来装下一个对象数据 否则这个对象的内容可能存入TextNode中 //注意 :在xml文件中结束标签与开始标签之间的空白部分依然是一个标签叫做TextNode user =null; } preTagName =null; } //当走到标签之间的文本就会调用这个方法 @Override public void characters(char[] ch, int start, int length) throws SAXException { //前面那个节点不为空的时候 if (preTagName!=null) { //获取标签之间文本 String content =new String(ch,start,length); if ("name".equals(preTagName)) { user.setName(content); } else if ("age".equals(preTagName)) { user.setAge(content); }else if ("sex".equals(preTagName)) { user.setSex(content); } } }
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DomParseXml { final String PROVINCE="p"; final String PROVINCEID="p_id"; final String PROVINCENAME="cn"; final String CITY="c"; final String CITYID="c_id"; final String CITYNAME="cn"; final String DISTRIBUTE="d"; final String DISTRIBUTEID="d_id"; private Document document; public DomParseXml(File file) throws ParserConfigurationException { //documentbuildfactry对象的获取 DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); //创建documentbuilder对象 DocumentBuilder builder=factory.newDocumentBuilder(); //用builder对象parse出来document对象 try { document = builder.parse(file); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 用document对象解析指定的xml文件 */ public List<Province> parseProvinceXml() throws URISyntaxException, ParserConfigurationException { //盛装解析后Province对象的集合 List<Province> lists_province ; //如果document不为空 if(document!=null) { //创建该集合对象 lists_province =new ArrayList<Province>(); //每个节点都是元素 //通过元素名称获取节点集合 获取首个节点p组成的节点结合 NodeList nodeList= document.getElementsByTagName(PROVINCE); //遍历这个节点集合 for(int i=0;i<nodeList.getLength();i++) { //获取其中的每个节点 Node node =nodeList.item(i); //每个节点代表一个Province对象 创建province对象 Province province =new Province(); //创建province对象的list_city属性 List<City> lists_city =new ArrayList<City>(); //如果这个节点是元素节点 就把这个节点转为element if(node.getNodeType()==node.ELEMENT_NODE) { Element provinceElement = (Element) node; //获取元素节点的属性 String province_id = provinceElement.getAttribute(PROVINCEID); //设置province属性 province.setP_id(province_id); //province的子节点<pn><c> NodeList nodeList2 =provinceElement.getChildNodes(); for (int j = 0; j <nodeList2.getLength(); j++) { Node node_2= nodeList2.item(j); //创建city对象 City city =new City(); //创建city对象对应的distribute集合属性 List<Distribute> list_distribute=new ArrayList<Distribute>(); if(node_2.getNodeType()==node_2.ELEMENT_NODE) { Element node2 =(Element) node_2; if("pn".equals(node2.getNodeName())) { //获取pn标签之间的TextContent内容 String pn =node2.getTextContent(); //设置province的name值 province.setP_name(pn); } if("c".equals(node2.getNodeName())) { //获取城市属性id String c_id= node2.getAttribute("c_id"); //设置城市属性id city.setC_id(c_id); } //获取<c>之下的子节点 NodeList nodeList3 =node2.getChildNodes(); //遍历子节点 for (int k = 0; k < nodeList3.getLength(); k++) { Node _node3 =nodeList3.item(k); Distribute distribute =new Distribute(); if(_node3.getNodeType()==_node3.ELEMENT_NODE) { Element node3 =(Element)_node3; if("cn".equals(node3.getNodeName())) { String cn =node3.getTextContent(); city.setC_name(cn); } if("d".equals(node3.getNodeName())) { Element element =(Element) node3; String d_id= element.getAttribute("d_id"); distribute.setD_id(d_id); String dn = element.getTextContent(); distribute.setD_name(dn); list_distribute.add(distribute); } } } } city.setList_distributeDistributes(list_distribute); lists_city.add(city); } } province.setList_citys(lists_city); lists_province.add(province); } return lists_province; } return null; } public static void main(String[] args) { //获取当前java文件运行的根目录 String relativePath; try { relativePath = DomParseXml.class.getResource("/").toURI().getPath(); //文件名 String fileName =relativePath+"\\citys_weather.xml"; //路径传过来行程file对象 File file =new File(fileName); //将文件夹conf下的xml,但是java程序跑在bin中,所以需要将程序输出到bin中 /* * 步骤:1.点击项目右键build_path---->Config buildPath----->source--->add Forlder----->将xml文件所在的文件夹添加到bin中 * conf文件夹中的内容就直接到了bin中 我们就可以直接通过上面的代码从bin中取得数据 * 所以上面路径代码中无需要写conf文件 */ DomParseXml domParseXml =new DomParseXml(file); List<Province > lists_province = domParseXml.parseProvinceXml(); System.out.println("XML解析之后的内容:"+lists_province.toString()); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
三种解析方式的区别:
PULL解析器:
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
三种解析方式区别:
(1)SAX解析器的优点是解析速度快,占用内存少。
DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。
PULL解析器的运行方式和SAX类似,都是基于事件的模式。PULL解析器小巧轻便,解析速度快,简单易用。
(2)DOM,它是生成一个树,有了树以后你搜索、查找都可以做。
SAX和PULL是基于流的,就是解析器从头到尾解析一遍xml文件,解析完了以后你不过想再查找重新解析。
SAX和PULL的区别:(1)sax的原理是解析器解析过程中通过回调把tag/value值等传给你,你可以比较、操作。
而pull的原理是它只告诉你一个tag开始或者结束了,至于tag/value的值是什么需要你自己去向parser问,所以叫做pull,而sax看起来 是push给你的。(2)如果在一个XML文档中我们只需要前面一部分数据,但是使用SAX方式或DOM方式会对整个文档进行解析,尽管XML文档中后面的大部分数据我们其实都不需要解析,因此这样实际上就浪费了处理资源。使用PULL方式正合适。
Pull解析器和SAX解析器虽有区别但也有相似性。他们的区别为:SAX解析器的工作方式是自动将事件推入注册的事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析。也就是说pull是一个while循环,随时可以跳出,而sax不是,sax是只要解析了,就必须解析完成,在解析过程中在读取到特定tag时调用相应处理事件。