XML解析-DOM解析

在做解析之前,我们先构建一个xml,以后相关的解析都针对这个xml进行操作。

<?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>

原理

DOM的全称是Document Object Model,也即文档对象模型。
xml解析器一次性把整个xml文档加载进内存,然后在内存中构建一颗Document的对象树,通过Document对象,得到树上的节点对象,通过节点对象访问(操作)到xml文档的内容。
Document对象代表了一个完整的xml文档,通过Document对象,可以得到其下面的其他节点对象,通过各个节点对象来访问xml文档的内容。
其中主要包括:标签节点,属性节点,文本节点和注释节点;并且各类节点也被封装成对应的对象,通过操作不同的对象来访问xml的内容。

优缺点

优点:
  1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。
  2、解析过程中,树结构保存在内存中,方便修改。
缺点:
  1、由于文件是一次性读取,所以对内存的耗费比较大。
  2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

解析过程

  1. 建立一个解析器工厂

    //创建一个DocumentBuilderFactory的对象
    //DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    

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

  2. 获得一个DocumentBuilder对象

    //调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象
    DocumentBuilder db = dbf.newDocumentBuilder();
    

    newDocumentBuilder()是一个抽象方法,通过它可以获得一个DocumentBuilder解析器对象,我们就可以利用这个解析器来对XML文档进行解析。

  3. 获取Document对象

                Document document = db.parse("books.xml");
                Document document = db.parse(new File("books.xml"));
    

    DocumentBuilder的parse()方法接受一个XML文档名作为输入参数,返回一个Document对象,这个Document对象就 代表了一个XML文档的树模型。以后所有的对XML文档的操作,都与解析器无关,直接在这个Document对象上进行操作就可以。
    这个方法进行了重载,可以接受不同的参数,返回Document对象。

        public Document parse(InputStream is)
            throws SAXException, IOException {
            if (is == null) {
                throw new IllegalArgumentException("InputStream cannot be null");
            }
            InputSource in = new InputSource(is);
            return parse(in);
        }
        
        public Document parse(InputStream is, String systemId)
            throws SAXException, IOException {
            if (is == null) {
                throw new IllegalArgumentException("InputStream cannot be null");
            }
            InputSource in = new InputSource(is);
            in.setSystemId(systemId);
            return parse(in);
        }
        
        public Document parse(String uri)
            throws SAXException, IOException {
            if (uri == null) {
                throw new IllegalArgumentException("URI cannot be null");
            }
            InputSource in = new InputSource(uri);
            return parse(in);
        }
    
        public Document parse(File f) throws SAXException, IOException {
            if (f == null) {
                throw new IllegalArgumentException("File cannot be null");
            }
            InputSource in = new InputSource(f.toURI().toASCIIString());
            return parse(in);
        }
    
        public abstract Document parse(InputSource is)
            throws SAXException, IOException;
    
  4. Dom操作
    因为xml以读取居多,很少涉及到dom更改和新增,所以这里不进行这部分操作了,有兴趣自己去百度就行。

       public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
            //创建一个DocumentBuilderFactory的对象
            //DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            //调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象
            DocumentBuilder db = dbf.newDocumentBuilder();
            //通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下
            Document document = db.parse("C:\\Users\\Administrator\\Desktop\\books.xml");
            //去掉XML文档中作为格式化内容的空白而映射在DOM树中 的不必要的Text Node对象
        	document.normalize();
        	
            //获取根节点的元素对象
            Element root = document.getDocumentElement();
            listNodes(root);
    
            //获取所有book节点的集合
            NodeList nodeList = document.getElementsByTagName("book");
            for (int i = 0; i < nodeList.getLength(); i++) {
                //通过 item(i)方法 获取一个节点,nodelist的索引值从0开始
                Node node = nodeList.item(i);
                listNodes(node);
            }
    	}
         /**
         * 遍历指定节点
         * @param node
         */
         public static void listNodes(Node node) {
            // 节点是什么类型的节点
            if (node.getNodeType() == Node.ELEMENT_NODE) {// 判断是否是元素节点
                Element element = (Element) node;
    
                System.out.println("name:" + element.getNodeName() + "  value:"
                        + element.getNodeValue() + "  type:" + element.getNodeType() + " text:"+element.getTextContent());
                //判断此元素节点是否有属性
                if(element.hasAttributes()){
                    //获取属性节点的集合
                    NamedNodeMap namenm = 	element.getAttributes();//Node
                    //遍历属性节点的集合
                    for(int k=0;k<namenm.getLength();k++){
                        //获取具体的某个属性节点
                        Attr attr = (Attr) namenm.item(k);
                        System.out.println("attrName:"+attr.getNodeName()+" attrValue:"
                                +attr.getNodeValue()+" attrType:"+attr.getNodeType());
                    }
                }
                //获取元素节点的所有孩子节点
                NodeList listnode = element.getChildNodes();
                //遍历
                for (int j = 0; j < listnode.getLength(); j++) {
                    //得到某个具体的节点对象
                    Node nd = listnode.item(j);
                    //重新调用遍历节点的操作的方法
                    listNodes(nd);
                }
    
            }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值