java与xml学习[DOM方式解析XML文件]

xml文件被广泛应用于各种领域,例如网络数据的传输和软件配置文件的设置。例如:最近很流行的ajax技术就是基于xml、 javascript、html的技术通过发送XHR(xml http request)的机制进行实现,再如:聊天工具QQ的配置文件:

http://img.mukewang.com/54d8b7e400018ae309170715.jpg


    xml文件是一种树形的结构(称为节点树),最上层是根节点。

https://i-blog.csdnimg.cn/blog_migrate/95f696f144a14c625457e4f0f685648d.jpeg

    下面是一个简单的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文件的应用:

http://img.mukewang.com/54d8ba2d0001fc9c11260129.jpg

    订票软件和支付软件的实现机制是不一样的,但是它们需要共享用户的信息。

    不同操作系统的底层的实现机制是不同的,但是它们可以通过相同的xml文件进行通信。

    手机和网站需要通过xml文件共享网站的数据。


    需要了解更多关于xml的信息,请参见:w3school中关于xml的系列教程


【xml文件的解析】

    xml文件的读取又叫做xml文件的解析。xml文件的解析的目的是:

http://img.mukewang.com/54d8bb100001e04606300144.jpg


    在java中XML文件的解析方式通常有4种:

https://i-blog.csdnimg.cn/blog_migrate/c6b286b7a108044921fd672d62cddc6c.jpeg

在解析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添加到项目中:

https://i-blog.csdnimg.cn/blog_migrate/d1dfc692a13371a77670d287f3ec41c9.jpeg

    通过DOM方式解析XML文件需要3个步骤:

        1、创建一个DocumentBuilderFactory对象(DocumentBuilderFactory的静态方法);

        2、使用创建DocumentBuilderFactory的实例对象创建一个DocumentBuilder对象;

        3、通过DocumentBuilder对象的parse(String fileName)方法解析xml文档。


    XML DOM的节点及其返回值简表如下:

http://img.mukewang.com/54d8b92f0001386909250252.jpg


    详见:w3school的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();
    }
    }
 
}
运行结果:
http://img.mukewang.com/54d8b9210001608805390425.jpg

注意:图中为什么显示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应该是文本节点,见下图:

https://i-blog.csdnimg.cn/blog_migrate/45c6d5da6b62c07942023d91e6070881.jpeg

 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();
      }
    }
 
}

http://img.mukewang.com/54dac7d900015b2907990075.jpg



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值