<?xml version="1.0" encoding="UTF-8"?>
<!-- 员工信息 -->
<employees>
<employee>
<!-- 员工工号。 -->
<deptNo>1</deptNo>
<!-- 姓名 -->
<name attribute1="张三的某些属性值">张三</name>
<!-- 年龄 -->
<age>25</age>
<!-- 部门 -->
<dept>
<deptName>dept1</deptName>
</dept>
</employee>
<employee>
<deptNo>2</deptNo>
<name attribute1="李四的某些属性值">李四</name>
<age>22</age>
<dept>
<deptName>dept2</deptName>
</dept>
</employee>
<employee>
<deptNo>3</deptNo>
<name attribute1="王五的某些属性值">王五</name>
<age>50</age>
<dept>
<deptName>dept3</deptName>
</dept>
</employee>
<employee>
<deptNo>4</deptNo>
<name attribute1="陈六的某些属性值">陈六</name>
<age>55</age>
<dept>
<deptName>dept2</deptName>
</dept>
</employee>
</employees>
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
/**
* 使用jdom修改xml文档。(增加,删除,修改)。
*
* @author sky
* @version xmlPART1_1.0, May 5, 2009
* @since xmlPART1_1.0
*/
public class XML1
{
/**
* 解析出来的xml文档根目录。
*/
private static Document doc;
/**
* xml文档的路径。该路径是相对于src源代码包的路径。
*/
private static final String XML_PATH = "/employees.xml";
/**
* 使用sax从指定的xml文件中获取相关的数据。
*
* @param xmlPath
* 读取的xml文档的路径。
* @throws IOException
* 失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文件时的非人为异常。
*/
public static void readDataFromXML(final String xmlPath)
throws JDOMException, IOException
{
SAXBuilder sax = new SAXBuilder();// 创建一个SAXBuilder对象,用于解析xml文档
InputStream is = XML1.class.getResourceAsStream(XML1.XML_PATH);
XML1.doc = sax.build(is);// 根据一个InputStream 解析xml文档,并将其存放于Document中
is.close();
}
/**
* 从Document对象中解析出相关数据。把这些解析出来的数据放到一个list对象中,并将该对象返回。
*
* @return 返回解析出来的List对象。如果Document不存根节点元素或其根节点元素不存在名为"employee"根节点,
* 则返回一个空的list对象。
* @throws IOException
* 解析xml文档时,失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文档时出现非人为因素的异常。
* @exception NumberFormatException
* 数字格式化异常。Integer.valueOf与Short.ValueOf这两个地 方可能会产生数字格式化异常。
* @exception NullPointerException
* Document对象为空时,抛出异常。
*/
@SuppressWarnings("unchecked")
public static List<Emp> getDataFromDocument() throws JDOMException,
IOException
{
final List<Emp> EMPS = new ArrayList<Emp>();// 创建一个List对象,用于存放解析出来的员工信息对象。
if (XML1.doc == null)
{
XML1.readDataFromXML(XML1.XML_PATH);
}
if (XML1.doc == null)
{
throw new NullPointerException("解析xml文档出错,docment对象为空。");
}
if (XML1.doc.hasRootElement())// 如果解析出来的Document对象有根元素节点时,才解析。
{
Element root = XML1.doc.getRootElement();// 获取xml根节点。
// 获取员工节点信息。说明:在Element对象里边还有个与该方法的重载方法,
// 是不带参数的,这个方法是返回所有的根节点的字节点对象。
List<Element> empsElement = root.getChildren("employee");
Emp emp = null;// 创建一个员工对象引用,在for循环中使用。
for (Element e : empsElement)// 获取emp对象,并将其放到List集合对象中。
{
emp = new Emp(Integer.valueOf(e.getChildTextTrim("empNo")), e
.getChildTextTrim("name"), Short.valueOf(e
.getChildTextTrim("age")), e.getChild("dept")
.getChildTextTrim("deptName"), Utils.stringTrim(e.getChild(
"name").getAttributeValue("attribute2")));
EMPS.add(emp);
}// end for (final Element e : empsElement)
}// end if (XML1.doc.hasRootElement())
return EMPS;
}
/**
* 把Docment对象写入到XML文档之中。
*
* @param doc
* 要被写入的Document对象。
* @param file
* 要被写入的XML文件名。注意,这个文件不能放入源代码包中, 因为如果放入到源代码包中如果将应用程序打包后就不能写入数据了。
* @throws IOException
* 输入流异常。
*/
public static void writeDocumentToXML(final Document doc, final String file)
throws IOException
{
OutputStream os = new FileOutputStream(file);
XMLOutputter out = new XMLOutputter();
out.output(doc, os);
os.close();
}
/**
* 添加一个员工信息到xml文档。
*
* @param emp
* 要添加的员工信息。
* @param addFile
* 添加员工信息后保存的xml文档名。
* @throws IOException
* 解析xml文档时,失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文档时出现非人为因素的异常。
* @exception NullPointerException
*/
private static void addEmpToXML(final Emp emp, final String addFile)
throws JDOMException, IOException
{
if (XML1.doc == null)
{
XML1.readDataFromXML(XML1.XML_PATH);
}
if (XML1.doc == null)
{
throw new NullPointerException("解析XML文件出错,Docment对象为空");
}
// 根据emp对象创建一个Element对象。
Element empElement = new Element("employee");
empElement.addContent(new Element("empNo").setText(String.valueOf(emp
.getEmpNo())));
empElement.addContent(new Element("name").setText(emp.getName())
.setAttribute("attribute1", emp.getAttribute()));
empElement.addContent(new Element("age").setText(String.valueOf(emp
.getAge())));
empElement.addContent(new Element("dept")
.addContent(new Element("name").setText(emp.getDept())));
XML1.doc.getRootElement().addContent(empElement);// 把员工信息添加到Docment对象中。
XML1.writeDocumentToXML(XML1.doc, addFile);// 添加到Document对象后,将其保存到xml文件。
}
/**
* 删除一个员工信息。根据员工名字删除一个员工信息,并将删除后的Docment写入到文件中。
*
* @param name
* 要删除的名字。
* @param removeFile
* 刪除後保存xml文件的文件名。
* @throws IOException
* 解析xml文档时,失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文档时出现非人为因素的异常。
*/
public static void remove(final String name, final String removeFile)
throws JDOMException, IOException
{
XML1.delete(name);
XML1.writeDocumentToXML(XML1.doc, removeFile);// 删除后把Docment对象写入到指定的xml文件中。
}
/**
* 从Docment中删除一个员工信息,删除后不写入xml文件。
*
* @param name
* 要删除的员工名字。
* @throws IOException
* 解析xml文档时,失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文档时出现非人为因素的异常。
*/
@SuppressWarnings("unchecked")
private static void delete(String name) throws JDOMException, IOException
{
if (Utils.isNullOrEmpty(name))// 如果name為空或空白字符串,認為其名字是錯誤的,直接返回。
{
return;
}
name = name.trim();// 去掉字符串的首尾空白。
if (XML1.doc == null)// 如果doc为空,重新解析XML文件。
{
XML1.readDataFromXML(XML1.XML_PATH);
}
if (XML1.doc == null)// 重新解析XML文件後,仍為空,拋出空指針異常。
{
throw new NullPointerException("解析XML文档出错,Docment对象为空。");
}
if (XML1.doc.hasRootElement())// doc有根元素節點才進行下邊操作。
{
List<Element> emps = XML1.doc.getRootElement().getChildren(
"employee");
for (Element e : emps)// 循環遍曆,找出與name對應的Element對象,並將其從Docment中刪除。
{
if (name.equals(e.getChildTextTrim("name")))
{
emps.remove(e);// 删除Emp。
break;// 刪除完後,退出循環。。
}// end if (name.equals(e.getChildTextTrim("name")))
}// end for (final Element e : emps)
}// end if (XML1.doc.hasRootElement())
}
/**
* 修改一个员工信息,修改后保存到指定的文件中。如果要修改的员工信息不存在于Docment对象中 (这里根据name是否相等来进行判断),
* 则将其做为新的员工信息添加到xml文件。
*
* @param emp
* 要修改的员工对象。
* @param modifyFile
* 修改后保存的文件名。
* @throws IOException
* 解析xml文档时,失败或中断的输入流操作而产生异常。
* @throws JDOMException
* 解析xml文档时出现非人为因素的异常。
*/
@SuppressWarnings("unchecked")
public static void modify(final Emp emp, final String modifyFile)
throws JDOMException, IOException
{
if ((emp == null) || (emp.getName() == null))
{
return;
}
// 方法一:
// 我始终感觉我这种方法很烂,但是写法很方法,如果有哪位大虾有好的修改方法,给我提供下,谢谢。
// 这里可以先判断下是否存在,不存在就不允许修改,这里我就不这样做了。
XML1.delete(emp.getName());// 先把员工信息从doc文档中删除。
XML1.addEmpToXML(emp, modifyFile);// 删除后再把新的员工信息保存到xml文件中。
// 方法二:
// 循环遍历Document对象,当其name值为emp的name值时,更改Element的其它属性。这种方法比较简单,但是比较麻烦。
// List<Element> empsEmelent = XML1.doc.getRootElement().getChildren(
// "employee");
// for (Element e : empsEmelent)
// {
// if (emp.getName().equals(e.getChildTextTrim("name")))
// {
// e.getChild("empNo").setText(String.valueOf(emp.getempNo()));
// e.getChild("name").getAttribute("attribute1").setValue(
// emp.getAttribute());
// e.getChild("dept").getChild("deptName").setText(emp.getDept());
// }
// }
// XML1.writeDocumentToXML(XML1.doc, XML1.XML_PATH);
}
/**
* XML1类主入口函数。
*
* @param args
* 虚拟机参数列表。
* @throws Exception
* 异常。为了方便,我这里将异常上抛。
*/
public static void main(final String[] args) throws Exception
{
Utils.print("-------读取开始---------");
XML1.readDataFromXML(XML1.XML_PATH);// 从xml文档中解析Docment对象。
List<Emp> emps = XML1.getDataFromDocument();
for (Emp e : emps)
{
Utils.print(e);
}
Utils.print("*******读取完成*********");
Utils.print("-------增加开始---------");
Emp e = new Emp(5, "添加的用户名", (short) 32, "部门名", "属性值");
XML1.addEmpToXML(e, "./add.xml");
Utils.print("*******增加完成*********");
Utils.print("-------删除开始---------");
XML1.remove("陈六", "./delete.xml");
Utils.print("*******删除完成*********");
Utils.print("-------修改开始---------");
e.setEmpNo(4);
e.setAttribute("修改属性值");
XML1.modify(e, "./modify.xml");
Utils.print("*******修改完成*********");
}
}
/**
* 工具类。说明,为了方便,我这里直接把这个类写在XML1.java文件里边。
*
* @author sky
* @version xmlPART1_1.0, May 5, 2009
* @since xmlPART1_1.0
*/
class Utils
{
/**
* 打印对象的字符串信息。<br/><br/> 如果要打印的对象为null,则直接打印出字符串“null”;为字符串,则直接把该字符串输出;
* 如果为其它非字符串对象,则打印该对象的toString()方法的返回值 。
*
* @param obj
* 要打印的对象。
*/
public static void print(final Object obj)
{
System.out.println(String.valueOf(obj));
}
/**
* 去掉字符串首尾的空白。因为String类的trim()方法只能由非空的String调用,如果出现类似如下的代码: <div
* style="padding-left:70px;padding-bottom:10px;"> String str=getXXX();<br/>
* str.trim(); </div>
* 当getXXX返回的结果为null时,执行str.trim()会抛NullPointerException的运行时异常。
*
* @param str
* 要去掉首尾空白的字符串。
* @return 返回去掉首尾空白后的字符串。如果字符串为空,返回“null”。
*/
public static String stringTrim(final String str)
{
return (str == null) ? "null" : (str.trim());
}
/**
* 判斷一個字符串是否為空或空白字符串。
*
* @param str
* 要判斷的字符串。
* @return 返回判斷的結果。如果字符串為null或空白字符串,返回true,否則返回false。
*/
public static boolean isNullOrEmpty(final String str)
{
return (str == null) || (str.trim().length() == 0);
}
}
/**
* 员工信息类。为了方便,在这里把这个类直接写在XML1.java文件中。
*
* @author sky
* @version xmlPART1_1.0, May 5, 2009
* @since xmlPART1_1.0
*/
final class Emp
{
private int empNo;
private String name;
private short age;
private String dept;
private String attribute;
/**
* 构造方法
*/
public Emp()
{
}
/**
* 构造方法
*
* @param name
* 姓名。
* @param age
* 年龄。
* @param dept
* 所在部门。
* @param attribute
* 其它属性值 。
* @param empNo
* 员工工号。
*/
public Emp(final int empNo, final String name, final short age,
final String dept, final String attribute)
{
this.empNo = empNo;
this.name = name;
this.age = age;
this.dept = dept;
this.attribute = attribute;
}
/**
* 获取empNo的值。
*
* @return 返回获取到的值。
*/
public final int getEmpNo()
{
return empNo;
}
/**
* 对empNo进行赋值。
*
* @param empNo
* 要被赋予的值。
*/
public final void setEmpNo(final int empNo)
{
this.empNo = empNo;
}
/**
* 获取name的值。
*
* @return 返回获取到的值。
*/
public final String getName()
{
return name;
}
/**
* 对name进行赋值。
*
* @param name
* 要被赋予的值。
*/
public final void setName(final String name)
{
this.name = name;
}
/**
* 获取age的值。
*
* @return 返回获取到的值。
*/
public final short getAge()
{
return age;
}
/**
* 对age进行赋值。
*
* @param age
* 要被赋予的值。
*/
public final void setAge(final short age)
{
this.age = age;
}
/**
* 获取dept的值。
*
* @return 返回获取到的值。
*/
public final String getDept()
{
return dept;
}
/**
* 对dept进行赋值。
*
* @param dept
* 要被赋予的值。
*/
public final void setDept(final String dept)
{
this.dept = dept;
}
/**
* 获取attribute的值。
*
* @return 返回获取到的值。
*/
public final String getAttribute()
{
return attribute;
}
/**
* 对attribute进行赋值。
*
* @param attribute
* 要被赋予的值。
*/
public final void setAttribute(final String attribute)
{
this.attribute = attribute;
}
/**
* 重写toString()方法,返回员工信息类的有意义的相关信息。
*
* @return 返回该类有意义的字符串形式。
* @see java.lang.Object#toString()
*/
@Override
public final String toString()
{
StringBuilder sb = new StringBuilder(50);
sb.append("Emp:hashCode = ").append(hashCode()).append(" empNo = ")
.append(empNo).append(" name = ").append(name).append(" age = ")
.append(age).append(" dept = ").append(dept)
.append(" attribute = ").append(attribute);
return sb.toString();
}
}