1. 程式人生 > >schema約束 SAXP和DOM解析,案例 Dom4J xpath總結

schema約束 SAXP和DOM解析,案例 Dom4J xpath總結

1、schema約束
    dtd語法: <!ELEMENT 元素名稱 約束>
    ** schema符合xml的語法,xml語句
    ** 一個xml中可以有多個schema,多個schema使用名稱空間區分(類似於java包名)
    ** dtd裡面有PCDATA型別,但是在schema裡面可以支援更多的資料型別
        *** 比如 年齡 只能是整數,在schema可以直接定義一個整數型別
    *** schema語法更加複雜,schema目前不能替代dtd

2、schema的快速入門
    * 建立一個schema檔案 字尾名是 .xsd
        ** 根節點 <schema>
    ** 在schema檔案裡面
        ** 屬性  xmlns="http://www.w3.org/2001/XMLSchema"
            - 表示當前xml檔案是一個約束檔案
        ** targetNamespace="http://www.itcast.cn/20151111"
            - 使用schema約束檔案,直接通過這個地址引入約束檔案
        ** elementFormDefault="qualified"
    步驟
        (1)看xml中有多少個元素
            <element>
        (2)看簡單元素和複雜元素
            * 如果複雜元素
                <complexType>
                    <sequence>
                        子元素
                    </sequence>
            </complexType>
        (3)簡單元素,寫在複雜元素的
            <element name="person">
            <complexType>
            <sequence>
                    <element name="name" type="string"></element>
                    <element name="age" type="int"></element>
            </sequence>
            </complexType>
            </element>

        (4)在被約束檔案裡面引入約束檔案
            <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://www.itcast.cn/20151111"
            xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd">

            ** xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                -- 表示xml是一個被約束檔案
            ** xmlns="http://www.itcast.cn/20151111"
                -- 是約束文件裡面 targetNamespace
            ** xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd">
                -- targetNamespace 空格  約束文件的地址路徑
        

    * <sequence>:表示元素的出現的順序
    <all>: 元素只能出現一次
    <choice>:元素只能出現其中的一個
    maxOccurs="unbounded": 表示元素的出現的次數
    <any></any>:表示任意元素

    * 可以約束屬性
        * 寫在複雜元素裡面
        ***寫在 </complexType>之前
        --
        <attribute name="id1" type="int" use="required"></attribute>
            - name: 屬性名稱
            - type:屬性型別 int stirng
            - use:屬性是否必須出現 required

    * 複雜的schema約束
        <company xmlns = "http://www.example.org/company"
    xmlns:dept="http://www.example.org/department"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.example.org/company company.xsd http://www.example.org/department department.xsd" 
>
    * 引入多個schema檔案,可以給每個起一個別名

    <employee age="30">
        <!-- 部門名稱 --> 
        <dept:name>100</dept:name>
        * 想要引入部門的約束檔案裡面的name,使用部門的別名 detp:元素名稱
        <!-- 員工名稱 -->
        <name>王曉曉</name>   
    </employee>

3、sax解析的原理(********)
    * 解析xml有兩種技術 dom 和sax

    * 根據xml的層級結構在記憶體中分配一個樹形結構
    ** 把xml中標籤,屬性,文字封裝成物件

    * sax方式:事件驅動,邊讀邊解析
    * 在javax.xml.parsers包裡面
        ** SAXParser
            此類的例項可以從 SAXParserFactory.newSAXParser() 方法獲得
            - parse(File f, DefaultHandler dh) 
                * 兩個引數
                ** 第一個引數:xml的路徑
                ** 事件處理器

        ** SAXParserFactory
            例項 newInstance() 方法得到
    * 畫圖分析一下sax執行過程
        * 當解析到開始標籤時候,自動執行startElement方法
        * 當解析到文字時候,自動執行characters方法
        * 當解析到結束標籤時候,自動執行endElement方法

4、使用jaxp的sax方式解析xml(**會寫***)    
    * sax方式不能實現增刪改操作,只能做查詢操作
    ** 打印出整個文件
    *** 執行parse方法,第一個引數xml路徑,第二個引數是 事件處理器
        *** 建立一個類,繼承事件處理器的類,
        ***重寫裡面的三個方法
    
     * 獲取到所有的name元素的值
        ** 定義一個成員變數 flag= false
        ** 判斷開始方法是否是name元素,如果是name元素,把flag值設定成true
        ** 如果flag值是true,在characters方法裡面列印內容
        ** 當執行到結束方法時候,把flag值設定成false

     * 獲取第一個name元素的值
        ** 定義一個成員變數 idx=1
        ** 在結束方法時候,idx+1 idx++
        ** 想要打印出第一個name元素的值,
            - 在characters方法裡面判斷,
            -- 判斷flag=true 並且 idx==1,在列印內容

5、使用dom4j解析xml
    * dom4j,是一個組織,針對xml解析,提供解析器 dom4j

    * dom4j不是javase的一部分,想要使用第一步需要怎麼做?
        *** 匯入dom4j提供jar包
        -- 建立一個資料夾 lib
        -- 複製jar包到lib下面,
        -- 右鍵點選jar包,build path -- add to build path
        -- 看到jar包,變成奶瓶樣子,表示匯入成功
    
    * 得到document
         SAXReader reader = new SAXReader();
             Document document = reader.read(url);
    * document的父介面是Node
        * 如果在document裡面找不到想要的方法,到Node裡面去找

    * document裡面的方法 getRootElement() :獲取根節點 返回的是Element

    * Element也是一個介面,父介面是Node
        - Element和Node裡面方法
        ** getParent():獲取父節點
        ** addElement:新增標籤

        * element(qname)
            ** 表示獲取標籤下面的第一個子標籤
            ** qname:標籤的名稱
        * elements(qname)
            ** 獲取標籤下面是這個名稱的所有子標籤(一層)
            ** qname:標籤名稱
        * elements()
            ** 獲取標籤下面的所有一層子標籤

6、使用dom4j查詢xml    
    * 解析是從上到下解析
    * 查詢所有name元素裡面的值
        /*
            1、建立解析器
            2、得到document
            3、得到根節點  getRootElement() 返回Element

            4、得到所有的p1標籤
                * elements("p1") 返回list集合
                * 遍歷list得到每一個p1
            5、得到name
                * 在p1下面執行 element("name")方法 返回Element
            6、得到name裡面的值
                * getText方法得到值
        */
    
    * 查詢第一個name元素的值
        /*
         * 1、建立解析器
         * 2、得到document
         * 3、得到根節點
         * 
         * 4、得到第一個p1元素  
            ** element("p1")方法 返回Element
         * 5、得到p1下面的name元素
            ** element("name")方法 返回Element
         * 6、得到name元素裡面的值
            ** getText方法
         * */
    * 獲取第二個name元素的值
        /*
         * 1、建立解析器
         * 2、得到document
         * 3、得到根節點
         * 
         *  4、得到所有的p1 
            ** 返回 list集合
         *  5、遍歷得到第二個p1
            ** 使用list下標得到 get方法,集合的下標從 0 開始,想要得到第二個值,下標寫 1 
         *  6、得到第二個p1下面的name
            ** element("name")方法 返回Element
         *  7、得到name的值
            ** getText方法
         * */
        
7、使用dom4j實現新增操作
    * 在第一個p1標籤末尾新增一個元素 <sex>nv</sex>
    * 步驟
        /*
         * 1、建立解析器
         * 2、得到document
         * 3、得到根節點
         * 
         * 4、獲取到第一個p1
            * 使用element方法
         * 5、在p1下面新增元素
            * 在p1上面直接使用 addElement("標籤名稱")方法 返回一個Element

         * 6、在新增完成之後的元素下面新增文字
         *    在sex上直接使用 setText("文字內容")方法
         * 7、回寫xml
            * 格式化 OutputFormat,使用 createPrettyPrint方法,表示一個漂亮的格式
            * 使用類XMLWriter 直接new 這個類 ,傳遞兩個引數
                *** 第一個引數是xml檔案路徑 new FileOutputStream("路徑")
                *** 第二個引數是格式化類的值
         * */

8、使用dom4j實現在特定位置新增元素 
    * 在第一個p1下面的age標籤之前新增 <school>ecit.edu.cn</schlool>
    * 步驟
        /*
         * 1、建立解析器
         * 2、得到document
         * 3、得到根節點
         * 4、獲取到第一個p1
         * 
         * 5、獲取p1下面的所有的元素
         *         ** elements()方法 返回 list集合

         *      ** 使用list裡面的方法,在特定位置新增元素
         *        ** 首先建立元素 在元素下面建立文字
                    - 使用DocumentHelper類方法createElement建立標籤
                    - 把文字新增到標籤下面 使用 setText("文字內容")方法

         *          *** list集合裡面的 add(int index, E element)
         *              - 第一個引數是 位置 下標,從0開始
         *              - 第二個引數是 要新增的元素
         * 6、回寫xml
         * */

    ** 可以對得到document的操作和 回寫xml的操作,封裝成方法
    ** 也可以把傳遞的檔案路徑,封裝成一個常量
    *** 好處:可以提高開發速度,可以提交程式碼可維護性
        - 比如想要修改檔案路徑(名稱),這個時候只需要修改常量的值就可以了,其他程式碼不需要做任何改變

9、使用dom4j實現修改節點的操作
    * 修改第一個p1下面的age元素的值 <age>30</age>
    * 步驟
    /*
         * 1、得到document
         * 2、得到根節點,然後再得到第一個p1元素
         * 3、得到第一個p1下面的age
            element("")方法
         * 4、修改值是 30
         *    * 使用setText("文字內容")方法
         * 5、回寫xml
         * 
         * */

10、使用dom4j實現刪除節點的操作
    * 刪除第一個p1下面的<school>ecit</school>元素
    * 步驟
    /*
         * 1、得到document
         * 2、得到根節點
         * 3、得到第一個p1標籤
         * 4、得到第一個p1下面的school元素

         * 5、刪除(使用p1刪除school)
         *    * 得到school的父節點
                - 第一種直接得到p1
                - 使用方法 getParent方法得到
            * 刪除操作
                - 在p1上面執行remove方法刪除節點
         * 6、回寫xml
         * */

11、使用dom4j獲取屬性的操作
    * 獲取第一個p1裡面的屬性id1的值
    * 步驟
    /*
         * 1、得到document
         * 2、得到根節點
         * 3、得到第一個p1元素
         * 4、得到p1裡面的屬性值
            - p1.attributeValue("id1");
            - 在p1上面執行這個方法,裡面的引數是屬性名稱
         * */

12、使用dom4j支援xpath的操作
    * 可以直接獲取到某個元素 

    * 第一種形式
        /AAA/DDD/BBB: 表示一層一層的,AAA下面 DDD下面的BBB
    * 第二種形式
        //BBB: 表示和這個名稱相同,表示只要名稱是BBB,都得到
    * 第三種形式
        /*: 所有元素
    * 第四種形式
        ** BBB[1]: 表示第一個BBB元素
        ×× BBB[last()]:表示最後一個BBB元素
    * 第五種形式
        ** //BBB[@id]: 表示只要BBB元素上面有id屬性,都得到
    * 第六種形式
        ** //BBB[@id='b1'] 表示元素名稱是BBB,在BBB上面有id屬性,並且id的屬性值是b1

13、使用dom4j支援xpath具體操作
    ** 預設的情況下,dom4j不支援xpath
    ** 如果想要在dom4j裡面是有xpath
        * 第一步需要,引入支援xpath的jar包,使用 jaxen-1.1-beta-6.jar
        ** 需要把jar包匯入到專案中

    ** 在dom4j裡面提供了兩個方法,用來支援xpath
        *** selectNodes("xpath表示式")
            - 獲取多個節點
        *** selectSingleNode("xpath表示式")
            - 獲取一個節點

    ** 使用xpath實現:查詢xml中所有name元素的值
        ** 所有name元素的xpath表示: //name
        ** 使用selectNodes("//name");
        ** 程式碼和步驟
        /*
         * 1、得到document
         * 2、直接使用selectNodes("//name")方法得到所有的name元素
         * 
         * */
            //得到document
            Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
            //使用selectNodes("//name")方法得到所有的name元素
            List<Node> list = document.selectNodes("//name");
            //遍歷list集合
            for (Node node : list) {
                //node是每一個name元素
                //得到name元素裡面的值
                String s = node.getText();
                System.out.println(s);
            }
    
    ** 使用xpath實現:獲取第一個p1下面的name的值
        * //p1[@id1='aaaa']/name
        * 使用到 selectSingleNode("//p1[@id1='aaaa']/name")
        * 步驟和程式碼
        /*
         * 1、得到document
         * 2、直接使用selectSingleNode方法實現
         *     - xpath : //p1[@id1='aaaa']/name
         * */
        //得到document
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        //直接使用selectSingleNode方法實現
        Node name1 = document.selectSingleNode("//p1[@id1='aaaa']/name"); //name的元素
        //得到name裡面的值
        String s1 = name1.getText();
        System.out.println(s1);

14、實現簡單的學生管理系統
    ** 使用xml當做資料,儲存學生資訊

    ** 建立一個xml檔案,寫一些學生資訊

    ** 增加操作
        /*
         * 1、建立解析器
         * 2、得到document
         * 3、獲取到根節點
         * 4、在根節點上面建立stu標籤
         * 5、在stu標籤上面依次新增id name age
            ** addElement方法新增
         * 6、在id name age上面依次新增值
         *    ** setText方法
         * 7、回寫xml
         * */

    ** 刪除操作(根據id刪除)
        /*
         * 1、建立解析器
         * 2、得到document
         * 
         * 3、獲取到所有的id    
         *     使用xpath //id 返回 list集合
         * 4、遍歷list集合
         * 5、判斷集合裡面的id和傳遞的id是否相同
         * 6、如果相同,把id所在的stu刪除
         * 
         * */
        
    ** 查詢操作(根據id查詢)
        /*
         * 1、建立解析器
         * 2、得到document
         * 
         * 3、獲取到所有的id
         * 4、返回的是list集合,遍歷list集合
         * 5、得到每一個id的節點
         * 6、id節點的值
         * 7、判斷id的值和傳遞的id值是否相同
         * 8、如果相同,先獲取到id的父節點stu
         * 9、通過stu獲取到name age值

         ** 把這些值封裝到一個物件裡面 返回物件
         * 
         * */