XML第十三讲:使用DOM解析XML文档

    上一讲内容我们讲解了 简单工厂模式 这个设计模式就是为了服务于XML解析的,通过前面几讲的内容我们已经学会了如何写XML,如何写DTD,Schema文档来验证XML。从这一讲开始我们就来详细的剖析一下XML解析,XML解析,就是如何通过Java代码去处理XML,给你一个XML,如何提取出你想要的东西出来。

1. XML解析的方式:DOM和SAX解析
   W3C制定了一套书写XML分析器的标准接口规范--DOM。除此之外,XML_DEV邮件列表中的成员根据应用的需求也自发地定义了一套对XML文档进行操作的接口规范--SAX。这两种接口规范各有侧重,互有长短,应用都比较广泛。
   [也就是说DOM是由W3C指定的标准,而SAX是民间的一种XML解析标准。]
   我们给出DOM和SAX在应用程序开发过程中所处地位的示意图。参考图1,从图中可以看出,应用程序不是直接对XML文档进行操作的,而是首先由XML分析器对XML文档进行分析,然后,应用程序通过XML分析器所提供的DOM接口或SAX接口对分析结果进行操作,从而间接地实现了对XML文档的访问。
  

2. DOM解析

DOM:Document Object Model (文档对象模型)。

   DOM是基于树形结构来处理的。XML文档本身也是树形结构的,它与XML文档是非常吻合的。DOM解析的方式,首先读取XML文档,然后在内存里面形成一棵树形的结构,这就结构就反映出来XML的结构,接下我们就可以遍历这棵树,从根结点到叶子结点,每一个结点都可以认为它是一个元素。然后从结点提取出来元素的内容,元素的属性等信息都可以拿到了。
   DOM也有缺点的,因为要将XML文档读取到内存里面了,如果内容比较大,则其消耗就会高。读取到内存,内存里面构造出来的就是对象,这些对象都是要消耗内存的。这么多对象,必然会消耗内存,正因为有这个缺陷,所以就产生了SAX解析,它就没有这个缺点了。

  对于XML应用开发来说,DOM就是一个对象化的XML数据接口,一个与语言无关、与平台无关的标准接口规范 [这个接口是由W3C标准制定的,它是没有实现的,是由各个厂商根据接口的描述把对应的实现类提供出来的。另外它跟语言无关,换句话说Java根据这个接口的实现定义方式用Java代码实现这个接口,同理.Net同样根据这种规范用.Net的语言将其实现出来。接口是一样的,但是实现方式是不一样的,但是接口所实现的功能是一样的。]

3.DOM

<?xml version="1.0" encoding="gb2312"?>
<addressbook>
    <person sex = "male">
        <name>张三</name>
        <email>zhs@xml.net.cn</email>
    </person>
    <person sex = "male">
        <name>李四</name>
        <email>ls@xml.net.cn</email>
    </person>
</addressbook>

  从上面的XML文档,可以发现这是个标准XML文档,将其倒过来可以发现它是一个树形结构,则它在内存中形成的对象布局也是一个树形结构,所以可以通过得到文档根元素之后访问所要访问的内容了如下图所示:


   

4. DOM模型结构

1) 标准的XML文档

<?xml version="1.0" encoding="gb2312"?>
<books>
	<book>
		<author>至尊宝</author>
		<title>倘若时光倒流</title>
	</book>
	<book>
		<author>白晶晶</author>
		<title>月光宝盒实用大全</title>
	</book>
</books>

2) DOM模型结构



    注意上图中的的文档(根节点)根元素节点的不同,根节点表示的整个文档本身,它是我们访问XML的入口,我们都要从根节点开始,来获取到这个XML文档的DOCUMENT对象,获得到对象之后,就可以得到它的根元素,之后就可以逐层递进了。而根元素节点表示这个文档的根元个根元素节点而已。
    要严格区分XML文档树中的根结点与根元素结点:根节点(Document)代表的是XML文档本身,是我们解析XML文档的入口,而根元素结点则表示XML文档的根元素,它对应于XML文档的Root。

5. 最常见的节点类型

1)元素:元素是 XML 的基本构件。典型地,元素可以有其它元素、文本节点或两者兼有来作为其子节点。元素节点还是可以有属性的唯一类型的节点。
2)属性:属性节点包含关于元素节点的信息,但实际上,不认为它是元素的子节点
3)文本:确切来讲,文本节点是:文本。它可以包含许多信息或仅仅是空白。
4)文档(根节点):文档节点是整个文档中所有其它节点的父节点。(根节点不等于根元素节点!)如上图的节点books

   [说明]属性不是元素的子结点,属性是元素的一种固有的特性,元素的子结点是它的子元素。文本就是普通的空白字符之类的。

还有较不常见的节点类型:CDATA、注释、处理指令我们在使用XML解析的时候主要遇到类型是一个是元素,一个是元素的内容,一个是属性和属性值,这是我们最常用的。

6. DOM的四个基本接口

    在DOM接口规范中,有四个基本的接口:Document,Node,NodeList以及NamedNodeMap。在这四个基本接口中,Document接口是对文档进行操作的入口,它是从Node接口继承过来的。Node接口是其他大多数接口的父类,象Document,Element,Attribute,Text,Comment等接口都是从Node接口继承过来的。NodeList接口是一个节点的集合,它包含了某个节点中的所有子节点。NamedNodeMap接口也是一个节点的集合,通过该接口,可以建立节点名和节点之间的一一映射关系,从而利用节点名可以直接访问特定的节点。这四个基本接口基本上就可以完成大部分的操作了。

1) Document接口

查看JDK文档中Document的说明,这里就不再阐述,注意的是它是位于org.w3c.dom包下的,在DOM树中,Document接口同其他接口之间的关系如下图所示:

2) Node接口

   Node接口在整个DOM树中具有举足轻重的地位,DOM接口中有很大一部分接口是从Node接口继承过来的,例如,Element、Attr、CDATASection等接口,都是从Node继承过来的。在DOM树中,Node接口代表了树中的一个节点。一个典型的Node接口如下图所示:同样,查看JDK文档中Node接口的说明,这里不做阐述

    [说明]:w3c 把元素,元素里面的内容,文本,注释、属性都是用Node来表示,所以在解析的时候要经常进行向下类型转换。查看JDK文档,可以发现Element、Attr等的父接口都是Node

3) NodeList

   可以装多个列表,查看JDK文档中的用法,需要注意的是:NodeList中的每个item都可以通过一个索引来访问,该索引值从0开始。

4) NamedNodeMap

   NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。NamedNodeMap接口经常都是跟属性打交道的,属性的名字不能重复,它的值可以不要求,可以看出他的特性与Map很相似。

  查看JDK文档介绍和方法,以便更好的使用。

7.练习使用DOM解析XML

  下面有一份XML文档,我们现在利用DOM解析将下面文档的4个PERSON的5个信息:NAME、ADDRESS、TEL、FAX、EMAIL提取打印出来。

<?xml version="1.0"?>
<PEOPLE>
	<PERSON PERSONID="E01">
		<NAME>Tony Blair</NAME>
		<ADDRESS>10 Downing Street, London, UK</ADDRESS>
		<TEL>(061) 98765</TEL>
		<FAX>(061) 98765</FAX>
		<EMAIL>blair@everywhere.com</EMAIL>
	</PERSON>
	<PERSON PERSONID="E02">
		<NAME>Bill Clinton</NAME>
		<ADDRESS>White House, USA</ADDRESS>
		<TEL>(001) 6400 98765</TEL>
		<FAX>(001) 6400 98765</FAX>
		<EMAIL>bill@everywhere.com</EMAIL>
	</PERSON>
	<PERSON PERSONID="E03">
		<NAME>Tom Cruise</NAME>
		<ADDRESS>57 Jumbo Street, New York, USA</ADDRESS>
		<TEL>(001) 4500 67859</TEL>
		<FAX>(001) 4500 67859</FAX>
		<EMAIL>cruise@everywhere.com</EMAIL>
	</PERSON>
	<PERSON PERSONID="E04">
		<NAME>Linda Goodman</NAME>
		<ADDRESS>78 Crax Lane, London, UK</ADDRESS>
		<TEL>(061) 54 56789</TEL>
		<FAX>(061) 54 56789</FAX>
		<EMAIL>linda@everywhere.com</EMAIL>
	</PERSON>
</PEOPLE>
接下来就是解析的过程,解析过程写在程序的注释中,请参考以下的代码:

/*
 * DOM解析XML文档的流程,基本都是按照这个流程来走的。
 */
package com.ahuier.xml.dom;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;


public class DomTest1 {

   
    public static void main(String[] args) throws Exception {
        /*
         * Step 1: 获得dom解析器工厂(工厂的作用就是用于创建具体的解析器。)
         * 获得一个文档构建的工厂,DOM解析器工厂
         * 查看JDK文档DoucmentBuilderFactory 它是protected类,所以是不能new的,只能使用它的方法 newInstance() 这种方式很像之前学的单例模式。
         */
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        
        //Step 2: 获得具体的DOM解析器
        DocumentBuilder db = dbf.newDocumentBuilder();
        
        /*
         * 查看DocumentBuilderJDK文档的多个parse()方法,
         * 选择public Document parse(File f)方法 ,当然你还可以用其他的方式,它返回的是代表整个文档的Document对象,通过这个入口我们就可以往下了
         * Step 3:解析一个XML文档,获得Document对象(根节点)
         */
        Document document = db.parse(new File("candidate.xml"));
        
        /*
         * 现在我们想要获得所有的person节点,查看JDK文档中的Document的方法
         * 查看NodeList getElementsByTagName(String tagname)
         */
        NodeList list = document.getElementsByTagName("PERSON");
       
    //    System.out.println(list.getLength()); //打印出NodeList长度,即节点的个数,PERSON有四个
        
        for(int i = 0; i < list.getLength(); i++){
            //item返回的元素是Node,现在我们要的是Element 所以要进行向下类型转换,这一点要心里很清楚。
            Element element = (Element)list.item(i);
            
            /*
             * 现在流程进入到了PERSON元素下面了,我们要获得PERSON低下的子元素NAME、ADDRESS等。
             * getNodeValue()表示获得当前节点的值
             */
            
           /* 注意如果是下面这两行程序打印出来的是4个null空的值
            * 原因是因为XML在这个地方:<NAME>Tony Blair</NAME>
            * 中间的Tony Blair的文本也是看做是一个元素了,下面我们打印的就是这个文本,它永远都是空的,所以我们必须打印出这个文本所对应的的子元素 就是Tony Blair
            * 所以我们必须用这种方式来getFirstChild()来得到它的内容。
            String content = element.getElementsByTagName("NAME").item(0).getNodeValue();
            System.out.println(content);*/
            
            String content = element.getElementsByTagName("NAME").item(0).getFirstChild().getNodeValue();
            System.out.println("name: " + content);
            
            content = element.getElementsByTagName("ADDRESS").item(0).getFirstChild().getNodeValue();
            System.out.println("address: " + content);
            
            content = element.getElementsByTagName("TEL").item(0).getFirstChild().getNodeValue();
            System.out.println("tel: " + content);
            
            content = element.getElementsByTagName("FAX").item(0).getFirstChild().getNodeValue();
            System.out.println("fax: " + content);
            
            content = element.getElementsByTagName("EMAIL").item(0).getFirstChild().getNodeValue();
            System.out.println("email: " + content);
            
            System.out.println("-------------------------------------");
        }
    }   
}

[编译执行结果]:

name: Tony Blair
address: 10 Downing Street, London, UK
tel: (061) 98765
fax: (061) 98765
email: blair@everywhere.com
-------------------------------------
name: Bill Clinton
address: White House, USA
tel: (001) 6400 98765
fax: (001) 6400 98765
email: bill@everywhere.com
-------------------------------------
name: Tom Cruise
address: 57 Jumbo Street, New York, USA
tel: (001) 4500 67859
fax: (001) 4500 67859
email: cruise@everywhere.com
-------------------------------------
name: Linda Goodman
address: 78 Crax Lane, London, UK
tel: (061) 54 56789
fax: (061) 54 56789
email: linda@everywhere.com
-------------------------------------

[说明]:上面程序中注意XML文档放的位置,以及相对路径的问题。

   DOM解析是非常重要的,工作中经常有人会问解析XML的方式有几种,它们的特点是什么?其实就是一个是DOM方式,一个SAX方式,把他们的解析的过程分析一下就行了。

另外我们之后要做一个多人聊天室的项目,最好能够利用XML的方式来传输这种方式最好的是最强壮的。而不应该用之前程序写的那种拼接字符串的形式。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值