zoukankan      html  css  js  c++  java
  • 读写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区别很大

    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();  
        }  
    }  
    
  • 相关阅读:
    关于mysql无法添加中文数据的问题以及解决方案
    如何在Eclipse中使用tomcat9 运行servlet开发简单的动态网页?
    Eclipse新建Servlet时候,不会自动生成mapping到web.xml,而是在代码中加入注解@WebServlet
    win10 Tomcat9.x控制台乱码问题解决
    命令行键入命令时,几个比较常用的快捷键
    Mesh Filter & Mesh Render
    Java路径
    Java复制数组的四种方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRange()方法
    static class 静态类(Java)
    Java将文件转为字节数组
  • 原文地址:https://www.cnblogs.com/AngeLeyes/p/7399626.html
Copyright © 2011-2022 走看看