xml文件被广泛应用于各种领域,例如网络数据的传输和软件配置文件的设置。例如:最近很流行的ajax技术就是基于xml、 javascript、html的技术通过发送XHR(xml http request)的机制进行实现,再如:聊天工具QQ的配置文件:
xml文件是一种树形的结构(称为节点树),最上层是根节点。
下面是一个简单的xml文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?
xml
version = "1.0" encoding = "UTF-8"?>
<
bookstore
>
<
book
id
=
"1"
>
<
name
>冰与火之歌</
name
>
<
author
>乔治马丁</
author
>
<
year
>2014</
year
>
<
price
>89</
price
>
</
book
>
<
book
id
=
"2"
>
<
name
>安徒生童话</
name
>
<
year
>2004</
year
>
<
price
>77</
price
>
<
language
>English</
language
>
</
book
>
</
bookstore
>
|
XML文件的应用:
订票软件和支付软件的实现机制是不一样的,但是它们需要共享用户的信息。
不同操作系统的底层的实现机制是不同的,但是它们可以通过相同的xml文件进行通信。
手机和网站需要通过xml文件共享网站的数据。
需要了解更多关于xml的信息,请参见:w3school中关于xml的系列教程。
【xml文件的解析】
xml文件的读取又叫做xml文件的解析。xml文件的解析的目的是:
在java中XML文件的解析方式通常有4种:
在解析XML文件的解析的时候始终要注意2点:
1. 需要取得xml文件中的所有数据;
2. 需要保存xml文件的树形结构(节点之间的层级关系)。
一、DOM方式解析XML文件
XML DOM (XML Document Object Model) 定义了访问和操作 XML 文档的标准方法。DOM 把 XML 文档作为树结构来查看。能够通过 DOM 树来访问所有元素。
根据 DOM,XML 文档中的每个成分都是一个节点。
DOM 是这样规定的:
1. 整个文档是一个文档节点
2. 每个 XML 标签是一个元素节点
3. 包含在 XML 元素中的文本是文本节点
4. 每一个 XML 属性是一个属性节点
5. 注释属于注释节点
文本总是存在于文本节点中。在 DOM 处理中一个普遍的错误是,认为元素节点包含文本,实际上元素节点的文本是存储在文本节点中的。例如以上的books.xml文件中:
1
|
<
name
>冰与火之歌</
name
>
|
元素节点<name>拥有一个值为“冰与火之歌”的文本节点(元素节点拥有子节点文本节点),所以获取元素节点中的内容的时候,应该获取其子节点的NodeValue或者用getTextContent()方法获取其中的文本。
首先在Eclipse中新建一个java项目,再将我们事先写好的books.xml添加到项目中:
通过DOM方式解析XML文件需要3个步骤:
1、创建一个DocumentBuilderFactory对象(DocumentBuilderFactory的静态方法);
2、使用创建DocumentBuilderFactory的实例对象创建一个DocumentBuilder对象;
3、通过DocumentBuilder对象的parse(String fileName)方法解析xml文档。
XML DOM的节点及其返回值简表如下:
下面的一个简单的代码用于解析上面的books.xml文件:
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* 该类用DOM的方式解析xml
*
*/
public class DOMTest {
public static void main(String[] args) {
// 1.创建一个DocumentBuilderFactory对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// 2.使用DocumentBuilderFactory的newDocumentBuilder()方法创建DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
// 3.通过DocumentBuilder对象的parse(String fileName)方法解析xml文档
Document document = db.parse("books.xml");
NodeList bookList = document.getElementsByTagName("book");// 获取所有的book节点的集合
System.out.println("一共有" + bookList.getLength() + "本书!");
// 遍历每一个book节点
for (int i = 0; i < bookList.getLength(); i++) {
System.out.println("***************下面开始遍历第" + (i + 1)
+ "本书的内容*****************");
Node bookNode = (Node) bookList.item(i);// 通过item(i)方法获取一个book节点
NamedNodeMap attributes = bookNode.getAttributes();// 获取book节点的属性集合
System.out.println("第" + (i + 1) + "本书共有"
+ attributes.getLength() + "个属性!");
// 遍历book节点的属性
for (int j = 0; j < attributes.getLength(); j++) {
Node attribute = attributes.item(j);// 通过item(index)方法获取NamedNodeMap中的某个属性
System.out.print("属性名:" + attribute.getNodeName());
System.out.println("-属性值:" + attribute.getNodeValue());
}
// 解析book节点的子节点
NodeList childNodes = bookNode.getChildNodes();
// 遍历childNodes获取每个节点的节点名和节点值
for (int j = 0; j < childNodes.getLength(); j++) {
// 区分textNode和elementNode,过滤空白
if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) {
System.out.print("第" + (j + 1) + "个节点的节点名是:"
+ childNodes.item(j).getNodeName() + "--");// 获取元素节点的节点名
System.out.println("节点值是:"
+ childNodes.item(j).getFirstChild()
.getNodeValue());// 获取节点值,元素节点的子节点的nodeValue
}
}
System.out.println("**************结束遍历第" + (i + 1)
+ "本书**************");
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
注意:图中为什么显示2、4、6、8的节点,仔细观察books.xml应该是:对于第一本书的book的子节点,第一个子节点是name,第二个子节点应该是author,第三个节点应该是year,第四个节点应该是price,但是以上结果中name、author、year、price分别对应2、4、6、8节点,这是什么原因呢?实际上标准的XML文档是不带有任何空白和缩进的(缩进只是为了便于人们手工编码),空白字符会被认为是文本节点,因此文档中的1、3、5、7、9应该是文本节点,见下图:
DOM方式解析XML文件的一些简单操作:
1. 如果已知一个元素节点个属性名,可以将该节点转化为元素节点,然后用getAttribute(String attrName)方法获得其指定的属性值;
将以上代码的37~45行改为如下:
Element bookElement = (Element) bookNode;//将book节点转化为元素节点
String attrValue = bookElement.getAttribute("id"); //获取id属性
System.out.println("第"+(i+1)+"本书的id属性:"+attrValue);
2. 可以通过元素节点的getTextContent()方法获取元素节点中的文本内容(该标签中的所有内容都被当做文本来处理),而不需要通过getFirstChild().getNodeValue()方法。
将以上代码的55行可以改为如下:
System.out.println("节点值:" + childNodes.item(j).getTextContent());
将XML中的数据保存到java对象;
通过DOM的方式解析XML文件如果需要保存XML中的数据其实非常简单,我们只需要创建一个相应的对象,在本例中我们创建Book对象,并依照属性名和标签名为该类创建一些属性字段提供一系列的setter,本帖三楼中类的设计。
在DOM解析的时候,每遇到一个该类所代表的节点,在本例中是book元素节点就为其创建一个对象,每遇到一个XML标签或者是属性就用setter方法为类设置相应的属性:
/**
* 该类用DOM的方式解析xml,将其保存到java对象
*
*/
public class DOMTest {
private static Book book = null;// 声明一个全局的book对象
private static ArrayList<Book> books = new ArrayList<Book>();
public ArrayList<Book> getBookList() {
return books;
}
public static void main(String[] args) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse("books.xml");
NodeList bookList = document.getElementsByTagName("book");
// 遍历每一个book节点
for (int i = 0; i < bookList.getLength(); i++) {
book = new Book();// 每遇到一个book节点就创建一个book对象
Node bookNode = (Node) bookList.item(i);
NamedNodeMap attributes = bookNode.getAttributes();
// 遍历book节点的属性
for (int j = 0; j < attributes.getLength(); j++) {
Node attribute = attributes.item(j);
if ("id".equals(attribute.getNodeName())) {
book.setId(attribute.getNodeValue());
}
}
// 解析book节点的子节点
NodeList childNodes = bookNode.getChildNodes();
// 遍历childNodes获取每个节点的节点名和节点值
for (int j = 0; j < childNodes.getLength(); j++) {
// 区分textNode和elementNode
if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) {
if ("name".equals(childNodes.item(j).getNodeName())) {
book.setName(childNodes.item(j).getFirstChild()
.getNodeValue());
} else if ("author".equals(childNodes.item(j)
.getNodeName())) {
book.setAuthor(childNodes.item(j).getTextContent());
} else if ("year".equals(childNodes.item(j)
.getNodeName())) {
book.setYear(childNodes.item(j).getTextContent());
} else if ("price".equals(childNodes.item(j)
.getNodeName())) {
book.setPrice(childNodes.item(j).getTextContent());
} else if ("language".equals(childNodes.item(j)
.getNodeName())) {
book.setLanguage(childNodes.item(j)
.getTextContent());
}
}
}
books.add(book);// 结束一本书的遍历的时候将其加入ArrayList中
}
// 输出arrayList中的book对象
System.out.println("arrayList中一共有" + books.size() + "本书!");
for (Book book : books) {
System.out.println(book);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}