XML与DOM4J
1.XML —— Extensible Markup Language ( 可扩展标记语言 )
在实际开发中,每种语言都有自己的用途,好比如:
①:HTML 在网页中合理地编排数据,使数据更有条理地展现
②:CSS 添加更多视觉效果,使得网页的显示效果更佳丰富
③: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>等
-- Attribute 属性 person标签中的id
-- 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;
}
}