DOM综合案例、SAX解析、StAX解析、DOM4J解析
今日大纲
1、DOM技术对xml的增删操作
2、使用DOM技术完成联系人管理
3、SAX和StAX解析
4、DOM4J解析
5、XPATH介绍
1、DOM的增删操作
1.1、DOM的增加操作
/* * 演示使用dom技术给xml中添加标签 * <book> <name id="b001">SSH</name> <author>老于</author> <price>152</price> </book> 首先要找到book标签的父标签,拿到books,就可以books标签下添加book标签。 */ @Test public void add() throws Exception{ //获取解析工厂 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //获取解析器对象 DocumentBuilder builder = dbf.newDocumentBuilder(); //获取dom对象 Document dom = builder.parse("book.xml"); //先创建book标签 <book></book> Element book = dom.createElement("book"); //创建name标签 Element name = dom.createElement("name"); name.setAttribute("id", "b003"); // <name id="b003"></name> name.setTextContent("oracle技术"); // <name id="b003">oracle技术</name> Element author = dom.createElement("author"); author.setTextContent("老毕"); // <author>老毕</author> Element price = dom.createElement("price"); price.setTextContent("1.28"); // <price>1.28</price> //把标签组合在一起 book.appendChild(name); book.appendChild(author); book.appendChild(price); Node books = dom.getElementsByTagName("books").item(0); books.appendChild(book); //写出去 TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(new DOMSource(dom), new StreamResult("book.xml")); }
1.2、DOM的删除操作
/* * 删除xml中的指定标签 * 首先要找到被删除的标签,再找到它的父标签,通过父标签删除当前这个标签 * 删除完成之后一定要重新写到xml中 */ @Test public void delete() throws Exception{ //获取解析工厂 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //获取解析器对象 DocumentBuilder builder = dbf.newDocumentBuilder(); //获取dom对象 Document dom = builder.parse("book.xml"); //获取所有的book标签 NodeList nodeList = dom.getElementsByTagName("book"); //获取最后一个book标签 Node node = nodeList.item(nodeList.getLength()-1); //获取book标签的父标签,然后删除自己 node.getParentNode().removeChild(node); //写出去 TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(new DOMSource(dom), new StreamResult("book.xml")); }
1.3、抽取公共方法
/* * 这个类主要提供对dom 的基本公共操作 * 获取dom对象 * 保存dom对象 * 工具类一般提供的方法都是静态的。 */ public class DOMUtils { private static Document dom; // 书写静态代码块,在这个工具类加载的时候,就把dom树创建完成 static { try { // 获取解析工厂 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 获取解析器对象 DocumentBuilder builder = dbf.newDocumentBuilder(); // 获取dom对象 dom = builder.parse("book.xml"); } catch (Exception e) { System.out.println("创建dom树失败"); } } // 获取dom对象 public static Document getDOM() { return dom; } // 保存dom对象到xml中 public static void save() { try { // 写出去 TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(new DOMSource(dom), new StreamResult( "book.xml")); } catch (Exception e) { System.out.println("保存失败"); } } }
2、DOM的综合案例(联系人管理系统):
需求:
用户在运行程序的时候需要先登录或注册个人信息,注册完成之后,当前登录的用户才能去管理自己的联系人。
开发和用户交互的程序时,需要开发2个模块:
1、用户登录或者注册的模块
2、用户用来管理自己的联系人模块。
联系人模块主要是对联系人的增删改查操作
使用xml保存数据。就需要定义一层专门负责和xml交互。
而和用户交互的层中还需要访问和xml交互那一层
2.1、先准备存储数据的容器。这里采用xml。
这个xml中要保存用户的信息同时还要保存联系人的信息。
每个用户都需要维护自己的联系人。
<contacts> <user username=”zhangsan” password=”1234”> user标签用户 <contact> <name></name> <age></age> <tel></tel> <addr></addr> <sex></sex> </contact> <contact> <name></name> <age></age> <tel></tel> <addr></addr> <sex></sex> </contact> </user> <user username=”xxxx” password=”4321”> <contact> <name></name> <age></age> <tel></tel> <addr></addr> <sex></sex> </contact> </uesr> </contacts>
2.2、包的创建
2.3、完成和用户交互的注册登录退出界面
//用户显示用户的登录注册退出 public void core(){ while( true ){ System.out.println("1.登录"); System.out.println("2.注册"); System.out.println("0.退出"); //获取用户输入的操作类型 String operator = getKeyInfo(); //处理用户到底选择的登录 注册 退出 switch( operator ){ case "1": //处理登录的功能 break; case "2": //处理注册的功能 break; case "0": //处理退的功能 System.out.println("谢谢使用,您已经退出此系统"); return; default: System.out.println("操作类型错误"); } } }
2.4、实现登录功能
定义LoginAndRegiter 实现登录和注册
登录的用户交互界面功能实现:
//处理登录的方法 public void login(){ //System.out.println("登录"); System.out.println("请输入用户名"); String username = GetKeyInfo.getKeyInfo(); System.out.println("请输入密码"); String password = GetKeyInfo.getKeyInfo(); //调用dao中的判断用户登录是否成功的方法 boolean boo = ConatactDao.login(username, password); //判断是否登录成功 if( boo == true ){ System.out.println("登录成功"); }else{ System.out.println("用户名或者密码错误"); } }
登录的帐号和密码验证的功能:在dao层的ContactDao类中实现帐号和密码的验证功能
//完成验证用户的登录是否成功 public static boolean login( String name , String pwd ){ //定义标记 boolean flag = false; Document dom = DOMUtils.getDOM(); NodeList list = dom.getElementsByTagName("user"); //遍历获取到的所有user标签,然后获取其中的username和password属性 for (int i = 0; i < list.getLength(); i++) { Element user = (Element) list.item(i); //获取xml中的用户名和密码 String xml_username = user.getAttribute("username"); String xml_password = user.getAttribute("password"); //判断用户名和密码是否正确 if( name.equals(xml_username) && pwd.equals(xml_password) ){ flag = true; } } return flag; }
2.5、实现注册功能
//和用户交互的注册代码 //处理注册的方法 public void register(){ System.out.println("请输入注册名"); String username = GetKeyInfo.getKeyInfo(); System.out.println("请输入注册密码"); String password = GetKeyInfo.getKeyInfo(); //调用后台完成用户名的注册 ConatactDao.register(username, password); }
用户保存注册信息的dao层的代码
//完成注册的功能 public static void register(String username, String password) { Document dom = DOMUtils.getDOM(); //创建user节点 Element user = dom.createElement("user"); user.setAttribute("username", username); user.setAttribute("password", password);//<user username="xxxx" password="yyyy"></user> //xml中的根节点 contacts,并把这个user节点添加在根上 dom.getFirstChild().appendChild(user); DOMUtils.save(); }
2.6、实现登录成功后显示对联系人的操作界面
在负责登录和注册类中完成登录成功之后的显示联系人的增删改查界面
//显示当前联系人的CRUD private void showCRUDOperator() { while( true ){ System.out.println("1.增加联系人信息"); System.out.println("2.删除联系人信息"); System.out.println("3.修改联系人信息"); System.out.println("4.查询联系人信息"); System.out.println("0.退出"); String operator = GetKeyInfo.getKeyInfo(); switch (operator) { case "1": //调用添加联系人的功能 con.add(); break; case "2": //调用删除联系人的功能 con.delete(); break; case "3": //调用修改联系人的功能 con.update(); break; case "4": //调用查询联系人的功能 con.find(); break; case "0": return; default: System.out.println("选择的操作类型错误"); break; } } }
2.7、实现联系人的增加功能
在登录注册类中的用于给用户显示联系人CURD功能中完成对ContactCRUD类中的增加联系人的操作
//增加联系人 public void add(){ System.out.println("请输入联系人的姓名"); String name = GetKeyInfo.getKeyInfo(); System.out.println("请输入联系人的年龄"); String age = GetKeyInfo.getKeyInfo(); System.out.println("请输入联系人的电话"); String tel = GetKeyInfo.getKeyInfo(); System.out.println("请输入联系人的住址"); String addr = GetKeyInfo.getKeyInfo(); System.out.println("请输入联系人的性别"); String sex = GetKeyInfo.getKeyInfo(); //创建一个联系人对象 Contact c = new Contact(); c.setAddr(addr); c.setAge(age); c.setSex(sex); c.setTel(tel); c.setName(name); //调用到层把当前的联系人的信息保存在当前登录成功的这个用户下面 ConatactDao.addContact(c); }
在ContactDao中完成对联系人的增加操作
//用于保存当前的联系人信息 public static void addContact( Contact c ){ //完成用户的的联系人的增加过程 Document dom = DOMUtils.getDOM(); Element contact = dom.createElement("contact"); contact.setAttribute("id", IDUtils.getID()); Element name = dom.createElement("name"); name.setTextContent(c.getName()); Element age = dom.createElement("age"); age.setTextContent(c.getAge()); Element tel = dom.createElement("tel"); tel.setTextContent(c.getTel()); Element addr = dom.createElement("addr"); addr.setTextContent(c.getAddr()); Element sex = dom.createElement("sex"); sex.setTextContent(c.getSex()); contact.appendChild(name); contact.appendChild(age); contact.appendChild(tel); contact.appendChild(addr); contact.appendChild(sex); currentUser.appendChild(contact); DOMUtils.save(); }
2.8、实现联系人的删除功能
ContactCRUD中的删除功能实现
//删除联系人。根据联系人的姓名来删除 public void delete(){ System.out.println("请输入要删除的联系人姓名"); String name = GetKeyInfo.getKeyInfo(); boolean boo = ConatactDao.deleteByName(name); //判断是否删除成功 if( boo ){ System.out.println("删除成功"); }else{ System.out.println("删除失败"); } }
ContactDao中的删除功能
/* * 删除联系人 */ public static boolean deleteByName(String name) { boolean flag = false; //使用当前登录的人来删除下面的指定名称的联系人 NodeList list = currentUser.getElementsByTagName("contact"); //遍历 for (int i = 0; i < list.getLength(); i++) { //获取每个联系人的标签 Element contact = (Element) list.item(i); //获取当前联系人的name标签中的文本值 String xml_name = contact.getElementsByTagName("name").item(0).getTextContent(); //判断 if( name.equals(xml_name) ){ flag = true; //删除当前的联系人 currentUser.removeChild(contact); break; } } DOMUtils.save(); return flag; }
2.9、实现联系人的修改功能
修改功能的实现需要先查询有没有被修改的联系人,然后才能修改
ContactCRUD中的修改功能实现
//修改联系人 public void update(){ System.out.println("请输入要修改的联系人姓名"); String name = GetKeyInfo.getKeyInfo(); boolean boo = ConatactDao.findByName(name); //判断是否删除成功 if( boo ){ //让输入联系人的年龄 性别 电话 地址 System.out.println("请输入修改的联系人的年龄"); String age = GetKeyInfo.getKeyInfo(); System.out.println("请输入修改的联系人的电话"); String tel = GetKeyInfo.getKeyInfo(); System.out.println("请输入修改的联系人的住址"); String addr = GetKeyInfo.getKeyInfo(); System.out.println("请输入修改的联系人的性别"); String sex = GetKeyInfo.getKeyInfo(); //创建一个联系人对象 Contact c = new Contact(); c.setAddr(addr); c.setAge(age); c.setSex(sex); c.setTel(tel); c.setName(name); ConatactDao.update(c); System.out.println("修改成功"); }else{ System.out.println("没有当前输入姓名的联系人"); } }
ContactDao中的代码分成2部分,第一部分查询被修改的人是否存在
/* * 修改时查找有没有当前这个联系人 */ public static boolean findByName(String name) { boolean flag = false; // 使用当前登录的人来查询其中的符合条件的联系人信息 NodeList list = currentUser.getElementsByTagName("contact"); for (int i = 0; i < list.getLength(); i++) { Element contact = (Element) list.item(i); // 获取联系人的姓名 String xml_name = contact.getElementsByTagName("name").item(0) .getTextContent(); // 判断姓名是否相同 if (name.equals(xml_name)) { flag = true; } } return flag; }
ContactDao中的代码分成2部分,第二部分查询被修改练习人实现
/* * 完成数据的修改 */ public static void update(Contact c) { // 使用当前登录的人来查询其中的符合条件的联系人信息 NodeList list = currentUser.getElementsByTagName("contact"); for (int i = 0; i < list.getLength(); i++) { Element contact = (Element) list.item(i); // 获取联系人的姓名 String xml_name = contact.getElementsByTagName("name").item(0).getTextContent(); // 判断姓名是否相同 if (c.getName().equals(xml_name)) { contact.getElementsByTagName("age").item(0).setTextContent(c.getAge()); contact.getElementsByTagName("tel").item(0).setTextContent(c.getTel()); contact.getElementsByTagName("addr").item(0).setTextContent(c.getAddr()); contact.getElementsByTagName("sex").item(0).setTextContent(c.getSex()); break; } } DOMUtils.save(); }
2.10、实现联系人的显示功能
完成和用户交互的显示联系人
//查询联系人 public void find(){ List<Contact> list = ConatactDao.findAll(); for (Contact contact : list) { System.out.println(contact); } }
在ContactDao类中完成查询联系人的信息
/* * 提供查询所有联系人的功能 */ public static List<Contact> findAll(){ List<Contact> list = new ArrayList<>(); //获取dom //Document dom = DOMUtils.getDOM(); NodeList contacts = currentUser.getElementsByTagName("contact"); //遍历获取每个联系人的信息 for (int i = 0; i < contacts.getLength(); i++) { //单独创建一个联系人对象,用来封装从xml中获取到的联系人信息 Contact c = new Contact(); //获取某个联系人的标签 Element contact = (Element) contacts.item(i); //获取到联系人下的name标签 Element name = (Element) contact.getElementsByTagName("name").item(0); c.setName(name.getTextContent()); //获取到联系人下的age标签 Element age = (Element) contact.getElementsByTagName("age").item(0); c.setAge(age.getTextContent()); //获取到联系人下的tel标签 Element tel = (Element) contact.getElementsByTagName("tel").item(0); c.setTel(tel.getTextContent()); //获取到联系人下的addr标签 Element addr = (Element) contact.getElementsByTagName("addr").item(0); c.setAddr(addr.getTextContent()); //获取到联系人下的sex标签 Element sex = (Element) contact.getElementsByTagName("sex").item(0); c.setSex(sex.getTextContent()); //把联系人添加到集合中 list.add(c); } return list; }
3、SAX解析
public class StAX { @Test public void read() throws Exception{ //获取工厂 XMLInputFactory factory = XMLInputFactory.newFactory(); //获取解析器 XMLEventReader reader = factory.createXMLEventReader(new FileInputStream("book.xml")); //使用循环开始读取数据 while( reader.hasNext() ){ XMLEvent event = reader.nextEvent(); if(event.isStartElement()){ //获取当前这个标签 StartElement element = event.asStartElement(); Attribute attr = element.getAttributeByName(new QName("id")); if( attr != null ){ System.out.println("id="+attr.getValue()); } //判断当前的标签名是否是name或者age if( element.getName().getLocalPart().equals("name") ){ XMLEvent text = reader.nextEvent(); System.out.println(text.asCharacters()); } //判断当前的标签名是否是name或者age if( element.getName().getLocalPart().equals("age") ){ XMLEvent text = reader.nextEvent(); System.out.println(text.asCharacters()); } } } } }
4、StAX解析
public class SAXDemo { @Test public void read() throws Exception{ //获取工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //获取解析器 SAXParser parser = factory.newSAXParser(); //给解析器传递xml和handler对象 parser.parse("book.xml", new MyDefaultHandler() ); } } //在handler中使用对应的方法来读取数据 class MyDefaultHandler extends DefaultHandler{ //记录当前读取到标签名称 private String el = ""; public void startDocument() throws SAXException { System.out.println("文档开始了"); } public void endDocument() throws SAXException { System.out.println("文档结束了"); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if( qName.equals("name") ){ el = qName; System.out.print("name:id="+attributes.getValue("id")+"\t"); } } public void endElement(String uri, String localName, String qName) throws SAXException { if( qName.equals("name") ){ el=""; } } public void characters(char[] ch, int start, int length) throws SAXException { if( !el.equals("") ){ System.out.println(new String(ch,start,length)); } } }
5、DOM4J解析
/* * dom4j技术: * sun公司提供三种对xml的解析: * dom * sax * stax * jaxp jdk中提供好了这三种解析方案。 * 在市面上也有第三方公司提供的xml解析。 * dom4j dom for java 需要到第三方公司去下载对应的jar包程序。 * www.dom4j.org 下载 * 解压后,把dom4j-1.6.1.jar添加到当前自己项目的classpath中 */ public class DOMDemo { //解析一个xml文件 public Document getDom() throws Exception{ //获取解析器 SAXReader reader = new SAXReader(); Document dom = reader.read("book.xml"); return dom; } /* * 读取xml文件中的内容 */ @Test public void read()throws Exception{ Document dom = getDom(); //获取根节点 Element root = dom.getRootElement(); //System.out.println(root); //获取根节点下的所有直接子节点 Iterator it = root.elementIterator(); while( it.hasNext() ){ Element el = (Element) it.next(); String name = el.getName(); String id = el.attribute("id").getValue(); String text = el.getText(); System.out.println(name+",id="+id+",text="+text); } } /* * 使用dom4j给xml中添加标签 * <book id="b002" name="xxxx"> <name>JavaEE</name> <author>老于</author> <price>2.82</price> </book> */ @Test public void add() throws Exception{ //获取dom树 Document dom = getDom(); //获取 根节点 Element root = dom.getRootElement(); //创建book标签,并且已经添加到books上 Element book = root.addElement("book"); book.addAttribute("id", "b002").addAttribute("name", "xxxxx"); //给book标签下添加子标签 book.addElement("name").addText("JavaEE"); book.addElement("author").setText("老于"); book.addElement("price").setText("2.82"); //保存 //创建用于写出xml的对象,建议用字节流FileOutputStream,因为字符流要转码 OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),format); writer.write(dom); writer.close(); } @Test public void update()throws Exception{ Document dom = getDom(); //获取根节点 Element root = dom.getRootElement(); //Element el = root.element("book").element("name"); List list = root.elements("book"); Element lastBook = (Element) list.get(list.size()-1); lastBook.element("name").setText("oracle"); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),format); writer.write(dom); writer.close(); } @Test public void delete()throws Exception{ Document dom = getDom(); //获取根节点 Element root = dom.getRootElement(); Element fisrtBook = (Element) root.elements("book").get(0); root.remove(fisrtBook); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),format); writer.write(dom); writer.close(); } /* * 使用第三方jar包来开发程序时,如果报错,类找不到错误 * 这时可能是在当前的jar文本中没有这个类, * 错误中的第二个单词,或者第三个单词就为这个类所在的jar包名 * * * xpath语法: * 在使用dom4j解析xml文档的时候可以使用xpath技术快速定位到具体的标签上。 * 以/ 开始 说明是从根开始找 * 以// 开始 只要匹配就可以。 * * /books 找根为books的标签 * /books/name 找根books下紧跟的子标签name * /books//name books标签下的所有的name标签,那么不一定是它的直接子标签 * /AAA/BBB[@id] aaa标签下的直接子标签bbb中含有id的标签全部被选中 * /AAA/BBB[1] aaa标签下的第一个字节子标签bbb * xpath的功能是可以快速的定位到xml的某个标签上。 */ @Test public void find()throws Exception{ Document dom = getDom(); //获取根节点 Element root = dom.getRootElement(); String xpath = "/books/abc"; List names = root.selectNodes(xpath); Element el = (Element) names.get(0); System.out.println(el.getText()); } @Test public void select() throws Exception{ // String path = "//user[fn:upper-case(@id)='XX'and fn:upper-case(@name)='"+name+"']"; SAXReader reader = new SAXReader(); Document dom = reader.read("contact.xml"); Scanner s = new Scanner(System.in); String name = s.nextLine().toUpperCase(); String pwd = s.nextLine().toUpperCase(); //获取到根 Element root = dom.getRootElement(); String xpath = "//user[fn:upper-case(@username)='"+name+"' and fn:upper-case(@password)='"+pwd+"']"; List list = root.selectNodes(xpath); if( list.size() == 0 ){ System.out.println("用户名或者密码错误"); }else{ System.out.println("登录成功"); } } }