一、 JAXP 简介
JAXP 使得用 Java 开发处理 XML 数据的应用程序非常容易,JAXP 包括语法分析器、标准 SAX 与 DOM ,可以选择以事件流或建立对象表示来解析数据。JAXP 1.1 版本还支持XSLT 标准, 可以控制数据的表示, 并可以将数据转换成其他的XML 文件或格式, 如HTML 。JAXP 还提供对名称空间的支持,可以在没有命名冲突的情况下使用 DTD 。
JAXP 提供的类和方法,可以让 Java 应用程序使用 DOM 解析或转换 XML 文件,在JDK 1.4 支持的JAXP API 1.1 版支持XML , 建议规格有DOM Level 2 、 XSLT 1.0 和SAX 2.0 。其解析文档对象模型的相关套件,见表。
表 JAXP API 1.1 解析文档对象模型的相关套件
套 件 | 说 明 |
Javax.xml.parsers | 提供处理XML 文件的类 |
Javax.xml.transform | 提供处理XSLT 文件的类 |
org.xml.sax | 这是SAX 解析器,提供以事件驱动方式解析XML 文件的AP |
org.xml.saxhelpers | 提供解析错误处理的相关类,可以帮助程序设计者使用SAX API |
org.w3c.dom | 提供支持DOM 建议规格的套件 |
二、加载 XML 文档文件
在 Java 程序中加载 XML 文档文件,步骤如下。
1 、首先需要导入相关的套件。
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import java.io.*;
其中org.xml.sax.* 套件是解析错误处理的相关套件,此外因为XML 文件属于文本文件,
所以导入文件处理的套件用 import java.io.* 。
2 、在 JAXP 中,DOM 解析器称为 DocumentBulider ,可以通过工厂类 DocumentBulider Factory 获得,而 document 对象则可以通过类 DocumentBulider 获得,使用 try catch 指令建立解析的错误处理。在建立 DocumentBulider 对象后,可使用 parser 方法解析加载 XML 文件,file 对象加载后就可以处理 XML 文件的结点内容。
3 、获得接口类 document 实例后,就可以对 DOM 的文档树进行访问。如要遍历 DOM 文档,首先要获得根结点,然后获得根结点的子结点列表。
// 获得根结点
Element element=document.getDocumentElement();
// 获得根结点的子结点列表
NodeList=element.getChildNodes();
三、XML编程——CRUD
1 、访问 XML 元素和属性
在 DOM 接口规范中,有 4 个基本接口:Document 、Node 、NodeList 、Element 。在这4 个基本接口中,Document 接口是对文档进行操作的入口,它是从 Node 接口继承过来的。Node 接口是其他大多数接口的父类,像 Document 、Element 、Text 、Comment 等接口都是从 Node 接口继承过来的。NodeList 接口是一个结点的集合,它包含了某个结点中的所有子结点。下面对这几个接口分别做一些简单的介绍。
Document 接口
Document 接口代表了整个 XML 文档,因此,它是整个文档树的根,提供了对文档中数据进行访问和操作的入口。通过 Document 结点,可以访问到文档中的其他结点,如处理指令、批注、文字等。
方法描述:
1) getDocumentElement() , Document 文件对象使用该方法可获取XML 文件的根结点;
2) getElementsByTagName() , Document 使用标记名获取子结点,取出的结点是一个NodeList 对象。
Node 接口
Node 接口在整个 DOM 树中具有举足轻重的地位,DOM 接口中很大一部分接口是从Node 接口继承过来的,例如 Document 、Element 、Text 、Comment 等接口。在 DOM 树中,Node 接口代表了树中的一个结点。
方法描述:
1) getChildNodes() ,获取子结点的 NodeList 结点对象列表,即子结点数;
2) getNodeName() ,返回结点名称,不同类型结点的值不同;
3) getNodeType() ,返回结点类型的代码;
4) getNodeValue() ,返回结点的值;
5) getFirstChild() ,获取第一个子结点;
6) getNextSibling() ,获取此结点的兄弟结点,即同级的下一个结点;
7) getLastChild() ,获取最后一个子结点;
8) getParentNode() ,获取父结点;
9) hasChildNodes() ,Node 结点对象检查是否拥有子结点,是返回 true ,否则为 false 。
NodeList 接口
NodeList 接口提供了对结点集合的抽象定义, 它并不包含如何实现这个结点集的定义。NodeList 接口用于表示有顺序关系的一组结点,比如某个结点的子结点序列。其中的每个item 都可以通过一个索引来访问,该索引值从 0 开始。另外,它还出现在一些方法的返回值中。
方法描述:
(1) getLength() ,可获取 NodeList 对象共有多少结点,即结点的个数;
(2) item(int) ,返回参数制定的结点对象,参数是结点对象的索引值。
Element 接口
Element 接口是从 Node 接口继承过来的,它代表了 XML 文档中的元素。Element 接口提供了访问 DOM 树中元素内容与信息的途径,并给出了对 DOM 树中的元素进行遍历的支持。
方法描述:
(1) getElementsByTagName(string) ,通过标记名称获取元素;
(2) getTagName() ,获取元素的标记的名称;
(3) getAttributes(string) ,获取元素的属性,是属性对象列表,属于 NamedNodeMap ;
(4) getAttributeNode(string) ,通过属性的名字得到一个属性类型结点。
下面通过一个实例来说明如何使用上述对象和方法来解析 XML 文档。
Demo1.java 代码清单如下:
package cn.csdn.xml;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Demo1 {
@Test
public void test() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringComments(true);
DocumentBuilder db;
try {
db = dbf.newDocumentBuilder();
Document document = db.parse(new File("src\\code2.xml"));
Node root = document.getDocumentElement();
NodeList list = root.getChildNodes();
display(list);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void display(NodeList list) {
if (list.getLength() == 0) {
System.out.println("该结点没有子结点!");
}
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
// 获取结点的类型,可以是ElementNode,TextNode,DocumentNode等
short nodetype = node.getNodeType();
if (nodetype == Node.ELEMENT_NODE) {
System.out.println(node.getNodeName());
if (node.hasAttributes()) {
Node attribute = node.getAttributes().item(0);
System.out.println(attribute.getNodeName() + " "
+ attribute.getNodeValue());
}
if (node.hasChildNodes()) {
display(node.getChildNodes());
}
}
if (nodetype == Node.TEXT_NODE) {
String txtName = node.getNodeName();
// 取出text类型结点的值
Node parent = node.getParentNode(); //此结点的父结点
Node txtNode = parent.getChildNodes().item(0);
String txtValue = txtNode.getNodeValue();
if (txtValue.trim().length() > 0) {
System.out.println(txtName + " " + txtValue);
}
}
}
}
}
2 、使用 DOM 创建 XML 文档
创建 XML 文档
可以使用 newDecument 方法建立 XML 文档。
Document=db.newDecument();
建立新的结点
使用 Document 对象的方法建立所需结点对象,见表。
建立新结点的方法
方 法 | 说 明 |
createElement(string) | 建立XML 元素的结点,参数为标记名称 |
createAttribute(string) | 建立属性名称的属性结点,参数是属性名称 |
createCDATASection(string) | 建立CDATA 块,参数是文字内容 |
createComment(string) | 建立注释文字结点,参数为注释文字内容 |
createTextNode(string) | 建立文字结点,参数为内容 |
createEntityReference(string) | 建立实体参考,参数为实体参考名称 |
createProcessingInstring(string,string) | 建立PI 结点,第一个参数是PI 名称,第二个为值 |
指定插入的位置
在建立好 XML 元素的对象后,可以使用 Node 结点对象的方法添加到 DOM 树中:
Ø appendChild(newnode) ,新添加一个 newnode 结点;
Ø insertBefore(newnode,befnode) ,将 newnode 结点插到 befnode 结点前。
新增元素内容
使用 createTextNode 方法建立文字结点后, 再使用 appendChild 方法将它添加到元素结点中。
新增元素的属性
可以使用 setAttribute 方法给 Element 元素对象增加属性。
使用 DOM 对象创建 XML 文件,代码清单如下:
package cn.csdn.xml;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class Demo2 {
// 使用DOM创建一个XML文档
static Document document;
@Test
public void testAdd() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
// 建立新的XML文档
document = db.newDocument();
// 建立根元素
Element root = document.createElement("中国");
document.appendChild(root);
// 新增子元素 陕西省
Element newchild = document.createElement("陕西省");
root.appendChild(newchild);
// 增加元素的内容
newchild.appendChild(document.createTextNode("交通大学"));
// 增加元素的属性
newchild = (Element) root.getFirstChild();
newchild.setAttribute("ID", "0x8905072");
// 新增子元素 河北省
newchild = document.createElement("河北省");
root.appendChild(newchild);
// 增加元素的内容
newchild.appendChild(document.createTextNode("河北软件职业技术 学院"));
// 新增子元素 北京市
newchild = document.createElement("北京市");
// 新增元素插入在根元素的最后一个节点前面
root.insertBefore(newchild, root.getLastChild());
// 新增文字节点
Node text = document.createTextNode("中关村软件园");
// 插入文字结点到根结点第一个子结点的兄弟结点,即第二子结点
Node temp = root.getFirstChild();
temp.getNextSibling().appendChild(text);
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
"src\\code.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public void testIndexAdd() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringComments(true);
try {
DocumentBuilder db = dbf.newDocumentBuilder();
// 记载XML源文件
document = db.parse(new File("src\\code2.xml"));
// 获取节点,因为要将新增的子元素插在元素“海淀”之前,所以这里获取根元素“北京”的节点
Node node = document.getElementsByTagName("北京").item(0);
// 新增子元素
Element ele = document.createElement("昌平");
ele.appendChild(document.createTextNode("O(∩_∩)O哈哈~"));
node.insertBefore(ele, node.getFirstChild()); // 将新增子元素“昌平”插入元素“海淀”的前面
// 新增子元素
ele = document.createElement("新密");
// 获取节点
node = document.getElementsByTagName("郑州").item(0);
// // 将新增子元素“新密”插入元素“商丘”的前面
node.insertBefore(ele, node.getFirstChild()); //插入元素“商丘”之后,则为node.getLastChild();
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
"src\\code2.xml"));
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3、 使用DOM 删除元素或属性
如要删除结点可使用 Node 结点的 removeChild 方法删除指定的结点,如要删除属性可使用 Element 元素对象的 removeAttribute 方法删除。
// 删除第一个customer 结点
root.removeChild(Element)root.getElementsBytagName("customer").item(0);
// 删除属性
Element node=(Element)root.getFirstChild();
Node.removeAttribute("ID")
看下面的代码片段。
public void test1()throws Exception{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("src\\dom.xml"));
Node node = doc.getElementsByTagName("海淀").item(0);
node.removeChild(doc.getElementsByTagName("东北旺").item(2));
TransformerFactory factory1 = TransformerFactory.newInstance();
Transformer tformer = factory1.newTransformer();
tformer.transform(new DOMSource(doc), new StreamResult("src\\dom.xml"));
}
4 、使用DOM 更改元素的值
public void test2()throws Exception{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("src\\dom.xml"));
Node node1 = doc.getElementsByTagName("东北旺").item(0);
node1.setTextContent("未知地区");
TransformerFactory factory1 = TransformerFactory.newInstance();
Transformer tformer = factory1.newTransformer();
tformer.transform(new DOMSource(doc), new StreamResult("src\\dom.xml"));
}
以上案例使用的dom.xml 代码清单如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><中国> <北京> <海淀> <上地>上地七街</上地> <中关村>鼎好</中关村> <东北旺>哈哈</东北旺> <东北旺/></海淀> </北京> <河南> <郑州> <商丘 id="attr" 人口="100万">商丘中学</商丘> </郑州> <安阳/> </河南> <河北> <石家庄 人口="2000万"/> </河北> </中国>
四、小结
本文主要介绍 Java 应用程序如何使用 DOM 处理 XML 文件。要创建 DOM 需要使用JAXP ,JAXP 使得用Java 开发处理XML 文件的应用程序非常容易,只要在Java 程序中导入相关的套件, 如import javax.xml.parsers.* 、 import org.xml.sax.* 、 import org.w3c.dom.* 、 import java.io.* ,就可以使用它所提供的类和方法,让 Java 应用程序使用 DOM 加载 XML 文件,访问、增加和删除 XML 元素和属性。