XML 7—— DOM

  • DOM,Document Object Model(文档对象模型)
  • 对于XML应用开发来说,DOM就是一个对象化的XML数据接口,一个与语言无关、与平台无关的标准接口规范。
  • 要严格区分XML文档树中的根结点(Document)与根元素结点,根节点代表的是 XML文档本身,是我们解析XML文档的入口,而根元素结点则表示XML文档的根元素,它对应于XML文档的Root。
  • JAXP(Java API for XML Parsing),用于XML解析的Java API。

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

  • DOM的全称是Document object Model,也即文档对象模型。在应用程序中,基于DOM的ML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。
  • DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。
  • DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

对于XML应用开发来说,DOM就是一个对象化的XML数据接口,一个与语言无关、与平台无关的标准接口规范。它定义了HTML文档和XML文档的逻辑结构,给出了一种访问和处理HTML文档和XML文档的方法。利用DOM,程序开发人员可以动态地创建文档,遍历文档结构,添加、修改、删除文档内容,改变文档的显示方式等等。可以这样说,文档代表的是数据,而DOM则代表了如何去处理这些数据。无论是在浏览器里还是在浏览器外,无论是在服务器上还是在客户端,只要有用到XML的地方,就会碰到对DOM的应用。

作为W3C的标准接口规范,目前,DOM由三部分组成,包括:核心(core)、HTML和XML。核心部分是结构化文档比较底层对象的集合,这一部分所定义的对象已经完全可以表达出任何HTMT和XML文档中的数据了。HTML接口和XML接口两部分则是专为操作具体的HTML文档和XML文档所提供的高级接口,使对这两类文件的操作更加方便。

  • 例一
    • <?xml version="1.0" encoding="gb2312"?>
      <addressbook>
          <person sex ="male">
              <name>张三</name>
              <email>zhs@xml.net.cn</emai1>
          </person>
          <person sex ="male">
              <name>李四</name>
              <email>1se@xml.net.cn</email>
          </person>
      </addressbook>
  • 例二
    • <?xml version="1.0" encoding="gb2312"?>
      <books>
          <book>
              <author>至尊宝</author>
              <title>倘若时光倒流</title >
          </book>
          <book>
              <author>白晶晶</author>
              <title>月光宝盒实用大全</title>
          </book>
      </books>

DOM模型结构

  • 最常见的节点类型
    • 元素,元素是XML的基本构件。典型地,元素可以有其它元素、文本节点或两者兼有来作为其子节点。元素节点还是可以有属性的唯一类型的节点。
    • 属性,属性节点包含关于元素节点的信息,但实际上,不认为它是元素的子节点。
    • 文本,确切来讲,文本节点是文本。它可以包含许多信息或仅仅是空白。
    • 文档(根节点),文档节点是整个文档中所有其它节点的父节点。(根节点不等于根元素节点!)
  • 较不常见的节点类型
    • CDATA
    • 注释
    • 处理指令

 DOM的四个基本接口

文档对象模型利用对象来把文档模型化,这些模型不仅描述了文档的结构,还定义了模型中对象的行为。换句话说,在上面给出的例子里,图中的节点不是数据结构,而是对象,对象中包含方法和属性。

在DOM中,对象模型要实现:

  • 用来表示、操作文档的接口
  • 接口的行为和属性
  • 接口之间的关系以及互操作

在DOM接口规范中,有四个基本的接口Document,Node,NodeList以及NamedNodeMap

  • Document接口是对文档进行操作的入口,它是从Node接口继承过来的。
    • Document接口代表了整个XML/HTML文档,因此,它是整棵文档树的根,提供了对文档中的数据进行访问和操作的入口。
    • 由于元素、文本节点、注释、处理指令等都不能脱离文档的上下文关系而独立存在,所以在Document接口提供了创建其他节点对象的方法,通过该方法创建的节点对象都有一个ownerDocument属性,用来表明当前节点是由谁所创建的以及节点同Document之间的联系。
    • 在DOM树中,Document接口同其他接口之间的关系如下图所示。
  • Node接口是其他大多数接口的父类,像Document,Element,Attribute,Text,Comument等接口都是从Node接口继承过来的。
    • Node接口在整个DOM树中具有举足轻重的地位,DOM接口中有很大一部分接口是从Node接口继承过来的,例如,Element、Attr、CDATAsection等接口,都是从Node继承过来的。在DOM树中,Node接口代表了树中的一个节点。一个典型的Node接口如下图所示。
  • NodeList接口是一个节点的集合。它包含了某个节点中的所有子节点。
    • NodeList接口提供了对节点集合的抽象定义,它并不包含如何实现这个节点集的定义。NodeList用于表示有顺序关系的一组节点,比如某个节点的子节点序列。另外,它还出现在一些方法的返回值中,例如,getElementsByTagName。

    • 在DOM中,NodeList的对象是"live"的,换句话说,对文档的改变,会直接反映到相关的NodeList对象中。例如,如果通过DOM获得一个NodeList对象,该对象中包含了某个Element节点的所有子节点的集合,那么,当再通过DOM对Element节点进行操作(添加、删除、改动节点中的子节点)时,这些改变将会自动地反映到NodeList对象中,而不需DOM应用程序再做其他额外的操作。

    • NodeList中的每个item都可以通过一个索引来访问,该索引值从0开始。

  • NamedNodeMap接口也是一个节点的集合,通过该接口,可以建立节点名和节点之间的一一映射关系,从而利用节点名可以直接访问特定的节点。
    • 实现了NamedNodeMap接口的对象中包含了可以通过名字来访间的一组节点的集合。不过注意,NamedNodeMap并不是从NodeList继承过来的,它所包含的节点集中的节点是无序的。尽管这些节点也可以通过索引来进行访问,但这只是提供了枚举NamedNodeMap中所包含节点的一种简单方法,并不表明在DOM规范中为NamedNodeMap中的节点规定了一种排列顺序。

    • NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。

    • 与NodeList相同,在DOM中,NamedNodeMap对象也是"live"的。

解析器工厂

下面,我们需要把这个文档的内容解析到一个个的Java对象中去供程序使用,利用JAXP,我们只需几行代码就能做到这一点。首先,我们需要建立一个解析器工厂,以利用这个工厂来获得一个具体的解析器对象。

DocumentBuilderFactory dbf =  DocumentBuilderFactory.newfnstance();

我们在这里使用DocumentBuilderFacotry的目的是为了创建与具体解析器无关的程序,当DocumentBuilderFactory类的静态方法newInstance()被调用时,它根据一个系统变量来决定具体使用哪一个解析器。又因为所有的解析器都服从于JAXP所定义的接口,所以无论具体使用哪一个解析器,代码都是一样的。所以当在不同的解析器之间进行切换时,只需要更改系统变量的值,而不用更改任何代码。这就是工广所带来的好处。

DOM的基本对象

  • Document,Document对象代表了整个XML的文档,所有其它的Node,都以一定的顺序包含在Document对象之内,排列成一个树形的结构,程序员可以通过遍历这颗树来得到XML文档的所有的内容,这也是对XML文档操作的起点。我们总是先通过解析XML源文件而得到一个Document对象,然后再来执行后续的操作。此外,Document还包含了创建其它节点的方法,比如createAttribute()用来创建一个Attr对象。它所包含的主要的方法有
    • createAttribute( String),用给定的属性名创建一个Attr对象,并可在其后使用setAttributeNode方法来放置在某一个Element对象上面。
    • createElement(String):用给定的标签名创建一个Element对象,代表XML文档中的一个标签,然后就可以在这个Element对象上添加属性或进行其它的操作。
    • createTextNode(String),用给定的字符串创建一个Text对象,Text对象代表了标签或者属性中所包含的纯文本字符串。如果在个标然内没有其它的标签,那么标签内的文本所代表的Text对象是这个Element对象的唯一子对象。
    • getElementsByTagName(String),返回一个NodeList对象,它包含了所有给定标签名字的标签。
    • getDocumentElement(),返回一个代表这个DOM树的根元素节点的Element对象,也就是代表XML文档根元素的那个对象。
  • Node,Node对象是DOM结构中最为基本的对象,代表了文档树中的一个抽象的节点。在实际使用的时候,很少会真正的用到Node这个对象,而是用到诸如Element、Attr、Text等Node对象的子对象来操作文档。Node对象为这些对象提供了一个抽象的、公共的根。虽然在Node对象中定义了对其子节点进行存取的方法,但是有一些Node子对象,比如Text对象,它并不存在子节点,这一点是要注意的。Node对象所包含的主要的方法有
    • appendChild(org.w3c.dom.Node),为这个节点添加一个子节点,并放在所有子节点的最后,如果这个子节点已经存在,则先把它删掉再添加进去。
    • getFirstChild(),如果节点存在子节点,则返回第一个子节点,对等的,还有getLastChild()方法返回最后一个子节点。
    • gstNextSibling(),返回在DOM树中这个节点的下一个兄弟节点,对等的,还有getPreviousSibling()方法返回其前一个兄弟节点。
    • getNodeName(),根据节点的类型返回节点的名称。
    • getNodeType(),返回节点的类型。
  • NodeList
  • Element
  • Attr
    • Attr对象代表了某个标签中的属性。Attr继承于Node,但是因为Attr实际上是包含在Element中的,它并不能被看作是Element的子对象,因而在DOM中Attr并不是DOM树的一部分,所以Node中的getparentNode(),getpreviousSibling()和getnextSibling()返回的都将是null。也就是说,Attr其实是被看作包含它的Element对象的一部分,它并不作为DOM树中单独的一个节点出现。这一点在使用的时候要同其它的Node子对象相区别

 具体例子

Domtest.xml

<?xml version="1.0" encoding="UTF-8"?>
<PEOPLE>
    <PERSON PERSONID="EO1">
        <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>
</PEOPLE>    

domtest.java

package DOMTEST;

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 domtest {
    public static void main(String[] args) {
        // step 1 :获得dom解析器工厂(工作的作用是用于创建具体的解析器)
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        System.out.println("class name: " + dbf.getClass().getName());

        // step 2 :获得具体的dom解析器
        DocumentBuilder db = null;
        
        // step 3 :解析一个XML文档,获得Document对象(根结点)
        Document document = null;

        try {
            db = dbf.newDocumentBuilder();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            document = db.parse(new File("DomTest.xml"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        NodeList list = document.getElementsByTagName("PERSON");
        System.out.println("class name: " + db.getClass().getName());
        System.out.println("class name: " + document.getClass().getName());
        System.out.println(list.getLength());

        for (int i = 0; i < list.getLength(); i++) {
            Element element = (Element) list.item(i);
            String content = element.getElementsByTagName("NAME").item(0).getFirstChild().getNodeValue();
            System.out.println("NAME " + i + ": " + content);

            content = element.getElementsByTagName("ADDRESS").item(0).getFirstChild().getNodeValue();
            System.out.println("ADDRESS " + i + ": " + content);

            content = element.getElementsByTagName("TEL").item(0).getFirstChild().getNodeValue();
            System.out.println("TEL " + i + ": " + content);

            content = element.getElementsByTagName("FAX").item(0).getFirstChild().getNodeValue();
            System.out.println("FAX " + i + ": " + content);

            content = element.getElementsByTagName("EMAIL").item(0).getFirstChild().getNodeValue();
            System.out.println("EMAIL " + i + ": " + content);
        }
    }
}

 domtest2.java

package DOMTEST;

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.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class domtest2 {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = null;
        Document document = null;
        db = dbf.newDocumentBuilder();
        document = db.parse(new File("DomTest.xml"));

        // 获得文档的根元素结点
        Element root = document.getDocumentElement();
        System.out.println(root.getTagName());

        NodeList list = root.getChildNodes();
        System.out.println(list.getLength());

        for (int i = 0; i < list.getLength(); i++) {
            System.out.println(list.item(i).getNodeName());
        }
        System.out.println("-------------------------");

        for (int i = 0; i < list.getLength(); i++) {
            Node n = list.item(i);
            System.out.println(n.getNodeType() + " : " + n.getNodeValue());
        }
        System.out.println("-------------------------");

        for (int i = 0; i < list.getLength(); i++) {
            Node n = list.item(i);
            System.out.println(n.getTextContent());
        }
        System.out.println("-------------------------");

        for (int i = 0; i < list.getLength(); i++) {
            Node n = list.item(i);
            System.out.println(n.getTextContent());
        }
        System.out.println("-------------------------");

        // 获得属性值
        NodeList nodelist = document.getElementsByTagName("PERSON");
        System.out.println(nodelist.getLength());
        for (int i = 0; i < nodelist.getLength(); i++) {
            NamedNodeMap nnm = nodelist.item(i).getAttributes();
            String attrName = nnm.item(0).getNodeName();
            String attrValue = nnm.item(0).getNodeValue();
            System.out.println(attrName + " = " + attrValue);
        }
        System.out.println("-------------------------");
    }
}

domtest3.java 

package DOMTEST;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.events.Comment;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/*
 * 使用递归解析给定的任意一个的XML文档并且将其内容输出到命令行
 * */
public class domtest3 {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(new File("DomTest2.xml"));

        // 获得根元素结点
        Element root = document.getDocumentElement();
        parseElement(root);
    }

    private static void parseElement(Element element) {
        String tagName = element.getNodeName();
        NodeList children = element.getChildNodes();
        System.out.print("<" + tagName);

        // element元素所有属性所构成的NamedNodeMap对象,需要对其进行判断
        NamedNodeMap map = element.getAttributes();

        // 如果该元素存在属性
        if (map != null) {
            for (int i = 0; i < map.getLength(); i++) {
                // 获得该元素的每一个属性
                Attr attr = (Attr) map.item(i);
                String attrName = attr.getName();
                String attrValue = attr.getValue();
                System.out.print(" " + attrName + "=\"" + attrValue + "\"");
            }
        }
        System.out.print(">");
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            // 获得结点的类型
            short nodeType = node.getNodeType();
            if (nodeType == Node.ELEMENT_NODE) {
                // 是元素,继续递归
                parseElement((Element) node);
            } else if (nodeType == Node.TEXT_NODE) {
                // 递归出口
                System.out.print(node.getNodeValue());
            } else if(nodeType == Node.COMMENT_NODE) {
                System.out.print("<!-- ");
                // 注释内容
                String data = node.getNodeValue();
                System.out.print(data);
                System.out.print(" -->");
            }
        }
        System.out.print("</" + tagName +">");
    }
}

 

posted @ 2021-01-27 22:45  我等着你  阅读(114)  评论(0编辑  收藏  举报