@author:Edison丶梦楠
转载请注明作者~!
关于什么是DOM,请自行查阅!作者在这里不做解释。
本文演示的XML为了演示方便,放在项目中,采用绝对路径的方法。
以下是创建的XML:
获得Document对象模型的方法:
1:找到DocumentBuilderFactory工厂类,调用newInstance();方法返回的是工厂类对象。factory
2:通过factory对象调用newDocumentBuilder()方法,返回DocumentBuilder对象builder
3:(返回Document的第一种方式)通过builder对象调用newIDocument()方法,返回Document对象。注意:此方法是针对没有XML文档时调用的方法。(调用此方法,会在内存中建立一个树状Document模型)
返回Document对象的第二种方式:通过builder对象调用parse(File f这里是XML的文件路径,也可以接收一个输入流) 也可以返回Document对象,但是这个方法是建立在有XML文件的前提下的。
PS:解析XML文档时,返回的是Document对象,和DateFormat中的parse()方法返回的是Date对象的理解相同。
为了更好的解释,博主采用画图的方式进行进一步理解。
下面是具体实现
在项目中引入Junit4单元测试插件,
创建test方法
DOM操作1:获取元素内容
package com.hard.dom;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Assert;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class DOMTest {
private File f = new File("E:/java_project/DOM/user.xml");
@Test
public void testSelect() throws Exception {
//获取Document文档对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document d = db.parse(f);
//获取文档对象中的根节点
Element root = d.getDocumentElement();
/*
* 获取根节点下的所有子元素。因为我们知道想要获取
* 哪一个根节点下的子元素,所以我们调用item(index)
* index表示找linkman下的第几个子元素
* 因为返回的是NodeList集合,所以我们必须强转为Element。
* 得到子元素
*/
Element linkmanChild = (Element) root.getElementsByTagName("linkman").item(0);
//获取linkman元素下的子元素name元素
Element name = (Element) linkmanChild.getElementsByTagName("name").item(0);
//使用断言,看看结果能不能达到我们的预想
Assert.assertEquals("错误提示~!", "博主很年轻",name.getTextContent());
System.out.println(name.getTextContent());
}
}
断言显示蓝条,并没有报错。
打印结果:
DOM操作2:修改XML操作:
@Test
public void testAlter() throws Exception {
//获得Document文档对象
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
//获得根节点
Element root = doc.getDocumentElement();
//获得根节点下的子元素
Element linkman =(Element) root.getElementsByTagName("linkman").item(1);
//获得linkman元素下的子元素
Element name =(Element) linkman.getElementsByTagName("addr").item(0);
//修改name属性文本中的新内容
name.setTextContent("安徽省");
//使用断言 查看是否成功修改
Assert.assertEquals("you is false!", "安徽省",name.getTextContent());
}
此时修改成功只是修改了内存中的Document对象模型,而实际文件内容并没有发生改变。
此时我们就需要做同步操作。核心类:TransFormer
//同步操作 把内存中的文档模型同步到本地磁盘中
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
//xmlSource 表示源文件 outputTarget 表示目标文件,要同步到哪个文件
Source xmlSource = new DOMSource(doc);
Result target = new StreamResult(f);
transformer.transform(xmlSource, target);
Source为接口,所以必须new它的实现类。通过实现类的构造器传入源文件。
Result也为接口。所以必须new它的实现类,但注意:这里我们不能再调用DOMResult对象,因为内存中的数据想要同步到本地磁盘中,就必须以(Stream)流的方式,所以此时我们得new它的实现类StremResult(目标文件);
此时我们查看user.xml中,博主的addr已被改变。
DOM操作3:添加一个新的用户信息(向本地磁盘XML文件中添加一个新的人员信息)
@Test //向本地磁盘XML文件中添加一个新的人员信息
public void testAdd() throws Exception {
//获取Document文档对象
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
//获取根节点
Element root = doc.getDocumentElement();
//创建新的子节点元素
Element linkman = doc.createElement("linkman");
Element name= doc.createElement("name");
name.setTextContent("陈二蒙");
Element age = doc.createElement("age");
age.setTextContent("21");
Element addr = doc.createElement("addr");
addr.setTextContent("安徽省六安市");
/*
* 此时我们在内存模型中创建了
* <linkman></linkman>
* <name></name>
* <age></age>
* <addr></addr>
* 并为他们设置了元素的文本内容
* 但是我们发现,他们并没有包含在linkman父元素中(同级关系)
* 所以此时我们得把name,age,addr设为linkman的子元素
*/
root.appendChild(linkman);
linkman.appendChild(name);
linkman.appendChild(age);
linkman.appendChild(addr);
//把内存中的树状结构模型同步到本地磁盘中
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc),new StreamResult(f) );
}
此时我们再回到user.xml文件中可以看到内容已经发生改变
DOM操作4:设置和获取元素属性
//设置和获取元素的属性
@Test
public void testProperty() throws Exception {
/*
* 给linkman元素添加一个id属性
*/
//获取Document文档对象.
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
//获取根节点
Element root = doc.getDocumentElement();
//获取根节点子元素
Element linkmanEl = (Element) root.getElementsByTagName("linkman").item(2);
//给根节点设置属性
linkmanEl.setAttribute("id", "2");
//将模型写入本地xml文件
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(f));
/*
* 获取linkman的属性
*/
linkmanEl.getAttribute("id");
//断言测试是否成功获取
Assert.assertEquals("2", linkmanEl.getAttribute("id"));
//显示绿条,表示成功获取
}
此时我们看到,第三个linkman元素被添加了一个id的属性
DOM操作5:删除指定用户
@Test //删除第一个用户的信息
public void testDelete() throws Exception {
//获取文档对象
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
//获取根节点
Element root = doc.getDocumentElement();
//获取第一个item(0) 的linkman元素
Element linkmanEl =(Element) root.getElementsByTagName("linkman").item(0);
//通过根节点的removeChild方法,移除此指定的linkman元素
root.removeChild(linkmanEl);
///同步到本地xml磁盘文件中
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(f));
此时我们发现第一个元素已被删除
DOM操作6:创建Document对象
创建Document对象有两种方式,前文提到过。
在我们创建Document对象时,有两种情况:
第一种是xml文件存在的情况下,我们解析过后,直接返回Document文档对象,并不需要再创建根目录。
第二种是xml文件不存在的情况下,调用Document对象的.newDocument()方法,创建文档对象,并创建根目录。
我们考虑的上述第二种情况是属于极端情况,在实际业务中可能不存在。实际业务中,一般不会存在没有xml的情况。
一般的,即使xml文件没有内容,也会有根节点。
@Test //创建Document对象
public void testCreateDocument() throws Exception {
//创建builder对象 先不要解析 因为我们不知道文件存不存在
DocumentBuilder builder= DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = null;
Element root = null;
if(f.exists()) {
//如果文件存在,则解析该文件
builder.parse(f);
}else {
//如果不存在,则新建文档对象
doc = builder.newDocument();
//并为该对象创建根元素
root=doc.createElement("contacts");
//并把该根元素追加作为文档对象的子元素
doc.appendChild(root);
}
/**
* 下面测试保存一个联系人
*/
//创建子元素
Element linkmanEl = doc.createElement("linkman");
linkmanEl.setAttribute("sex", "男");
Element nameEl= doc.createElement("name");
Element ageEl = doc.createElement("age");
Element addrEl= doc.createElement("addr");
//为name,age,addr添加文本内容
nameEl.setTextContent("彭于晏");
ageEl.setTextContent("35");
addrEl.setTextContent("江苏南京");
//把linkman作为子元素追加到父元素contacts中
root.appendChild(linkmanEl);
//把name,age,addr作为子元素追加到父元素linkman中
linkmanEl.appendChild(nameEl);
linkmanEl.appendChild(ageEl);
linkmanEl.appendChild(addrEl);
//同步到本地磁盘文件中
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(f));
}
此时,我们把项目中的xml文件删除,看看能否成功创建文件,并添加一个用户信息。
成功啦!