students.xml
<?xml version="1.0" encoding="UTF-8"?> <students> <student id="1"> <name>张珊</name> <age>22</age> </student> <student id="2"> <name>王航</name> <age>25</age> </student> <student id="3"> <name>刘沙</name> <age>26</age> </student> <student id="4"> <name>张海</name> <age>24</age> </student> </students>
Person.java
package xmldom; public class Person { int id; String name; int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
一,DOM方式解析XML就是先把XML文档都读到内存中,然后在用户DOMAPI来访问树形结构,获取数据
解析的思路是:
1,将xml文件加载进来
2,获取文档的根节点
3,获取文档根节点中的所有子节点的列表
4,获取子节点列表中需要多去的节点信息
首先创建一个DocumentBuilderFactory实例,然后通过该实例来加载XML文档(Document)文档加载完毕以后,进行节点获取,先找到根节点,在找到子节点。
package xmldom; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class Main { /** * @param args */ public static void main(String[] args) { ArrayList<Person> studentslist=new ArrayList<Person>(); DocumentBuilderFactory factory=null;//DOM解析器工厂 DocumentBuilder builder=null;//DOM解析器 Document document=null;//文档对象 try { //1,实例化DOM解析器工厂,工厂的作用是创建具体的解析器 factory=DocumentBuilderFactory.newInstance(); //2,通过工厂获得DOM解析器 builder=factory.newDocumentBuilder(); //3,通过DOM解析器获得文档对象,可以解析File,InputStream等 document=builder.parse(new File("students.xml"));//把这个文档放在项目的根路径下,与src目录平行,就可以使用相对路径来引用了 //4,获取文档的根节点 Element root=document.getDocumentElement(); //5,由根节点获取子节点列表 NodeList nodelist=root.getElementsByTagName("student"); //遍历每个子节点 Person person=null; for(int i=0;i<nodelist.getLength();i++){ person=new Person(); // 获得元素,将节点强制转换为元素。此时element就是一个具体的元素 Element studentelement=(Element) nodelist.item(i); String id=studentelement.getAttribute("id");//元素获得属性值 person.setId(Integer.valueOf(id)); //获取子元素:子元素name只有一个节点.所以是item(0) Element Name=(Element) studentelement.getElementsByTagName("name").item(0); person.setName(Name.getFirstChild().getNodeValue());//获得子元素的值,一定要加getFirstChild //获取子元素:子元素name只有一个节点.所以是item(0) Element Age=(Element) studentelement.getElementsByTagName("age").item(0); person.setAge(new Integer(Age.getFirstChild().getNodeValue()));//获得子元素的值,一定要加getFirstChild studentslist.add(person); } } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } for(int i=0;i<studentslist.size();i++){ System.out.println("ID:"+studentslist.get(i).getId()+ " 姓名:"+studentslist.get(i).getName()+ " 年龄:"+studentslist.get(i).getAge()); } } }结果:
ID:1 姓名:张珊 年龄:22 ID:2 姓名:王航 年龄:25 ID:3 姓名:刘沙 年龄:26 ID:4 姓名:张海 年龄:24DOM 的 API:
Document的方法:
4.节点列表类NodeList
NodeList代表了一个包含一个或者多个Node的列表,根据操作可以将其简化的看做为数组
5.节点类Node
Node对象是DOM中最基本的对象,代表了文档树中的抽象节点。但在实际使用中很少会直接使用Node对象,而是使用Node对象的子对象Element,Attr,Text等
6.元素类Element
是Node类最主要的子对象,在元素中可以包含属性,因而Element中有存取其属性的方法
二,使用SAX解析XML
SAX是Simple API for XML的缩写,比DOM速度更快,更有效,占用内存更小。他是逐行扫描,边扫描边解析,流式处理,是基于事件驱动的,就是不用完全解析整个文档,在按内容顺序解析文档过程中,SAX会判断当前读到的字符是否符合XML文件语法的某部分,如果符合,就会触发事件,就是调用一些回调方法。
使用SAX解析XML的几个步骤:
1,创建SAXParserFactory对象
2,调用SAXParserFactory的newSAXParser方法创建一个SAXParser对象
3,实例化一个继承DefaultHandler的自定义对象
4,SAXParser对象的parser方法按自定义Handler规则解析xml文档
MyHandler.java
package saxxml; import java.util.ArrayList; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class MyHandler extends DefaultHandler { ArrayList<Person> students;//要返回的对象集合 StringBuilder sb; Person student; //当遇到文档开头的时候,即开始解析XML根元素时调用该方法,调用这个方法,可以做一些预处理 @Override public void startDocument() throws SAXException { System.out.println("--startDocument--"); students=new ArrayList<Person>();//实例化对象 sb=new StringBuilder(); } //当读到开始标签的时,调用这个方法。即开始解析每个元素时都会调用该方法,uri表示命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名,attributes可以得到所有属性,一般读到的标签名在qName @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("--startElement--"+qName); //如果读到的开始标签是student,就实例化对象,设置id if(qName.equals("student")){ student=new Person(); student.setId(new Integer(attributes.getValue("id"))); } sb.setLength(0);//每次读到开始标签将字符长度设置为0,以便重新开始读取元素内的字符节点 } /*这个方法处理xml文件读到的内容,第一个参数存放文件的内容,注意是xml文件的全部内容早已经在ch中,只是每次调用此函数时start和length会变化, * 后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)可以获取内容 */ @Override public void characters(char[] ch, int start, int length) throws SAXException { System.out.println("--characters()--"+new String(ch,start,length)+"start="+start+" length="+length); sb.append(new String(ch,start,length));//将读取到数字符数组追加到builder中 } //遇到结束标签的时候,调用这个方法 @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("--endElement--"+qName); if(qName.equalsIgnoreCase("name")){ student.setName(sb.toString()); } else if(qName.equalsIgnoreCase("age")){ student.setAge(new Integer(sb.toString())); } else if(qName.equalsIgnoreCase("student")){ students.add(student); } } //文档结束的时候,调用这个方法,可以做一些善后工作 @Override public void endDocument() throws SAXException { System.out.println("--endDocument--"); } //返回对象集合 public ArrayList<Person> getList(){ return students; } }
package saxxml; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub try { //1,创建一个SAXParserFactory对象 SAXParserFactory factory=SAXParserFactory.newInstance(); //2,调用SAXParserFactory中的newSAXParser方法创建一个SAXParser对象 SAXParser parser=factory.newSAXParser(); MyHandler myhandler=new MyHandler(); //3,SAXParser对象使用自定义的Handler规则解析xml文件或xml文件流 parser.parse(new File("students.xml"), myhandler); //遍历返回的对象集合 ArrayList<Person> list=myhandler.getList(); for(int i=0;i<list.size();i++){ System.out.println("ID:"+list.get(i).getId()+" 姓名:"+list.get(i).getName()+" 年龄:"+list.get(i).getAge()); } } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }输出:
--startDocument-- --startElement--students --characters()-- start=13 length=5//前面的空格是回车符\t.换行符\n,空格,的输出 --startElement--student --characters()-- start=35 length=9 --startElement--name --characters()--张珊start=50 length=2 --endElement--name --characters()-- start=60 length=9 --startElement--age --characters()--22start=74 length=2 --endElement--age --characters()-- start=83 length=5 --endElement--student --characters()-- start=99 length=5 --startElement--student --characters()-- start=121 length=9 --startElement--name --characters()--王航start=136 length=2 --endElement--name --characters()-- start=146 length=9 --startElement--age --characters()--25start=160 length=2 --endElement--age --characters()-- start=169 length=5 --endElement--student --characters()-- start=185 length=5 --startElement--student --characters()-- start=207 length=9 --startElement--name --characters()--刘沙start=222 length=2 --endElement--name --characters()-- start=232 length=9 --startElement--age --characters()--26start=246 length=2 --endElement--age --characters()-- start=255 length=5 --endElement--student --characters()-- start=271 length=5 --startElement--student --characters()-- start=293 length=9 --startElement--name --characters()--张海start=308 length=2 --endElement--name --characters()-- start=318 length=9 --startElement--age --characters()--24start=332 length=2 --endElement--age --characters()-- start=341 length=5 --endElement--student --characters()-- start=357 length=1 --endElement--students --endDocument-- ID:1 姓名:张珊 年龄:22 ID:2 姓名:王航 年龄:25 ID:3 姓名:刘沙 年龄:26 ID:4 姓名:张海 年龄:24
分析:用SAX解析XML采用的是从上而下的基于事件驱动的解析方式,在解析过程中会视情况自动调用startDocument()、startElement()、characters()、endElement()、endDocument()等相关的方法。
由编译执行的结果来看:
1,startDocument()方法只会在文档开始解析的时候被调用,每次解析只会调用一次。,
2,startElement()方法每次在开始解析一个元素,即遇到元素标签开始的时候都会调用。
3,characters()方法也是在每次解析到元素标签携带的内容时都会调用,即在startElement调用后,调用characters时读到的内容值,在endElement调用后,调用characters时读到的回车符,换行符和空格。即使该元素标签的内容为空或换行。而且如果元素内嵌套元素,在父元素结束标签前,
characters()方法会再次被调用,此处需要注意。
4,endElement()方法每次在结束解析一个元素,即遇到元素标签结束的时候都会调用。
5,endDocument() startDocument()方法只会在文档解析结束的时候被调用,每次解析只会调用一次。
其实参数char[] ch中早已经加载了文档,每次调用的时候改变的是start,length
[ , , <, s, t, u, d, e, n, t, s, >, , , , , , , <, s, t, u, d, e, n, t, , i, d, =, ", 1, ", >, , , , , , , , , , , <, n, a, m, e, >, 张, 珊, <, /, n, a, m, e, >, , , , , , , , , , , <, a, g, e, >, 2, 2, <, /, a, g, e, >, , , , , , , <, /, s, t, u, d, e, n, t, >, , , , , , , <, s, t, u, d, e, n, t, , i, d, =, ", 2, ", >, , , , , , , , , , , <, n, a, m, e, >, 王, 航, <, /, n, a, m, e, >, , , , , , , , , , , <, a, g, e, >, 2, 5, <, /, a, g, e, >, , , , , , , <, /, s, t, u, d, e, n, t, >, , , , , , , <, s, t, u, d, e, n, t, , i, d, =, ", 3, ", >, , , , , , , , , , , <, n, a, m, e, >, 刘, 沙, <, /, n, a, m, e, >, , , , , , , , , , , <, a, g, e, >, 2, 6, <, /, a, g, e, >, , , , , , , <, /, s, t, u, d, e, n, t, >, , , , , , , <, s, t, u, d, e, n, t, , i, d, =, ", 4, ", >, , , , , , , , , , , <, n, a, m, e, >, 张, 海, <, /, n, a, m, e, >, , , , , , , , , , , <, a, g, e, >, 2, 4, <, /, a, g, e, >, , , , , , , <, /, s, t, u, d, e, n, t, >, , , <, /, s, t, u, d, e, n, t, s, >,
原文:http://blog.csdn.net/tuke_tuke/article/details/50995559