XML,eXtendsible markup language 可扩展的标记语言
-
可以用来保存数据
-
可以用来做配置文件
-
数据传输载体
XML解析其实就是获取元素里的字符数据或者属性数据
常用的XML解析方式
- DOM:Document Object Model,把整个xml全部读取到内存当中,形成树状结构。整个文档称为document对象,属性对应attribute对象,所有的元素节点对应element对象,文本称之为Text对象,以上所有对象称为Node节点;如果xml特别大可能会造成内存溢出;可以对文档进行增删操作
- SAX:Simple API of XML 基于事件驱动。读取一行,解析一行,不会造成内存溢出,不能对文档进行增删,只能查询
DOM方式解析XML文件
Document Object Model,把整个xml全部读取到内存当中,形成树状结构。整个文档称为document对象,属性对应attribute对象,所有的元素节点对应element对象,文本称之为Text对象,以上所有对象称为Node节点;如果xml特别大可能会造成内存溢出;可以对文档进行增删操作
创建一个stus.xml文件,并引入dom4j的jar包
stus.xml文件
<?xml version="1.0" encoding="UTF-8"?> <stus> <stu> <name>wxf</name> <age>24</age> </stu> <stu> <name>qf</name> <age>18</age> </stu> </stus>
Dom解析测试类
1 public class MainTest { 2 public static void main(String[] args) { 3 try { 4 //1.创建SAXReader对象 5 SAXReader reader = new SAXReader(); 6 //2.读取xml文件,获取Document对象 7 Document doc = reader.read(new File("src/stus.xml")); 8 //3.获取document对象的根元素 9 Element rootElement = doc.getRootElement(); 10 System.out.println("rootElement.getName()==="+rootElement.getName()); 11 System.out.println("--------------"); 12 //4.获取rootElement下的所有子元素 13 List<Element> elements = rootElement.elements(); 14 for (Element element : elements) { 15 System.out.println("element.getName()==="+element.getName()); 16 System.out.println("name==="+element.element("name").getText()); 17 System.out.println("age==="+element.element("age").getText()); 18 System.out.println("--------------"); 19 } 20 } catch (DocumentException e) { 21 e.printStackTrace(); 22 } 23 } 24 }
console测试结果
rootElement.getName()===stus -------------- element.getName()===stu name===wxf age===24 -------------- element.getName()===stu name===qf age===18 --------------
dom解析xml文件还可以根据XPath来处理(需要导入jaxen的jar包,否则会抛出java.lang.NoClassDefFoundError: org/jaxen/NamespaceContext)
XPath的常用语法:
如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径
如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)
星号 * 表示选择所有由星号之前的路径所定位的元素
............
XPath测试类
1 public class MainTest2 { 2 public static void main(String[] args) { 3 try { 4 //1.创建SAXReader对象 5 SAXReader reader = new SAXReader(); 6 //2.读取xml文件,获取Document对象 7 Document doc = reader.read(new File("src/stus.xml")); 8 //3.根据XPath获取element元素 9 //查找指定XPath("/")路径下第一个节点 10 Node selectSingleNode = doc.selectSingleNode("/stus/stu/name"); 11 System.out.println("name==="+selectSingleNode.getText()); 12 System.out.println("=================="); 13 //根据XPath("/")查找所有name节点 14 List<Node> selectNodes = doc.selectNodes("/stus/stu/name"); 15 for (Node node : selectNodes) { 16 System.out.println("name==="+node.getText()); 17 } 18 System.out.println("=================="); 19 //根据XPath("//")查找所有name节点 20 List<Node> selectNodes2 = doc.selectNodes("//age"); 21 for (Node node : selectNodes2) { 22 System.out.println("age==="+node.getText()); 23 } 24 System.out.println("=================="); 25 //根据XPath("*")查找stu下的所有子节点 26 List<Node> selectNodes3 = doc.selectNodes("/stus/stu/*"); 27 for (Node node : selectNodes3) { 28 System.out.println(node.getName()+"==="+node.getText()); 29 } 30 } catch (DocumentException e) { 31 e.printStackTrace(); 32 } 33 } 34 }
console测试结果
name===wxf ================== name===wxf name===qf ================== age===24 age===18 ================== name===wxf age===24 name===qf age===18
SAX解析XML方式
Java JDK自带的解析。Simple API of XML 基于事件驱动。读取一行,解析一行
优点:在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷。不需要加载进内存,因此不存在占用内存的问题,可以解析超大XML
缺点:只能用来读取XML中数据,无法进行增删改
SAX解析过程:
解析步骤:
- 创建一个SAXParserFactory对象:SAXParserFactory factory=SAXParserFactory.newInstance();
- 获得解析器 :SAXParser parser=factory.newSAXParser();
- 调用解析方法解析xml,这里的第一个参数可以传递文件、流、字符串、需要注意第二个参数(new DefaultHander)
File file=new File("girls.xml"); parser.parse(file,new DefaultHandler()); /**注解:--->这里的DefaultHandler表示 DefaultHandler类是SAX2事件处理程序的默认基类。它继承了EntityResolver、DTDHandler、 ContentHandler和ErrorHandler这四个接口。包含这四个接口的所有方法,所以我们在编写事件处理程序时, 可以不用直接实现这四个接口,而继承该类,然后重写我们需要的方法,所以在这之前我们先定义一个用于实现解析 方法如下:*/
- 创建一个MyHandler类来继承DefaultHandler并重写方法
//定一个名为MyHandler类用来继承DefaultHandler (1)MyHandler extends DefaultHander (2)重写方法,快速记住方法(2个开始,2个结束,1一个文字(charactor--里面的内容)) (3)2个开始:StartDocment(文档的开始)StartElement(元素的开始) 2个结束:endElement(元素的结束) endDocment(文档的结束,标志着xml文件的结束) 1个文字内容:charactor(文字内容)
- 创建一个集合把所解析的内容添加到集合
分析:目的我们只是需要把xml里面的文字内容添加到我们的集合而不需要其他元素,所以我们需要进行判断得到
- 接步骤三 输出集合System.out.pritnln(list); 解析完成
创建一个实体类Student.java
1 package com.qf.pojo; 2 3 public class Student { 4 5 private String name; 6 private int age; 7 8 public String getName() { 9 return name; 10 } 11 public void setName(String name) { 12 this.name = name; 13 } 14 public int getAge() { 15 return age; 16 } 17 public void setAge(int age) { 18 this.age = age; 19 } 20 @Override 21 public String toString() { 22 return "Student [name=" + name + ", age=" + age + "]"; 23 } 24 }
自定义一个ListHandler类继承DefaultHandler
1 package com.qf.handler; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.xml.sax.Attributes; 7 import org.xml.sax.SAXException; 8 import org.xml.sax.helpers.DefaultHandler; 9 10 import com.qf.pojo.Student; 11 12 public class ListHandler extends DefaultHandler { 13 14 private List<Student> stus; 15 private Student stu; 16 private String tag; 17 18 19 @Override 20 public void startDocument() throws SAXException { 21 //因为这个方法只调用一次,所以在开始的时候就可以实例化集合 22 stus = new ArrayList<>(); 23 } 24 @Override 25 public void endDocument() throws SAXException { 26 super.endDocument(); 27 } 28 @Override 29 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 30 //这个方法,只有当开始一个元素的时候才会调用, 31 //通过分析,当外部开始元素为student的时候,需要将student实例化 32 //将tag赋值 33 tag = qName; 34 if("stu".equals(qName)) { 35 stu = new Student(); 36 } 37 } 38 @Override 39 public void endElement(String uri, String localName, String qName) throws SAXException { 40 //这句话,必须写,因为,当sax解析完一个元素的时候,会自动认为换行符是一个字符,会继续执行 character 方法 。如果不写,就会造成没有数据的现象。 41 tag = ""; 42 //这个方法,当到了元素结尾的时候,会调用,应该在这里,将对象添加到集合里面去。 43 if ("stu".equals(qName)) { 44 stus.add(stu); 45 } 46 } 47 @Override 48 public void characters(char[] ch, int start, int length) throws SAXException { 49 //这里是内容,但是,无法直接判断属于哪一个元素。 50 String string = new String(ch, start, length); 51 if ("name".equals(tag)) {//判断当前内容,属于哪一个元素。 52 stu.setName(string); 53 }else if ("age".equals(tag)) { 54 stu.setAge(Integer.valueOf(string)); 55 }//这两种情况,表示 当前语句执行在 stus 标签内。 56 } 57 public List<Student> getStus() { 58 return stus; 59 } 60 public void setStus(List<Student> stus) { 61 this.stus = stus; 62 } 63 public Student getStu() { 64 return stu; 65 } 66 public void setStu(Student stu) { 67 this.stu = stu; 68 } 69 }
测试类
1 package com.qf.test; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.List; 6 7 import javax.xml.parsers.ParserConfigurationException; 8 import javax.xml.parsers.SAXParser; 9 import javax.xml.parsers.SAXParserFactory; 10 11 import org.xml.sax.SAXException; 12 13 import com.qf.handler.ListHandler; 14 import com.qf.pojo.Student; 15 16 public class SAXTest { 17 public static void main(String[] args) { 18 //1.创建对象 19 SAXParserFactory newInstance = SAXParserFactory.newInstance(); 20 try { 21 //2.获取解析器 22 SAXParser saxParser = newInstance.newSAXParser(); 23 //3.调用方法开始解析xml 24 File file = new File("src/stus.xml"); 25 ListHandler dh = new ListHandler(); 26 saxParser.parse(file, dh); 27 List<Student> stus=dh.getStus(); 28 //4.输出集合 29 System.out.println(stus); 30 } catch (ParserConfigurationException | SAXException e) { 31 e.printStackTrace(); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 36 } 37 }
控制台输出
[Student [name=wxf, age=24], Student [name=qf, age=18]]