【常用API】之XML文檔解析


【XML文檔】

數據彼此交互,本地可以使用 序列化文件。
主要針對本地化操作:應用程序,游戲。
序列化操作,必須有原始類文件。

如果數據需要提供互聯網共享,
企業與企業之間進行數據交互。
那就使用XML文檔。


XML文檔,是由 W3C 定義的一套標准規范。
所有語言,所有平台都兼容識別。
【xml文檔不受平台與語言的限制,跨平台,跨語言】


XML:可擴展的 標記 語言

xml是利用一套標記標簽進行內容(數據)的定義與描述的。
<標簽 />
<開始標簽>內容</結束標簽>

【定義與使用】:

xml文檔的定義有嚴格規定:
1、文檔必須是.xml結尾的后綴
2、文檔第一行開始部分,必須是一個聲明,
且聲明的前面不能有任何內容。
<?xml version="1.0" encoding="utf-8" ?>
3、一個xml文檔中,只能有一個最大的根元素
4、如果標簽有屬性,屬性必須小寫,且屬性的值必須有雙引號
<user id="555"></user>

 

創建XML文檔,也需要流對象

FileInputStream 基礎字節輸出流(寫)

PrintStream 打印流

.print(String) 方法,一次性寫入

 

創建XML實例:

1、首先創建一個用戶實體模型類User,用於生成XML

package com.xzm.test;

//用戶的數據實體模型類
public class User {
    
    //屬性
    private int id;
    private String name;
    private int age;
    
    //屬性封裝
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}

2、根據XML文檔定義的格式,手動生成XML文檔

package com.xzm.test;

//導入需要的包文件
import java.util.List;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;


public class 生成_XML {

    public static void main(String[] args) {
        
        //【生產數據 放入集合中】==========================
        List<User> list = new ArrayList<User>();
        
        //利用循環存入對象
        for(int i=1; i<=5; i++)
        {
            //創建User類對象
            User u = new User();
            
            //設置屬性值
            u.setId(1000+i); 
            u.setName("張三"+i);
            u.setAge( (int)Math.round( Math.random()*12+18 ) );//生成隨機年齡18-30
        
            //放入集合中
            list.add(u);
        }
        
        //顯示內存地址
        System.out.println(list);
        
        
        
        //=========================================================
        //【基於數據list,組合xml內容】
        
        //第一步:
        //    創建一個字符串操作對象,里面是保存xml組合的內容的
        //    由於是單線程應用程序
        //    在組合操作內容的時候,不會產生多余的內存對象
        StringBuilder sb = new StringBuilder();
        
        //第二步:
        //    追加:xml頭部聲明:
        //    內容中,使用轉義,保留雙引號本身
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
        
        //第三步:
        //    追加:最大根元素---開始標簽
        sb.append("<table>");        
        
        //遍歷集合,組合中間的內容
        for(User u : list)
        {
            //二級標簽---開始
            sb.append("<user>");
            
            //三級標簽: StringBuilder中,.append方法是可以連續使用的
            sb.append("<id>").append(u.getId()).append("</id>");
            sb.append("<name>").append(u.getName()).append("</name>");
            sb.append("<age>").append(u.getAge()).append("</age>");
            
            //二級標簽---結束
            sb.append("</user>");
        }        
        
        //    追加:最大根元素---結束標簽
        sb.append("</table>");
        
        
        //預覽組合數據
        System.out.println(sb);
        
        
        
        //=======================================================
        //【生成xml】
        try {
            //注意:
            //    由於操作系統是簡體中文的,默認系統生成的文件都是ANSI(gb2312),
            //    我們的內容中有特殊字符,但是文檔聲明為 utf-8
            //    如果直接寫文件,字符流是可以的,但是會容易導致:中文亂碼。
            //    【打印流:PrintStream】,直接解決編碼問題。
            
            //創建基礎字節輸出流(文件的保存格式是字節)
            //這里不需要File對象,直接指定路徑文件名
            //沒有指定物理路徑:當前項目根目錄下
            FileOutputStream fos = new FileOutputStream("table.xml");
        
            //創建 高層 內容 打印流
            //【必須使用三個參數的構造方法實例化】
            //(流對象,是否自動完成true,編碼utf-8)
            PrintStream ps = new PrintStream(fos, true, "utf-8");
        
            //調用方法打印
            ps.print(sb);
            
            //關閉
            ps.close();
            fos.close();
            
            //結果
            System.out.println("創建成功!");        
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }

    }

}

 

 

解析XMl的方式有兩種,一種SAX方式,一種DOM方式

SAX解析:
表示的是通過代碼,逐行解析,
會按照層次關系,一個個一次提取遞進。
優點:內存消耗少,每次只有一個信息
缺陷:必須按照它的順序進行逐步操作
必須實現一個類對象,且重寫方法去操作

package com.xzm.test;

import java.io.FileInputStream;

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

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

public class SAX解析_XML {
    public static void main(String[] args) {
        
        try {
            
            //SAX解析方式:
            //    打開文件,按照流的方式,一個一個節點遞進的。
            //    節約內存使用,但是會長時間鏈接文件,不能任意控制。
            
            //第一步:
            //    自定義一個類,繼承DefaultHandler類,
            //    重寫里面的方法
            //    這些方法都是自動調用的,我們只要實現里面具體的代就可以
            
            //第二步:
            //    得到一個SAX解析工廠
            SAXParserFactory sax = SAXParserFactory.newInstance();
            
            //第三步:
            //    基於工廠,得到解析對象
            SAXParser sp = sax.newSAXParser();
            
            //第四步:
            // 創建基礎輸入流
            FileInputStream fis = new FileInputStream("table.xml");
            
            //第五步:
            // 調用方法,解析文檔
            // 基於輸入流操作的,同時提供類對象
            // 讀取過程,自動調用類中重寫的方法
            sp.parse(fis, new MyHandler());
            
            //關閉
            fis.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    
}

//==============================================================
class MyHandler extends DefaultHandler
{
    
    //文檔開始
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("文檔開始");
    }

    //讀取到-開始標簽: qName:標簽名稱
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        System.out.println("<"+qName+">");
    }
    
    //標簽中的內容
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        
        //標簽中的內容,程序會按照一個個字符char,讀取出來,
        //保存到數組 ch 中,
        //會記錄開始的字符索引,同時記錄內容的長度
        //當前方法自動傳入
        //把這三個參數 直接給 String類對象
        //String類對象會自動從整個字符串文本中,提取出這一點信息
        String str = new String(ch, start, length);
        System.out.println(str);
    }
    

    //讀取到-結束標簽
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        System.out.println("</"+qName+">");
    }
    
    
    //文檔結束
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("文檔結束");
    }
}

 

DOM解析:
表示的是 Document 文檔解析,
它可以一次性把整個xml文檔的內容提取出來。
優點:用戶可以任意 遍歷、提取、操作等等。
缺陷:內存消耗過大

package com.xzm.test;

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 DOM解析_XML {

    public static void main(String[] args) {
        
        try {
            //DOM解析方式:
            //    通過Dom工廠,一次性把文檔信息讀取到內存上
            //    減少了IO操作,增加內存使用
            
            //第一步:
            // 得到一個文檔構建工廠,調用類中靜態方法得到對象的
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            
            
            //第二步:
            // 基於工廠,得到一個文檔構建對象
            DocumentBuilder db = dbf.newDocumentBuilder();
            
            
            //第三步:
            // 指定數據源文檔對象
            File f = new File("table.xml");
            
            
            //第四步:
            // 通過文檔對象調用方法,獲取數據源所有內容
            Document doc = db.parse(f);
            
            //======================================================
            //此時:doc對象中,已經得到了整個xml中的所有內容            
            //接下來,就是基於doc對象,在里面操作了
            
            //doc讀取的文檔信息中,有以下三種類型的內容:
            //    聲明:<?xml ?>
            //    元素:Element:最大的根元素:<table>
            //    節點:Node:內部的元素:table標簽中包括的所有
            
            
            //【得到最大的根元素】
            Element table = doc.getDocumentElement();
            
            //【得到這個根元素的節點名稱】
            //String name = table.getNodeName();
            //System.out.println(name);
            
            
            //【第一層:子節點】
            //在根元素中,得到第一層子節點
            //基於根對象,獲取所有的子節點
            //【注意:換行也會當作節點】
            NodeList nl = table.getChildNodes();
            //System.out.println( nl.getLength() );
            
            
            //循環遍歷每一個二級子節點
            for(int i=0; i<nl.getLength(); i++)
            {
                //從當前二級節點中,獲取第三級節點列表
                NodeList ns = nl.item(i).getChildNodes();
                
                //遍歷第三級
                for(int j=0; j<ns.getLength(); j++)
                {
                    //獲取遍歷到第三級節點的信息
                    System.out.print("節點名稱:" + ns.item(j).getNodeName());                    
                    System.out.println(",文本內容:" + ns.item(j).getTextContent());
                }                
            }
            
            
            
            
            
            
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM