1. 程式人生 > >2 XML 以及XML解析

2 XML 以及XML解析

instance 一個 修改 字符 pretty 沒有 tom 元素 描述

一、XML


1.XML:傳輸數據和保存數據
      特點:有且只有一個根元素,xml結構為樹形結構

2.XML文檔結構分析(一切皆節點)
     接口Node  
          子接口 
             Document :描述所有的xml文件
               Element  :描述所有的元素
               Text     :描述xml所有的文本內容(換行也是文本內容)
               Attr     :描述xml所有屬性
3.xml的CDATA
       用CDATA括起來的內容不會被xml文件解析,而是當成字符串使用。
        <![CDATA[
          中間的內容就是字符串<br>
    ]]>

二、XML解析

1.DOM解析(解析小型文件)

一次性將整個XML文件加載到內存中,形成一顆DOM樹對象,操作xml,
實際上就是操作(增刪改查)DOM對象即可, 操作完畢以後,要執行同步操作

     ①獲取Document文檔對象:
          1.創建DocumentBuilderFactory對象
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
          2.創建DocumentBuilder對象
         DocumentBulider builder=factory.newDocumentBuilder();
          3.創建Document對象
                Document doc=builder.parse(f);
            Document doc=builder.newDocument();

       ②常用API
           Node接口: 
            getTextContent():獲取文本內容
        setTextContent():設置文本內容
        appendChild(Node newChild):添加子元素
                removeChild(Node oldChild):刪除子元素

           Document接口:
                getDocumentElement():獲取根元素
        getElementsByTagName(""):根據指定的標簽名獲取所有子元素
        createElement(""):創建元素

           Element接口:(可以設置文本內容)
                getElementByTagName(""):獲取所有子元素
        setAttribute("","");設置屬性和屬性值
        getAttribute(""):獲取屬性值

      ③修改後,要執行同步操作:
         同步操作核心類:Transformer
      Transformer trans=TransformerFactory.newInstance().newTransformer();
       執行同步方法:
           trans.transform(Source xmlSource,Result outputTarget);
         xmlSource使用DOMSource
         outputTarget使用StreamResult
           trans.transform(new DOMSource(doc),new StreamResult(new File(filePath)));
public void testGet() throws Exception {

        // 步驟
        // 1, 創建Document文檔對象
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(filePath));
        // 2,獲取根元素 <contacts>
        Element root = doc.getDocumentElement();
        System.out.println(root);
        // 3,獲取第二個聯系人<linkman id="2">
        NodeList linkmans = root.getElementsByTagName("linkman");
        Element linkmanEL = (Element)linkmans.item(0);
        // 4,獲取第二個聯系人的<name>元素
        Node nameEL = linkmanEL.getElementsByTagName("name").item(0);
        // 5, 獲取<name>元素的文本內容
        String name = nameEL.getTextContent();
        System.out.println(name);
        //6, 修改<name>的文本內容
        nameEL.setTextContent("[email protected]");
        //7, 創建聯系人元素 <linkman>
        Element linkmanEL = doc.createElement("linkman");
//      8,創建聯系人的子元素 <name><email><address><group>
        Element nameEL = doc.createElement("name");
        Element emailEL = doc.createElement("email");

//      9, 設置子元素對應的文本內容
        nameEL.setTextContent("虛竹");
        emailEL.setTextContent("[email protected]");

//      10,將子元素添加到<linkman>
        linkmanEL.appendChild(nameEL);
        linkmanEL.appendChild(emailEL);

//      11,將<linkman>元素添加到根元素<contacts>中
        root.appendChild(linkmanEL);
//      12, 同步操作
        TransformerFactory factory = TransformerFactory.newInstance(); 
        Transformer trans = factory.newTransformer();
        //同步數據的數據來源
        Source xmlSource = new DOMSource(doc);
        //同步數據的目標
        Result outputTarget = new StreamResult(new File(filePath));
        trans.transform(xmlSource, outputTarget);
    }

1.2 使用dom4j框架解析xml文件

             //需求:獲取第一個聯系人的名稱
@Test
public void testGetName() throws Exception {
    //1,獲取Document對象
    SAXReader reader = new SAXReader();
    String filePath = "C:/Users/YL/workspace/j1704/day05-xml-parse/contacts.xml";
    Document doc = reader.read(new File(filePath));
    //2. 獲取根元素
    Element root = doc.getRootElement();
    //3,獲取第一個聯系人 <linkman id="1">
    List linkmans = root.elements("linkman");
    Element linkmanEL = (Element)linkmans.get(0);
    //4,獲取<name>元素
    Element nameEL = linkmanEL.element("name");
String name = nameEL.getText();
    String name = linkmanEL.elementText("name");
    //5.獲取第一聯系人的id屬性
    Attribute attr = linkmanEL.attribute("id");
    System.out.println(attr.getName()+" ---- "+attr.getValue());
    System.out.println(name);
}

             //添加一個 聯系人
             @Test
public void testAdd() throws Exception {
    String filePath = "C:/Users/YL/workspace/j1704/day05-xml-parse/contacts.xml";
    //1,獲取Document文檔和根元素
    SAXReader reader = new SAXReader();
    Document doc = reader.read(new File(filePath));
    Element root = doc.getRootElement();
    //2,創建一個linkman聯系人
    Element linkmanEL = root.addElement("linkman").addAttribute("id", "4");
    //3. 創建linkman聯系人的子元素
    linkmanEL.addElement("name").addText("王姑娘");
    linkmanEL.addElement("email").addText("[email protected]");
    linkmanEL.addElement("addres").addText("河南");
    linkmanEL.addElement("group").addText("少林");
    //4. 同步操作(將修改的數據同步到磁盤)
    //----------------普通的同步方法,同步到磁盤沒有格式-------------------
    // 1)創建FiewWrite對象
    //FileWriter writer = new FileWriter(filePath);
    //2) 創建 XMLWrite 對象,用於同步Document文檔
     //XMLWriter xmlWriter = new XMLWriter(writer);
     //3)同步數據
     //xmlWriter.write(doc);
     //3)關閉流:一定要關閉
     //xmlWriter.close();
    //--------------漂亮的同步方法:有格式------------------
    //1) 創建格式化對象
     OutputFormat format = OutputFormat.createPrettyPrint();
     //2)創建FiewWrite對象
     FileWriter writer = new FileWriter(filePath);
     //3)創建 XMLWrite 對象,用於同步Document文檔
     XMLWriter xmlWriter = new XMLWriter(System.out, format);
     //4)同步數據
     xmlWriter.write(doc);
     //5)關閉流:一定要關閉
     xmlWriter.close();
}

2.SAX解析

SAX(simple API for XML):是一種XML解析的替代方法。相比於DOM,SAX是一種速度更快,更有效的方法。它逐行掃描文檔,一邊掃描一邊解析。而且相比於DOM,SAX可以在解析文檔的任意時刻停止解析,但任何事物都有其相反的一面,對於SAX來說就是操作復雜。
  SAX是事件驅動型XML解析的一個標準接口不會改變 SAX的工作原理簡單地說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結束、元素(element)開始與結束、文檔(document)結束等地方時通知事件處理函數,由事件處理函數做相應動作,然後繼續同樣的掃描,直至文檔結束。

大多數SAX都會產生以下類型的事件:
1.在文檔的開始和結束時觸發文檔處理事件。
2.在文檔內每一XML元素接受解析的前後觸發元素事件。
3.任何元數據通常由單獨的事件處理
4.在處理文檔的DTD或Schema時產生DTD或Schema事件。
5.產生錯誤事件用來通知主機應用程序解析錯誤。
需求:解析contacts.xml文件,將所有的linkman聯系人封裝到LinkMan對象中並且添加到list和中

SAX解析的核心類 : SAXParser

如何獲取SAXParser 對象?

1, 創建 SAXParserFactory 對象
 SAXParserFactory factory = SAXParserFactory.newInstance();
2, 創建 SAXParser對象
 SAXParser  parser = factory.newSAXParser();
3, 進行SAX解析
 parser.parse(File f, DefaultHandler hb) 
f : 需要解析 xml文件
 hb : 解析器,真正幹活解析的代碼全在 DefaultHandler 中
public class SAXParseTest {
    String filePath = "C:/Users/YL/workspace/j1704/day05-xml-parse/contacts.xml";
    //需求:解析contacts.xml文件,將所有的linkman聯系人封裝到LinkMan對象中並且添加到list和中
    @Test
    public void testParse() throws Exception {
//      1, 創建 SAXParserFactory 對象
        SAXParserFactory factory = SAXParserFactory.newInstance();
//      2, 創建 SAXParser對象
        SAXParser parser = factory.newSAXParser();
//      3, 進行SAX解析
        //創建處理器對象
        CustomeHanlder dh  = new CustomeHanlder();
        parser.parse(new File(filePath), dh);
        //獲取處理器解析的list集合
        List<LinkMan> list = dh.getList();
        for (LinkMan linkMan : list) {
            System.out.println("解析結果:"+linkMan);
        }
    }
public class CustomeHanlder extends DefaultHandler {
    // 創建list集合,存放聯系人對象
    @Getter
    private List<LinkMan> list = new ArrayList<>();
    //聯系人對象
    private LinkMan linkman;

    //保存上一次元素名稱
    private String preTag;

    // 元素開始時候調用
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 判斷元素名稱是linkman時創建對象
        if ("linkman".equals(qName)) {
            linkman = new LinkMan();
            // 獲取id屬性
            String id = attributes.getValue("id");
            linkman.setId(Integer.valueOf(id));
        }
        //將qName 賦值給 成員變量 preTage ,在解析文本的時候就能獲取上一次的元素名稱
        preTag = qName;
    }
    // 解析文本內容調用
    public void characters(char[] ch, int start, int length) throws SAXException {
        String value = new String(ch,start,length);

        //排除所有為空的文本,換行等等
        if(value!=null){
            if("name".equals(preTag)){
                linkman.setName(value);
            }else if("email".equals(preTag)){
                linkman.setEmail(value);
            }else if("address".equals(preTag)){
                linkman.setAddress(value);
            }else if("group".equals(preTag)){
                linkman.setGroup(value);
                //此時linkman對象所有的數據都封裝完畢可以添加list中去了
                list.add(linkman);
            }
        }
    }
    // 元素結束時候調用
    public void endElement(String uri, String localName, String qName) throws SAXException {
        preTag = null;
    }

    // 文檔開始時候調用
    public void startDocument() throws SAXException {

    }

    // 文檔結束時候調用
    public void endDocument() throws SAXException {
    }
}

2 XML 以及XML解析