JAXP进行DOM和SAX解析
1.常用XML的解析方式:DOM和SAX
1)DOM思想:将整个XML加载内存中,形成文档对象,所以对XML操作都对内存中文档对象进行。
2)SAX思想:一边解析,一边处理,一边释放内存资源---不允许在内存中保留大规模XML数据
3)DOM和SAX的区别
DOM:支持回写,会将整个XML载入内存,以树形结构方式存储
XML比较复杂的时候,或者当你需要随机处理文档中数据的时候不建议使用
SAX:相比DOM是一种更为轻量级的方案
无法在读取过程中修改XML数据
2.常用解析开发包:JAXP、DOM4J
3.DOM解析原理图
4.使用JAXP进行DOM解析
JAXP:(Java API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
org.xml.sax:提供SAX方式解析XML的标准接口
javax.xml:提供了解析XML文档的类
5.JAXP进行DOM解析的实例(增删改查)
book.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?><书架> <书 ISBN="a11" 出版社="清华大学出版社"> <书名>JavaSE基础</书名> <作者>张三</作者> <批发价>35.00元</批发价> <售价>38.00元</售价> </书> <书 ISBN="b11" 出版社="北京大学出版社"> <书名>Android</书名> <作者>李四</作者> <售价>38.00元</售价> </书> </书架>
JaxpDomDemo.java
package cn.lsl.jaxp; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class JaxpDomDemo { public static void main(String[] args) throws Exception { //得到解析工厂DocumentBuilderFactory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //得到解析器DocumentBuilder DocumentBuilder builder = factory.newDocumentBuilder(); //解析指定的XML文档,得到代表内存DOM树的Document对象 Document document = builder.parse("src/book.xml"); test8(document); } //1.得到某个具体节点内容:打印第2本书的作者 public static void test1(Document document){ //根据标签的名称获取所有的作者元素 NodeList nodeList = document.getElementsByTagName("作者"); //按照索引取第2个作者元素 Node node = nodeList.item(1); //打印该元素的文本 String text = node.getTextContent(); System.out.println(text); } // 2、遍历所有元素节点:打印元素的名称 public static void test2(Node node){ //判断当前节点是不是一个元素节点 if(node.getNodeType() == Node.ELEMENT_NODE){ //如果是:打印他的名称 System.out.println(node.getNodeName()); } //查找子节点 NodeList nodeList = node.getChildNodes(); int len = nodeList.getLength(); for (int i = 0; i < len; i++) { Node n = nodeList.item(i); test2(n); } } //3、修改某个元素节点的主体内容:把第一本书的售价改为38.00元 public static void test3(Document document) throws Exception{ //找到第一本书的售价 NodeList nodeList = document.getElementsByTagName("售价"); //设置其主体内容 Node node = nodeList.item(0); node.setTextContent("38.00元"); //把内存中Document树写回xml文件中 TransformerFactory factory = TransformerFactory.newInstance(); Transformer ts = factory.newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); } //4.向指定元素节点中增加子元素节点:第一本中增加子元素<内部价>29.00</内部价> public static void test4(Document document) throws Exception{ //创建一个新的元素并设置其主体内容 Element e = document.createElement("内部价"); e.setTextContent("29.00元"); //找到第一本书元素 Node firstBookNode = document.getElementsByTagName("书").item(0); //把新节点挂接到第一本书上 firstBookNode.appendChild(e); //把内存中Document树写回XML文件中 TransformerFactory factory = TransformerFactory.newInstance(); Transformer ts = factory.newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); } //5.向指定元素节点上增加同级元素节点:在第一本书的售价前面增加批发价 public static void test5(Document document) throws Exception{ //创建一个新的元素并设置其中的主题内容 Element e = document.createElement("批发价"); e.setTextContent("35.00元"); //找到第一本书的售价 Node firstPrice = document.getElementsByTagName("售价").item(0); //在售价的前面加入新建的元素:增加子元素一定要用父元素来增加 firstPrice.getParentNode().insertBefore(e, firstPrice); //把内存中Document树写回XML文件中 TransformerFactory factory = TransformerFactory.newInstance(); Transformer ts = factory.newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); } //6.删除指定元素节点:删除内部价 public static void test6(Document document) throws Exception{ //找到内部价节点,用父节点删除 Node n = document.getElementsByTagName("内部价").item(0); n.getParentNode().removeChild(n); //把内存中Document书写回XML文件中 TransformerFactory factory = TransformerFactory.newInstance(); Transformer ts = factory.newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); } //7、操作XML文件属性:打印第一本书的出版社 public static void test7(Document document){ //得到第一本书 Node n = document.getElementsByTagName("书").item(0); //打印指定属性的取值 Element e = (Element)n; System.out.println(e.getAttribute("出版社")); } //8、添加一个出版社属性给第二本书 public static void test8(Document document) throws Exception{ //得到第二本书 Node n = document.getElementsByTagName("书").item(1); //打印指定属性的取值 Element e = (Element)n; e.setAttribute("出版社", "北京大学出版社"); //把内存中Document树写回XML文件中 TransformerFactory factory = TransformerFactory.newInstance(); Transformer ts = factory.newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/book.xml")); } }
6.案例(学生成绩的增删改查,采用分层开发)
案例原型
exam.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?><exam> <student examid="444" idcard="333"> <name>李四</name> <location>大连</location> <grade>97</grade> </student> <student examid="666" idcard="555"> <name>小舒</name> <location>福建</location> <grade>90.0</grade> </student> </exam>
实体类:Student.java
package cn.lsl.domain; public class Student { private String idcard; private String examid; private String name; private String location; private Double grade; public String getIdcard() { return idcard; } public void setIdcard(String idcard) { this.idcard = idcard; } public String getExamid() { return examid; } public void setExamid(String examid) { this.examid = examid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public Double getGrade() { return grade; } public void setGrade(Double grade) { this.grade = grade; } @Override public String toString() { return "Student [examid=" + examid + ", grade=" + grade + ", idcard=" + idcard + ", location=" + location + ", name=" + name + "]"; } }
工具类:DocumentUtil.java
package cn.lsl.util; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; //操作XML的工具类 //工具类中的异常可以抛也可以处理 public class DocumentUtil { public static Document getDocument() throws Exception{ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return builder.parse("src/exam.xml"); } public static void write2xml(Document document) throws Exception{ Transformer ts = TransformerFactory.newInstance().newTransformer(); ts.transform(new DOMSource(document), new StreamResult("src/exam.xml")); } }
DAO层:(StudentDao.java)
package cn.lsl.dao; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import cn.lsl.domain.Student; import cn.lsl.util.DocumentUtil; public class StudentDao { //添加学生信息到XML中 public boolean createStudent(Student s){ boolean result = false; try{ Document document = DocumentUtil.getDocument(); //创建name、location、grade元素并设置内容 Element nameE = document.createElement("name"); nameE.setTextContent(s.getName()); Element locationE = document.createElement("location"); locationE.setTextContent(s.getLocation()); Element gradeE = document.createElement("grade"); gradeE.setTextContent(s.getGrade()+""); //创建student元素,并设置属性 Element studentE = document.createElement("student"); studentE.setAttribute("idcard", s.getIdcard()); studentE.setAttribute("examid", s.getExamid()); studentE.appendChild(nameE); studentE.appendChild(locationE); studentE.appendChild(gradeE); //得到exam元素,把student挂接上去 Node node = document.getElementsByTagName("exam").item(0); node.appendChild(studentE); //写回XML文件中 DocumentUtil.write2xml(document); result = true; }catch(Exception e){ throw new RuntimeException(e); //异常转义。异常链 } return result; } //根据准考证号查询学生信息 public Student findStudent(String examid){ Student s = null; try{ Document document = DocumentUtil.getDocument(); //得到所有student元素 NodeList nodelist = document.getElementsByTagName("student"); //遍历student元素,判断他的examid属性的取值是否与参数匹配 for (int i = 0; i < nodelist.getLength(); i++) { Node node = nodelist.item(i); if(node instanceof Element){ Element e = (Element)node; if(e.getAttribute("examid").equals(examid)){ //如果匹配,说明找到了学生,创建学生对象 s = new Student(); s.setExamid(examid); s.setIdcard(e.getAttribute("idcard")); s.setName(e.getElementsByTagName("name").item(0).getTextContent()); s.setLocation(e.getElementsByTagName("location").item(0).getTextContent()); s.setGrade(Double.parseDouble(e.getElementsByTagName("grade").item(0).getTextContent())); } } } }catch(Exception e){ throw new RuntimeException(e); } return s; } //根据学生姓名删除学生 public boolean deleteStudent(String name){ boolean result = false; try{ //得到Document对象 Document document = DocumentUtil.getDocument(); NodeList nodelist = document.getElementsByTagName("name"); for(int i=0; i<nodelist.getLength(); i++){ Node node = nodelist.item(i); if(node.getTextContent().equals(name)){ node.getParentNode().getParentNode().removeChild(node.getParentNode()); //写回XML文档 DocumentUtil.write2xml(document); result = true; break; } } }catch(Exception e){ throw new RuntimeException(e); } return result; } }
View层(Main.java)
package cn.lsl.view; import java.io.BufferedReader; import java.io.InputStreamReader; import cn.lsl.dao.StudentDao; import cn.lsl.domain.Student; public class Main { public static void main(String[] args) { try{ StudentDao dao = new StudentDao(); System.out.println("a、添加学生\tb、删除学生\tc、查询成绩"); System.out.println("请输入操作类型"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String operation = br.readLine(); if("a".equals(operation)){ //添加操作 System.out.println("请输入学生姓名"); String name = br.readLine(); System.out.println("请输入学生准考证号"); String examid = br.readLine(); System.out.println("请输入学生身份证号"); String idcard = br.readLine(); System.out.println("请输入学生所在地"); String location = br.readLine(); System.out.println("请输入学生成绩"); String grade = br.readLine(); Student s = new Student(); s.setExamid(examid); s.setIdcard(idcard); s.setName(name); s.setLocation(location); s.setGrade(Double.parseDouble(grade)); //System.out.println(s); boolean b = dao.createStudent(s); if(b){ System.out.println("---添加成功---"); }else{ System.out.println("对不起!数据有误"); } }else if("b".equals(operation)){ System.out.println("请输入要删除的学生姓名:"); String name = br.readLine(); boolean b = dao.deleteStudent(name); if(b){ System.out.println("--删除成功--"); }else{ System.out.println("对不起!删除失败或者学生不存在"); } }else if("c".equals(operation)){ //查询操作 System.out.println("请输入要查询的学生准考证号:"); String examid = br.readLine(); Student s = dao.findStudent(examid); if(s == null){ System.out.println("对不起!您查询的学生不存在"); }else{ System.out.println(s); } }else{ System.out.println("请输入正确的操作类型"); } }catch(Exception e){ System.out.println("对不起!服务器忙!"); } } }
7.SAX解析原理图
8. SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器。
9.SAX解析
实例一:
book.xml
<?xml version="1.0" encoding="UTF-8"?> <书架> <书 出版社="清华大学出版社"> <书名>JavaSE基础</书名> <作者>张三</作者> <售价>38.00</售价> <内部价>19.00</内部价> </书> <书> <书名>Android</书名> <作者>李四</作者> <售价>28.00</售价> </书> </书架>
SAXDemo1.java
package cn.lsl.sax; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; //JAXP进行SAX解析 public class SAXDemo1 { public static void main(String[] args) throws Exception { //得到解析工厂SAXParserFactory SAXParserFactory factory = SAXParserFactory.newInstance(); //得到解析器SAXParser SAXParser parser = factory.newSAXParser(); //得到XML读取器:XMLReader XMLReader reader = parser.getXMLReader(); //注册内容处理器:ContentHandler reader.setContentHandler(new MyContentHandler()); //取出XML文档 reader.parse("src/book.xml"); } } class MyContentHandler implements ContentHandler{ //解析到文档开始时被调用 @Override public void startDocument() throws SAXException { System.out.println("解析到了文档的开始"); } //解析到了元素开始时被调用: qName元素名称 @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { System.out.println("解析到了元素的开始:"+qName); } //解析到了文本内容被调用 @Override public void characters(char[] ch, int start, int length) throws SAXException { System.out.println("文本内容:"+new String(ch,start,length)); } //解析到元素结束时被调用 @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("解析到了元素的结束:"+qName); } //解析到文档结束时被调用 @Override public void endDocument() throws SAXException { System.out.println("解析到了文档的结束"); } @Override public void endPrefixMapping(String prefix) throws SAXException { // TODO Auto-generated method stub } @Override public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub } @Override public void processingInstruction(String target, String data) throws SAXException { // TODO Auto-generated method stub } @Override public void setDocumentLocator(Locator locator) { // TODO Auto-generated method stub } @Override public void skippedEntity(String name) throws SAXException { // TODO Auto-generated method stub } @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { // TODO Auto-generated method stub } }
实例二:
SAXDemo2.java
package cn.lsl.sax; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; //打印第2本书的作者 public class SAXDemo2 { public static void main(String[] args) throws Exception { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.setContentHandler(new ContentHandler(){ //匿名内部类 boolean isAuthor = false; //是不是作者标签 int index = 0; //作者标签的索引 @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { if("作者".equals(qName)){ isAuthor = true; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(isAuthor&&index==1){ System.out.println(new String(ch,start,length)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("作者".equals(qName)){ index++; } isAuthor = false; } @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub } @Override public void endPrefixMapping(String prefix) throws SAXException { // TODO Auto-generated method stub } @Override public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub } @Override public void processingInstruction(String target, String data) throws SAXException { // TODO Auto-generated method stub } @Override public void setDocumentLocator(Locator locator) { // TODO Auto-generated method stub } @Override public void skippedEntity(String name) throws SAXException { // TODO Auto-generated method stub } @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub } @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { // TODO Auto-generated method stub } }); reader.parse("src/book.xml"); } }
实例三:读取XML内容,封装到JavaBean
Book.java
package cn.lsl.domain; public class Book { private String name; private String author; private Double price; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } @Override public String toString() { return "Book [author=" + author + ", name=" + name + ", price=" + price + "]"; } }
SAXDemo3.java
package cn.lsl.sax; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import cn.lsl.domain.Book; //读取XML内容,封装到JavaBean public class SAXDemo3 { public static void main(String[] args) throws Exception { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); XMLReader reader = parser.getXMLReader(); final List books = new ArrayList(); reader.setContentHandler(new DefaultHandler(){ Book book = null; String currentTagName = null; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("书".equals(qName)){ book = new Book(); } currentTagName = qName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if("书名".equals(currentTagName)){ book.setName(new String(ch,start,length)); } if("作者".equals(currentTagName)){ book.setAuthor(new String(ch,start,length)); } if("售价".equals(currentTagName)){ book.setPrice(Double.parseDouble(new String(ch,start,length))); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("书".equals(qName)){ books.add(book); book = null; } currentTagName = null; } }); reader.parse("src/book.xml"); for (Object b:books) { System.out.println(b); } } }