XML与DOM4J
1.XML —— Extensible Markup Language ( 可扩展标记语言 )
在实际开发中,每种语言都有自己的用途,好比如:
①:HTML 在网页中合理地编排数据,使数据更有条理地展现
③:JS用作网页的逻辑处理,使得程序能与用户产生交互
而XML纯粹用于存储或传输数据,而不是用来显示数据的,它不做任何逻辑行为
2.XML基本语法规则
我们可以发现XML和HTML很像,都是使用标签,但有一点不同:
HTML的标签是固定好的,只能使用该语言自带的标签或属性,而XML可以自定义标签和属性。
XML的基本内容— — 文档声明、标签元素、属性、注释、文本内容
格式注意事项:
①:每对标签都要成对出现
③:标签之间的嵌套关系要正确
④:键值对之间用 "=" 隔开,而且两边不能有空格,属性值用双或单引号括住
⑤:文档声明必须要有,并且要写在XML文件第一行
⑥:根元素<根标签> 有且仅有一个,其他子元素都要嵌套在里面
基本内容示例:
文档声明 <?xml version="1.0" encoding="utf-8"?>
注释<!-- 注释 -->
属性 <person id="10004"></person> id就是属性
标签 <person></person>
3.DOM4J -- Document Object Model ( 文档对象模型 )
XML文件在内存中表示就是一棵树,简称DOM树,我们可以通过 DOM4J这个API来读写XML文件。
说到树,就不得不提数据结构,学过数据结构都知道内存中的树模型,是由一个个节点组成的。正好,DOM树也是由节点组成的,而每个节点都代表着一个标签。
比如以下的XML文件
<?xml version="1.0" encoding="utf-8" ?> <person-list> <!-- 联系人的信息 --> <person id="10004"> <name>狂人</name> <gender>男</gender> <phone>1364499123</phone> <qq>1238645</qq> <email>1238645@qq.com</email> </person> <!-- 联系人的信息 --> <person id="10005"> <name>张三</name> <gender>男</gender> <phone>1378574765</phone> <qq>64593435</qq> <email>64593435@qq.com</email> </person> </person-list>
DOM4J中的 Node类 与以下几个类存在着 is-a 的关系
Node ( 节点 )
-- Document 文档声明
-- Element 标签元素 <person-list></person-list> <person></person> <name></name>等
-- Text 文本 XML中的空格或者换行、标签对之前的文本
-- Comment 注释 <!-- -->之前的内容
-- ......
因此,只要我们得DOM树中的节点,就能得到XML文件所有的信息。
每个Element对象包含着元素名、附带属性、父元素、子元素、兄弟元素等信息,而它又能获得其所有子节点的信息,所以,我们也可以首先得到根元素,然后得到其子节点的迭代器,遍历所有子节点。
我们可以使用 dom4j.jar 中所包含的各种工具来解析XML文件,得到DOM树后并对它进行各种操作。
其中,我们经常要使用到的类有:
①:SAXReader -- Simple API for XML XML解析器
②:Document
③:Element
④:Text
⑤:Attribute
⑥:Comment
SAXReader saxReader = new saxReader(); Document document = saxReader.read("XML文件路径"); Element element = document.getRootElement();
通常,都是以这种方式得到XML文件的整个文档与根元素的,接着我们就能很好地操作内部的数据了。
下面是读取XML并递归遍历所有元素和打印XML文件的例子:
package mdk.dom4j_tree; import java.net.URL; import java.util.Iterator; import org.dom4j.Attribute; import org.dom4j.Comment; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.Text; import org.dom4j.io.SAXReader; public class Print_XmlInfo { public static void main(String[] args) throws Exception { // 创建xml解析器 SAXReader saxReader = new SAXReader(); // 从该字节码所在的包中查找my_data.xml这个 文件 URL resource = Print_XmlInfo.class.getResource("my_data.xml"); // 获得某个xml文件的document对象 Document document = saxReader.read( resource ); // 获得文档中的根元素 Element rootElement = document.getRootElement(); System.out.println("------------xml文件元素内容-------------"); showElements(rootElement); System.out.println("------------xml文件文本内容-------------"); StringBuilder sb = new StringBuilder(); showElements2( rootElement,sb ); System.out.println( sb.toString() ); } // 递归显示xml文件整个文档的所有标签元素 public static void showElements( Element element ) { // 显示当前元素 System.out.println( element ); for ( Iterator<Element> elementIterator = element.elementIterator(); elementIterator.hasNext(); ) showElements( elementIterator.next() ); } // 递归遍历根元素中的所有节点并将所有信息打印出来 public static void showElements2( Element element,StringBuilder sb ) { // 拼接元素标签信息 sb.append("<").append( element.getName() ); for ( int i = 0; i != element.attributeCount(); i++ ){ Attribute attribute = element.attribute( i ); sb.append(" " + attribute.getName() + "=\"" + attribute.getValue() + "\"" ); } sb.append(">"); // 遍历该元素的子节点 for ( Iterator<Node> nodeIterator = element.nodeIterator(); nodeIterator.hasNext(); ) { Node node = nodeIterator.next(); if ( node instanceof Text ){ Text text = (Text) node; sb.append( text.getText() ); } else if ( node instanceof Comment ){ Comment comment = (Comment)node; sb.append("<!--").append( comment.getText() ).append("-->"); }else if ( node instanceof Element ){ showElements2( (Element)node,sb ); } } sb.append("</" + element.getName() + ">"); } }
打印的是之前用作示例的XML
output:
------------xml文件元素内容------------- org.dom4j.tree.DefaultElement@871e65 [Element: <person-list attributes: []/>] org.dom4j.tree.DefaultElement@ea7549 [Element: <person attributes: [org.dom4j.tree.DefaultAttribute@ba175f [Attribute: name id value "10004"]]/>] org.dom4j.tree.DefaultElement@1549ceb [Element: <name attributes: []/>] org.dom4j.tree.DefaultElement@a30fd [Element: <gender attributes: []/>] org.dom4j.tree.DefaultElement@11650d6 [Element: <phone attributes: []/>] org.dom4j.tree.DefaultElement@1532fc [Element: <qq attributes: []/>] org.dom4j.tree.DefaultElement@1c64ed8 [Element: <email attributes: []/>] org.dom4j.tree.DefaultElement@626fd2 [Element: <person attributes: [org.dom4j.tree.DefaultAttribute@9b777a [Attribute: name id value "10005"]]/>] org.dom4j.tree.DefaultElement@c12978 [Element: <name attributes: []/>] org.dom4j.tree.DefaultElement@189c12a [Element: <gender attributes: []/>] org.dom4j.tree.DefaultElement@e8c7db [Element: <phone attributes: []/>] org.dom4j.tree.DefaultElement@992fa5 [Element: <qq attributes: []/>] org.dom4j.tree.DefaultElement@10718b7 [Element: <email attributes: []/>] ------------xml文件文本内容------------- <person-list> <!-- 联系人的信息 --> <person id="10004"> <name>狂人</name> <gender>男</gender> <phone>1364499123</phone> <qq>1238645</qq> <email>1238645@qq.com</email> </person> <!-- 联系人的信息 --> <person id="10005"> <name>张三</name> <gender>男</gender> <phone>1378574765</phone> <qq>64593435</qq> <email>64593435@qq.com</email> </person> </person-list>
4.DOM树节点的增删改,并将改变后的树写入到XML文件
改变DOM树,就是改变其内部的节点。
若要改变树的节点,以及要将改变后的内容重新写入到XML文件,我们需要用到以下工具:
①:DocumentHelper
用于增加各种节点元素,比如Document、Element、Attribute都可以用它来创建
②:XmlWriter
创建其对象,通常都调用它的writer方法将新的document对象写到XML文件中
③:OutputFormat
用它的对象来限定以什么格式来将DOM树写入到XML文件中,只有紧凑和漂亮两种格式
.createCompactFormat() -- 以紧凑格式写到文件,通常用于网络传输数据,节省空间
.createPrettyPrint() -- 以带缩进换行的格式写到文件,这样自己查看XML文件内容会更方便
①:直接从无构建一棵DOM树
package mdk.dom4j_tree; import java.io.FileOutputStream; import org.dom4j.Attribute; import org.dom4j.Comment; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; public class CreateXml { public static void main(String[] args) throws Exception { // 创建document对象 Document document = DocumentHelper.createDocument(); // 创建根元素 Element rootElement = DocumentHelper.createElement("person-list"); // 将根元素添加到文档上 document.add( rootElement ); // 创建根元素附带的子元素 person Element personEle = DocumentHelper.createElement("person"); Attribute personAttr = DocumentHelper.createAttribute(personEle,"id","12345"); personEle.add( personAttr ); //添加注释 Comment comment = DocumentHelper.createComment("这是个人信息"); rootElement.add( comment ); // 创建person附带的子元素 name gender age personEle.addElement("name").setText("张三"); personEle.addElement("gender").setText("男"); personEle.addElement("age").setText("18"); rootElement.add( personEle ); writeTo("d:/my_data.xml",document); } public static void writeTo( String xmlFileName,Document document ) throws Exception { FileOutputStream out = new FileOutputStream( xmlFileName ); OutputFormat format = OutputFormat.createPrettyPrint(); OutputFormat.createCompactFormat(); XMLWriter xmlWriter = new XMLWriter(out,format); xmlWriter.write( document ); xmlWriter.close(); } }
②:节点的增删改,继续使用上面的XML代码作为例子 -- 一信息表的增删改查
package mdk.exec02; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import mdk.exec02.Person.InfoTable; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public class OutputToHtml { private static String str_info[]; private static InfoTable info[] = InfoTable.values(); static{ str_info = new String[ info.length ]; for ( int i = 0; i != str_info.length; i++ ) str_info[ i ] = info[ i ].toString(); } public static void main(String[] args) throws Exception { System.out.println(); System.out.println("************************"); System.out.println("(1)添加联系人"); System.out.println("(2)删除联系人"); System.out.println("(3)修改联系人"); System.out.println("(4)在网页中显示联系人"); System.out.println("(5)退出"); System.out.println("************************"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in,"utf-8")); String command = null; System.out.print("请选择:"); while ( !(( command = br.readLine() ).equals("5")) ) { if ( "1".equals(command) ) addPersonInfo(); else if ( "2".equals(command) ) deletePersonInfo(); else if ( "3".equals(command) ) modifyPersonInfo(); else if ( "4".equals(command) ) showAllInfo(); else System.out.print("无效选项,请重新选择:"); System.out.print("请选择:"); } System.out.println("程序退出..."); } private static void modifyPersonInfo() throws Exception{ SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File("d:/my_data.xml")); Element rootElement = document.getRootElement(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in,"gbk")); System.out.print("请输入你要修改的联系人的id号:"); String id = br.readLine(); Node targetNode = rootElement.selectSingleNode("//person[@id='"+id+"']"); if ( targetNode == null ){ System.out.println("通讯录没有此联系人"); return; } System.out.println("(1)姓名 (2)性别 (3)电话 (4)QQ (5)E-Mail"); String select = br.readLine(); Element elt = (Element)targetNode; Element element = elt.element( str_info[ Integer.parseInt(select) ] ); System.out.print("输入修改的内容:"); String content = br.readLine(); element.setText(content); writeTo(document,"d:/my_data.xml"); } private static void deletePersonInfo() throws Exception{ SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File("d:/my_data.xml")); Element rootElement = document.getRootElement(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in,"gbk")); System.out.print("请输入你要删除的联系人的id号:"); String id = br.readLine(); Node targetNode = rootElement.selectSingleNode("//person[@id='"+id+"']"); if ( targetNode == null ){ System.out.println("通讯录没有此联系人"); return; } targetNode.getParent().remove(targetNode); writeTo(document,"d:/my_data.xml"); } public static void showAllInfo()throws Exception{ // 装载Person信息的列表 List<Person> personList = new ArrayList<Person>(); //创建 SAXReader对象 SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File("d:/my_data.xml")); // 获取根元素 Element rootElement = document.getRootElement(); // 获取 XML 的信息,将得到的信息放入List中 List<Element> personElements = rootElement.elements("person"); for (Element personEle : personElements){ personList.add(new Person( personEle.attributeValue("id"),personEle.elementText("name"),personEle.elementText("gender"),personEle.elementText("phone"),personEle.elementText("qq"),personEle.elementText("email"))); } String html = ""; html += "<html>\n"; html += " <head>\n"; html += " <Meta http-equiv='content-type' content='text/html;charset=gbk'>\n"; html += " <title>联系人列表</title>\n"; html += " <style type='text/css'> th,td{ padding: 8px; } </style>\n"; html += " </head>\n"; html += " <body>\n"; html += " <h1 align='center'>8.21班通讯录</h1>\n"; html += " <table align='center' border='1' style='border-collapse: collapse;'> \n"; html += " <tr> <th>姓名</th> <th>性别</th> <th>电话</th> <th>QQ</th> <th>邮箱</th> </tr>\n"; // 循环生成tr(每一个联系人对应一个<tr>) for (Person p : personList) { html += " <tr>\n"; html += " <td>" + p.getName() + "</td>\n"; html += " <td>" + p.getGender() + "</td>\n"; html += " <td>" + p.getPhone() + "</td>\n"; html += " <td>" + p.getQq() + "</td>\n"; html += " <td>" + p.getEmail() + "</td>\n"; html += " </tr>\n"; } html += " </table>\n"; html += " <body>\n"; html += "</html>\n"; // 将上面的HTML代码写入到一个html文件中 FileWriter fw = new FileWriter("d:/person-list.html"); fw.write(html); fw.close(); // 使用 Runtime类中的的getRuntime()得到一个Runtime对象,然后调用exec()方法执行某些程序功能 Runtime.getRuntime().exec("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" d:/person-list.html"); } public static void addPersonInfo() throws Exception{ BufferedReader br = new BufferedReader( new InputStreamReader(System.in,"gbk")); System.out.println("----增加通讯录名单----"); String inputInfo[] = new String[ str_info.length ]; for ( int i = 1; i != str_info.length; i++ ){ System.out.print("请输入"+ info[ i ].getInfo() + ":"); inputInfo[ i ] = br.readLine(); } System.out.print("请输入id:"); String id = br.readLine(); SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File("d:/my_data.xml")); Element rootElement = document.getRootElement(); while ( true ) { //使用XPath查找 Node targetNode = rootElement.selectSingleNode ("//person[@id='"+id+"']"); if ( targetNode == null ) break; System.out.print("id与其它联系人的id重复了,请重新输入:"); id = br.readLine(); } inputInfo[ 0 ] = id; Element personEle = DocumentHelper.createElement("person"); personEle.addAttribute(str_info[ 0 ],inputInfo[ 0 ]); for ( int i = 1; i != str_info.length; i++ ) personEle.addElement(str_info[ i ]).setText(inputInfo[ i ]); rootElement.add(personEle); writeTo(document,"d:/my_data.xml"); System.out.println("添加成功..."); } public static void writeTo( Document document,String fileName ) { FileOutputStream out = null; XMLWriter xmlWriter = null; try { out = new FileOutputStream(fileName); } catch (FileNotFoundException e) { System.out.println("找不到文件!"); } OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("gbk"); try { xmlWriter = new XMLWriter(out,format); } catch (UnsupportedEncodingException e) { System.out.println("不支持该编码格式!"); } try { xmlWriter.write(document); xmlWriter.close(); } catch (IOException e) { throw new RuntimeException(e); } } }
里面所用到的Person类:
package mdk.exec02; /** * 模型/实体:联系人信息 * * @author tyg * */ public class Person { private String id; // 唯一标识符 private String name; // 姓名 private String gender; // 性别 private String phone; // 电话 private String qq; // QQ private String email; // 邮箱 public enum InfoTable{ id("id"),name("姓名"),gender("性别"),phone("电话"),qq("QQ"),email("E-mail"); private String info; private InfoTable( String value ) { info = value; } public String getInfo(){ return info; } } public Person(String id,String name,String gender,String phone,String qq,String email) { this.id = id; this.name = name; this.gender = gender; this.phone = phone; this.qq = qq; this.email = email; } public Person(){} public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getQq() { return qq; } public void setQq(String qq) { this.qq = qq; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }