读写xml

解析xml的两种方式

Dom

Dom解析会将整个xml文件加载到内存中,然后再逐个解析

package com.study.domtest;

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();
        //2、创建一个DocumentBuilder的对象
        try {
            //创建DocumentBuilder对象
            DocumentBuilder db = dbf.newDocumentBuilder();
            //3、通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下
            /*注意导入Document对象时,要导入org.w3c.dom.Document包下的*/
            Document document = db.parse("books.xml");//传入文件名可以是相对路径也可以是绝对路径
            //获取所有book节点的集合
            NodeList bookList = document.getElementsByTagName("book");
            //通过nodelist的getLength()方法可以获取bookList的长度
            System.out.println("一共有" + bookList.getLength() + "本书");
            //遍历每一个book节点
            for (int i = 0; i < bookList.getLength(); i++) {
                System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容=================");
        //❤未知节点属性的个数和属性名时:
                //通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始
                Node book = bookList.item(i);
                //获取book节点的所有属性集合
                NamedNodeMap attrs = book.getAttributes();
                System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性");
                //遍历book的属性
                for (int j = 0; j < attrs.getLength(); j++) {
                    //通过item(index)方法获取book节点的某一个属性
                    Node attr = attrs.item(j);
                    //获取属性名
                    System.out.print("属性名:" + attr.getNodeName());
                    //获取属性值
                    System.out.println("--属性值" + attr.getNodeValue());
                }
          //❤已知book节点有且只有1个id属性:
             /* 
              //前提:已经知道book节点有且只能有1个id属性
              //将book节点进行强制类型转换,转换成Element类型
              Element book1 = (Element) bookList.item(i);
              //通过getAttribute("id")方法获取属性值
              String attrValue = book1.getAttribute("id");
              System.out.println("id属性的属性值为" + attrValue);
              */
                
             //解析book节点的子节点
                NodeList childNodes = book.getChildNodes();
              //遍历childNodes获取每个节点的节点名和节点值
                System.out.println("第" + (i+1) + "本书共有" + childNodes.getLength() + "个子节点");
                for (int k = 0; k < childNodes.getLength(); k++) {
                  //区分出text类型的node以及element类型的node
                    if(childNodes.item(k).getNodeType() == Node.ELEMENT_NODE){
                      //获取了element类型节点的节点名
                        System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName());
                      //获取了element类型节点的节点值
                        System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue());
//                        System.out.println("--节点值是:" + childNodes.item(k).getTextContent());
                    }
                }
                System.out.println("======================结束遍历第" + (i + 1) + "本书的内容=================");
            }

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

在处理DOM的时候,我们需要读入整个的XML文档,然后在内存中创建DOM树,生成DOM树上的每个NODE对象。当文档比较小的时候,这不会造成什么问题,但是一旦文档大起来,处理DOM就会变得相当费时费力

SAX

SAX是SIMPLE API FOR XML的缩写,与DOM比较而言,SAX是一种轻量型的方法采用逐行解析的解析方式

SAX在概念上与DOM完全不同。首先,不同于DOM的文档驱动,它是事件驱动的,也就是说,它并不需要读入整个文档,而文档的读入过程也就是SAX的解析过程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方法。在XMLReader接受XML文档,在读入XML文档的过程中就进行解析,也就是说读入文档的过程和解析的过程是同时进行的,这和DOM区别很大

1201668-20170820124748115-753267123.png

Book实体类

package com.study.saxtest.entity;

/**
 * 用Book实体类代表XML文件中的"<book>...</book>"中整个元素
 * 在遇到<book>标签,证明我们要存储新的book时需要创建Book对象
 */
public class Book {
    private String id;
    private String name;
    private String author;
    private String year;
    private String price;
    private String language;
    public String getId() {
     return id;
    }
    public void setId(String id) {
     this.id = id;
    }
    public String getName() {
     return name;
    }
    public void setName(String name) {
     this.name = name;
    }
    public String getAuthor() {
     return author;
    }
    public void setAuthor(String author) {
     this.author = author;
    }
    public String getYear() {
     return year;
    }
    public void setYear(String year) {
     this.year = year;
    }
    public String getPrice() {
     return price;
    }
    public void setPrice(String price) {
     this.price = price;
    }
    public String getLanguage() {
     return language;
    }
    public void setLanguage(String language) {
     this.language = language;
    }
}

SAXParserHandler类

package com.study.saxtest.handler;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.study.saxtest.entity.Book;

public class SAXParserHandler extends DefaultHandler{
    /*注意DefaultHandler是org.xml.sax.helpers包下的*/
    
    int bookIndex = 0;//设置全局变量,用来记录是第几本书
    
    String value = null;
    Book book = null;
    private ArrayList<Book> bookList = new ArrayList<Book>();//保存book对象

    public ArrayList<Book> getBookList() {
        return bookList;
    }

    /**
     * 用来标识解析开始
     */
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("SAX解析开始");

    }
    
    /**
     * 用来标识解析结束
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("SAX解析结束");
    }
    
    /**
     * 用来遍历xml文件的开始标签
     * 解析xml元素
     */
    @Override
    public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
        //调用DefaultHandler类的startElement方法
        super.startElement(uri, localName, qName, attributes);
        if (qName.equals("book")) {
            bookIndex++;
            //创建一个book对象
            /*Book*/ book = new Book();
            //开始解析book元素的属性
            System.out.println("======================开始遍历第"+bookIndex+"本书的内容=================");
           /* //❤已知节点的属性名时:比如已知id属性,根据属性名称获取属性值
            String value = attributes.getValue("id");
            System.out.print("book的属性值是:"+value);*/
          //❤未知节点的属性名时,获取属性名和属性值
            int num=attributes.getLength();
            for(int i=0;i<num;i++){
                System.out.print("book元素的第"+(i+1)+"个属性名是:"+attributes.getQName(i));
                System.out.println("---属性值是:"+attributes.getValue(i));
                if (attributes.getQName(i).equals("id")) {//往book对象中塞值
                    book.setId(attributes.getValue(i));
                }
            }
        }else if (!qName.equals("book") && !qName.equals("bookstore")) {
            System.out.print("节点名是:" + qName + "---");//此时qName获取的是节点名(标签)
        }
    }
    
    /**
     * 用来遍历xml文件的结束标签
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //调用DefaultHandler类的endElement方法
        super.endElement(uri, localName, qName);
        //判断是否针对一本书已经遍历结束
        if (qName.equals("book")) {
            bookList.add(book);//在清空book对象之前先保存
            book = null;//把book清空,方便解析下一个book节点
            System.out.println("======================结束遍历第"+bookIndex+"本书的内容=================");
        }else if (qName.equals("name")) {
            book.setName(value);
        }
        else if (qName.equals("author")) {
         book.setAuthor(value);
        }
        else if (qName.equals("year")) {
         book.setYear(value);
        }
        else if (qName.equals("price")) {
         book.setPrice(value);
        }
        else if (qName.equals("language")) {
         book.setLanguage(value);
        }
    }
    
    /**
     * 获取文本
     * 重写charaters()方法时,
     * String(byte[] bytes,int offset,int length)的构造方法进行数组的传递
     * 去除解析时多余空格
     */
    @Override
    public void characters(char[] ch, int start, int length)throws SAXException {
        /**
         * ch 代表节点中的所有内容,即每次遇到一个标签调用characters方法时,数组ch实际都是整个XML文档的内容
         * 如何每次去调用characters方法时我们都可以获取不同的节点属性?这时就必须结合start(开始节点)和length(长度)
         */
        super.characters(ch, start, length);
        /*String */value = new String(ch, start, length);//value获取的是文本(开始和结束标签之间的文本)
//        System.out.println(value);//输出时会多出两个空格,是因为xml文件中空格与换行字符被看成为一个文本节点
        if(!value.trim().equals("")){//如果value去掉空格后不是空字符串
            System.out.println("节点值是:" + value);
        }
    }
    
    /**
     * qName获取的是节点名(标签)
     * value获取的是文本(开始和结束标签之间的文本)
     * 思考:qName和value分别在两个方法中,如何将这两个方法中的参数整合到一起?
     * 分析:要在两个方法中用同一个变量,就设置成全局变量,可以赋初值为null。
     *     可以把characters()方法中的value作成一个全局变量
     * 
     * 然后在endElement()方法中对book对象进行塞值。记得要把Book对象设置为全局变量,变量共享
     */
}

测试类:SAXTest

package com.study.saxtest.test;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import com.study.saxtest.entity.Book;
import com.study.saxtest.handler.SAXParserHandler;

/**
 * sax方式解析XML
 */
public class SAXTest {

    public static void main(String[] args) {
        //1.获取一个SAXParserFactory的实例对象
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //2.通过factory的newSAXParser()方法获取一个SAXParser类的对象。
        try {
            SAXParser parser = factory.newSAXParser();
            //创建SAXParserHandler对象
            SAXParserHandler handler = new SAXParserHandler();
            parser.parse("books.xml", handler);
            System.out.println("~~~~~共有"+handler.getBookList().size()+"本书");
            for (Book book : handler.getBookList()) {
                System.out.println(book.getId());
                System.out.println(book.getName());
                System.out.println(book.getAuthor());
                System.out.println(book.getYear());
                System.out.println(book.getPrice());
                System.out.println(book.getLanguage());
                System.out.println("----finish----");
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

运行结果:

SAX解析开始
======================开始遍历第1本书的内容=================
book元素的第1个属性名是:id---属性值是:1
节点名是:name---节点值是:冰与火之歌
节点名是:author---节点值是:乔治马丁
节点名是:year---节点值是:2014
节点名是:price---节点值是:89
======================结束遍历第1本书的内容=================
======================开始遍历第2本书的内容=================
book元素的第1个属性名是:id---属性值是:2
节点名是:name---节点值是:安徒生童话
节点名是:year---节点值是:2004
节点名是:price---节点值是:77
节点名是:language---节点值是:English
======================结束遍历第2本书的内容=================
SAX解析结束
​~~~~~共有2本书
冰与火之歌
乔治马丁
89
null
----finish----
安徒生童话
null
77
English
----finish----

比起SAX读取XML来,SAX写XML要相对复杂一些

SAX写

实现思路:

1.创建保存xml的结果流对象StreamResult;

2.然后利用SAXTransformerFactory这个工厂创建TransformerHandler这个操作者;

3.操作这个TransformerHandler获取Transformer,利用Transformer创建节点信息;

具体代码如下:

public void buildXml01(){  
    try {  
        //创建保存xml的结果流对象  
        Result reultXml = new StreamResult(new FileOutputStream(new File("c:\\user.xml")));  
        //获取sax生产工厂对象实例  
        SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();  
        //获取sax生产处理者对象实例  
        TransformerHandler transformerHandle = saxTransformerFactory.newTransformerHandler();  
        transformerHandle.setResult(reultXml);  
        //获取sax生产器  
        Transformer transformer = transformerHandle.getTransformer();  
        //transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");//xml的编码格式  
        transformer.setOutputProperty(OutputKeys.INDENT,"yes");//换行  
        //开始封装document文档对象,这里和解析一样都是成双成对的构造标签  
        transformerHandle.startDocument();  
        AttributesImpl attrImple = new AttributesImpl();  
        transformerHandle.startElement("", "", "Users",attrImple);  
          
        attrImple.addAttribute("", "", "id", "string", "123");  
        transformerHandle.startElement("", "", "user", attrImple);  
        transformerHandle.characters("这个是用户的信息".toCharArray(), 0, "这个是用户的信息".length());  
        transformerHandle.endElement("", "", "user");  
          
        transformerHandle.endElement("", "", "Users");  
        //因为没有appendChild等等添加子元素的方法,sax提供的是构造在startElement()和endElement()区间内的标签为包含的节点的父节点  
        transformerHandle.endDocument();  
          
        System.out.println("xml文档生成成功!");  
          
    } catch (FileNotFoundException e) {  
        e.printStackTrace();  
    } catch (TransformerConfigurationException e) {  
        e.printStackTrace();  
    } catch (SAXException e) {  
        e.printStackTrace();  
    }  
}  

转载于:https://www.cnblogs.com/AngeLeyes/p/7399626.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值