一、XML解析-WEB服務(wù)器簡單實現(xiàn)

一佩迟、XML介紹

XML 指可擴(kuò)展標(biāo)記語言(EXtensible Markup Language),也是一種標(biāo)記語言,很類似 HTML.它的設(shè)計宗旨是傳輸數(shù)據(jù)竿屹,而非顯示數(shù)據(jù)它;標(biāo)簽沒有被預(yù)定義,需要自行定義標(biāo)簽报强。
XML 被設(shè)計為具有自我描述性,是 W3C 的推薦標(biāo)準(zhǔn),在電子計算機(jī)中,標(biāo)記指計算機(jī)所能理解的信息符號拱燃,通過此種標(biāo)記秉溉,計算機(jī)之間可以處理包含各種的信息比如文章等。它可以用來標(biāo)記數(shù)據(jù)碗誉、定義數(shù)據(jù)類型召嘶,是一種允許用戶對自己的標(biāo)記語言進(jìn)行定義的源語言。它非常適合萬維網(wǎng)傳輸哮缺,提供統(tǒng)一的方法來描述和交換獨(dú)立于應(yīng)用程序或供應(yīng)商的結(jié)構(gòu)化數(shù)據(jù)弄跌。是Internet環(huán)境中跨平臺的、依賴于內(nèi)容的技術(shù)尝苇,也是當(dāng)今處理分布式結(jié)構(gòu)信息的有效工具铛只。早在1998年埠胖,W3C就發(fā)布了XML1.0規(guī)范,使用它來簡化Internet的文檔信息傳輸淳玩。

xml的作用:
XML 是各種應(yīng)用程序之間進(jìn)行數(shù)據(jù)傳輸?shù)淖畛S玫墓ぞ咧背罚⑶以谛畔⒋鎯兔枋鲱I(lǐng)域變得越來越流行。簡單的說蜕着,我們在開發(fā)中使用XML主要有以下兩方面應(yīng)用:
a. XML做為數(shù)據(jù)交換的載體谊惭,用于數(shù)據(jù)的存儲與傳輸
b. XML做為配置文件

應(yīng)用場景:

  • 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5">
    <servlet>
        <servlet-name>HelloMyServlet</servlet-name>
        <servlet-class>cn.itcast.HelloMyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloMyServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>
  • 存放數(shù)據(jù)
<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person id="p001">
        <name>張三</name>
    </person>
    <person id="p002">
        <name>李四</name>
    </person>
</persons>

二、XML語法

  • 書寫規(guī)范
    xml必須有根元素(只有一個)
    xml標(biāo)簽必須有關(guān)閉標(biāo)簽
    xml標(biāo)簽對大小寫敏感
    xml的屬性值須加引號
    特殊字符必須轉(zhuǎn)義
    xml中的標(biāo)簽名不能有空格
    空格/回車/制表符在xml中都是文本節(jié)點(diǎn)
    xml必須正確地嵌套
    我們將符合上述書寫規(guī)則的XML叫做格式良好的XML文檔侮东。

  • xml組成部分

<bookstore>
<book category="COOKING">
  <title lang="en">Everyday Italian</title> 
  <author>Giada De Laurentiis</author> 
  <year>2005</year> 
  <price>30.00</price> 
</book>
<book category="CHILDREN">
  <title lang="en">Harry Potter</title> 
  <author>J K. Rowling</author> 
  <year>2005</year> 
  <price>29.99</price> 
</book>
<book category="WEB">
  <title lang="en">Learning XML</title> 
  <author>Erik T. Ray</author> 
  <year>2003</year> 
  <price>39.95</price> 
</book>
</bookstore>
XML文件組成.png

對于一個xml文件,首先必須要有根元素豹芯,該元素是所有其它元素的父元素悄雅。而在xml中所有元素形成了一棵樹。父铁蹈,子及同胞等術(shù)語描述了元素之間的關(guān)系宽闲。所有的元素都可以擁有子元素。相同層級上的子元素成為同胞握牧。
所有元素都可以擁有文本內(nèi)容和屬性容诬。
Root 根元素
Element 元素
Attribute 屬性
Text 文本
在開發(fā)中,我們將上述內(nèi)容也統(tǒng)稱為Node(節(jié)點(diǎn))沿腰。
接下來,我們就分析一下览徒,對于一個xml文檔它的主要組成部分有哪些?

  1. XML文檔聲明
    <?xml version="1.0" encoding="UTF-8"?>

    1. 文檔聲明必須為<?xml開頭,以?>結(jié)束颂龙;
    2. 文檔聲明必須從文檔的0行0列位置開始习蓬;
    3. 文檔聲明只有三個屬性:
      a) versioin:指定XML文檔版本。必須屬性措嵌,因為我們不會選擇1.1躲叼,只會選擇1.0;
      b) encoding:指定當(dāng)前文檔的編碼企巢》憧叮可選屬性,默認(rèn)值是utf-8浪规;
      c) standalone:指定文檔獨(dú)立性或听。可選屬性罗丰,默認(rèn)值為yes神帅,表示當(dāng)前文檔是獨(dú)立文檔。如果為no表示當(dāng)前文檔不是獨(dú)立的文檔萌抵,會依賴外部文件找御。
  2. 元素
    <servlet>

    1. 元素是XML文檔中最重要的組成部分元镀,
    2. 普通元素的結(jié)構(gòu)開始標(biāo)簽、元素體霎桅、結(jié)束標(biāo)簽組成栖疑。例如:<hello>大家好</hello>
    3. 元素體:元素體可以是元素,也可以是文本滔驶,例如:<b><a>你好</a></b>
    4. 空元素:空元素只有開始標(biāo)簽遇革,而沒有結(jié)束標(biāo)簽,但元素必須自己閉合揭糕,例如:<c/>
    5. 元素命名:
      a) 區(qū)分大小寫
      b) 不能使用空格萝快,不能使用冒號:
      c) 不建議以XML、xml著角、Xml開頭
    6. 良好的XML文檔揪漩,必須有一個根元素。
  3. 屬性
    <web-app version="2.5">

    1. 屬性是元素的一部分吏口,它必須出現(xiàn)在元素的開始標(biāo)簽中
    2. 屬性的定義格式:屬性名=屬性值奄容,其中屬性值必須使用單引或雙引
    3. 一個元素可以有0~N個屬性,但一個元素中不能出現(xiàn)同名屬性
    4. 屬性名不能使用空格产徊、冒號等特殊字符昂勒,且必須以字母開頭
  4. 注釋
    XML的注釋與HTML相同,即以“”結(jié)束舟铜。注釋內(nèi)容會被XML解析器忽略戈盈!

  5. 轉(zhuǎn)義字符
    XML中的轉(zhuǎn)義字符與HTML一樣。
    因為很多符號已經(jīng)被XML文檔結(jié)構(gòu)所使用谆刨,所以在元素體或?qū)傩灾抵邢胧褂眠@些符號就必須使用轉(zhuǎn)義字符奕谭,例如:“<”、“>”痴荐、“’”血柳、“””、“&”生兆。


    轉(zhuǎn)義字符.png
  • CDATA區(qū)
<![CDATA[
    任意內(nèi)容
]]>

當(dāng)大量的轉(zhuǎn)義字符出現(xiàn)在xml文檔中時难捌,會使xml文檔的可讀性大幅度降低。這時如果使用CDATA段就會好一些鸦难。
在CDATA段中出現(xiàn)的“<”根吁、“>”、“””合蔽、“’”击敌、“&”,都無需使用轉(zhuǎn)義字符拴事。這可以提高xml文檔的可讀性沃斤。
在CDATA段中不能包含“]]>”圣蝎,即CDATA段的結(jié)束定界符。

三衡瓶、DTD約束

DTD(Document Type Definition)徘公,文檔類型定義,用來約束XML文檔哮针。規(guī)定XML文檔中元素的名稱关面,子元素的名稱及順序,元素的屬性等十厢。

開發(fā)中等太,我們很少自己編寫DTD約束文檔,通常情況我們都是通過框架提供的DTD約束文檔蛮放,編寫對應(yīng)的XML文檔澈驼。常見框架使用DTD約束有:struts2、hibernate等筛武。
DTD示例:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    模擬servlet2.3規(guī)范,如果開發(fā)人員需要在xml使用當(dāng)前DTD約束挎塌,必須包括DOCTYPE徘六。
    格式如下:
    <!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
-->
<!ELEMENT web-app (servlet*,servlet-mapping* , welcome-file-list?) >
<!ELEMENT servlet (servlet-name,description?,(servlet-class|jsp-file))>
<!ELEMENT servlet-mapping (servlet-name,url-pattern) >
<!ELEMENT servlet-name (#PCDATA)>
<!ELEMENT servlet-class (#PCDATA)>
<!ELEMENT url-pattern (#PCDATA)>

<!ELEMENT welcome-file-list (welcome-file+)>
<!ELEMENT welcome-file (#PCDATA)>

<!ATTLIST web-app version CDATA #IMPLIED>



案例實現(xiàn):通過提供的DTD“web-app_2_3.dtd”編寫XML

  • 步驟1:創(chuàng)建web.xml文檔,并將“web-app_2_3.dtd”拷貝相同目錄下榴都。


    image.png
  • 步驟2:從DTD文檔開始處待锈,拷貝需要的“文檔聲明”


    image.png

    image.png
  • 步驟3:完成xml內(nèi)容編寫

<web-app version="2.3">
    <servlet>
        <servlet-name></servlet-name>
        <servlet-class></servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name></servlet-name>
        <url-pattern></url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
    </welcome-file-list>
</web-app>

DTD語法

  • 文檔聲明
  1. 內(nèi)部DTD,在XML文檔內(nèi)部嵌入DTD嘴高,只對當(dāng)前XML有效竿音。
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<!DOCTYPE web-app [
    ... //具體的語法
]>
<web-app>
</web-app>
  1. 外部DTD—本地DTD,DTD文檔在本地系統(tǒng)上拴驮,公司內(nèi)部自己項目使用春瞬。
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
<web-app>
</web-app>
  1. 外部DTD—公共DTD,DTD文檔在網(wǎng)絡(luò)上套啤,一般都有框架提供宽气。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
</web-app>
  • 元素聲明
    定義元素語法:<!ELEMENT 元素名 元素描述>
    元素名:自定義
    元素描述包括:符號和數(shù)據(jù)類型
    常見符號:? * + () | ,
    常見類型:#PCDATA 表示內(nèi)容是文檔,不能是子標(biāo)簽


    元素描述.png
<!ELEMENT web-app (servlet*,servlet-mapping* , welcome-file-list?) >
    web-app 包括3個標(biāo)簽潜沦,且必須順序出現(xiàn)萄涯。
        servlet子標(biāo)簽個數(shù)任意
        servlet-mapping 子標(biāo)簽個數(shù)任意
        welcome-file-list 子標(biāo)簽最多只能出現(xiàn)一次
<!ELEMENT servlet (servlet-name,description?,(servlet-class|jsp-file))>
    servlet 有3個子標(biāo)簽,且必須順序出現(xiàn)
        servlet-name唆鸡,必須有涝影,且只能出現(xiàn)一次
        description,可選一次
        servlet-class 和 jsp-file 二選一争占,且只能出現(xiàn)一次
<!ELEMENT servlet-name (#PCDATA)>
    servlet-name 的標(biāo)簽體必須是文本
<!ELEMENT welcome-file-list (welcome-file+)>
    welcome-file-list 至少有一個子標(biāo)簽welcome-file

  • 屬性聲明

屬性的語法:

    <!ATTLIST 元素名 
        屬性名 屬性類型 約束
        屬性名 屬性類型 約束
        ...
    >

元素名:屬性必須是給元素添加燃逻,所有必須先確定元素名
屬性名:自定義
屬性類型:ID序目、CDATA、枚舉 …
ID : ID類型的屬性用來標(biāo)識元素的唯一性
CDATA:文本類型
枚舉:(e1 | e2 | ...) 多選一
約束:
#REQUIRED:說明屬性是必須的唆樊;
#IMPLIED:說明屬性是可選的宛琅;

<!ATTLIST web-app version CDATA #IMPLIED>
    給web-app元素添加 version屬性,屬性值必須是文本逗旁,且可選嘿辟。
    <web-app version="2.3"> 和 <web-app> 都符號約束

四、Schema約束

Schema是新的XML文檔約束片效;
Schema要比DTD強(qiáng)大很多红伦,是DTD 替代者;
Schema本身也是XML文檔淀衣,但Schema文檔的擴(kuò)展名為xsd昙读,而不是xml。
Schema 功能更強(qiáng)大膨桥,數(shù)據(jù)類型更完善
Schema 支持名稱空間

Schema與dtd區(qū)別:
XML從SGML中繼承了DTD蛮浑,并用它來定義內(nèi)容的模型,驗證和組織元素只嚣。同時沮稚,它也有很多局限:
? DTD不遵守XML語法;
? DTD不可擴(kuò)展册舞;
? DTD不支持名稱空間的應(yīng)用蕴掏;
? DTD沒有提供強(qiáng)大的數(shù)據(jù)類型支持,只能表示很簡單的數(shù)據(jù)類型调鲸。

Schema完全克服了這些弱點(diǎn)盛杰,使得基于Web的應(yīng)用系統(tǒng)交換XML數(shù)據(jù)更為容易。下面是它所展現(xiàn)的一些新特性:
? Schema完全基于XML語法藐石,不需要再學(xué)習(xí)特殊的語法即供;
? Schema能用處理XML文檔的工具處理,而不需要特殊的工具于微;
? Schema大大擴(kuò)充了數(shù)據(jù)類型募狂,支持boolean、numbers角雷、dates and times祸穷、URIs、integers勺三、decimal numbers和real numbers等雷滚;
? Schema支持原型,也就是元素的繼承吗坚。如:我們定義了一個“聯(lián)系人”數(shù)據(jù)類型祈远,然后可以根據(jù)它產(chǎn)生“朋友聯(lián)系人”和“客戶聯(lián)系”兩種數(shù)據(jù)類型呆万;
? Schema支持屬性組。我們一般聲明一些公共屬性车份,然后可以應(yīng)用于所有的元素谋减,屬性組允許把元素、屬性關(guān)系放于外部定義扫沼、組合出爹;
? 開放性。原來的DTD只能有一個DTD應(yīng)用于一個XML文檔缎除,現(xiàn)在可以有多個Schema運(yùn)用于一個XML文檔严就。

與DTD一樣,要求可以通過schema約束文檔編寫xml文檔器罐。常見框架使用schema的有:Spring等
實例:通過提供“web-app_2_5.xsd”編寫xml文檔

  • web-app_2_5.xsd
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    模擬servlet2.5規(guī)范梢为,如果開發(fā)人員需要在xml使用當(dāng)前Schema約束,必須包括指定命名空間轰坊。
    格式如下:
    <web-app xmlns="http://www.example.org/web-app_2_5" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
            version="2.5">
-->
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/web-app_2_5"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://www.example.org/web-app_2_5" 
    elementFormDefault="qualified">
    
    <xsd:element name="web-app">
        <xsd:complexType>
            <xsd:choice minOccurs="0" maxOccurs="unbounded">
                <xsd:element name="servlet">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="servlet-name"></xsd:element>
                            <xsd:element name="servlet-class"></xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
                <xsd:element name="servlet-mapping">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="servlet-name"></xsd:element>
                            <xsd:element name="url-pattern"></xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
                <xsd:element name="welcome-file-list">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="welcome-file" maxOccurs="unbounded"></xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:choice>
            <xsd:attribute name="version" type="double" use="optional"></xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
  • 案例實現(xiàn)
  1. 步驟1:創(chuàng)建web.xml铸董,并將“web-app_2_5.xsd”拷貝到同級目錄


    image.png
  2. 步驟2:從xsd文檔中拷貝需要的“命名空間”


    image.png

    image.png
  3. 完成xml內(nèi)容編寫

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
         version="2.5">
    
    <servlet>
        <servlet-name></servlet-name>
        <servlet-class></servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name></servlet-name>
        <url-pattern></url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
    </welcome-file-list>

</web-app>

命名空間(語法)
如果一個XML文檔中使用多個Schema文件,而這些Schema文件中定義了相同名稱的元素時就會出現(xiàn)名字沖突肴沫。這就像一個Java文件中使用了import java.util.和import java.sql.時粟害,在使用Date類時,那么就不明確Date是哪個包下的Date了樊零。
總之名稱空間就是用來處理元素和屬性的名稱沖突問題,與Java中的包是同一用途孽文。如果每個元素和屬性都有自己的名稱空間驻襟,那么就不會出現(xiàn)名字沖突問題,就像是每個類都有自己所在的包一樣芋哭,那么類名就不會出現(xiàn)沖突沉衣。

約束文檔和XML關(guān)系
當(dāng)W3C提出Schema約束規(guī)范時,就提供“官方約束文檔”减牺。我們通過官方文檔豌习,必須“自定義schema 約束文檔”,開發(fā)中“自定義文檔”由框架編寫者提供拔疚。我們提供“自定義文檔”限定肥隆,編寫出自己的xml文檔。

聲明命名空間
默認(rèn)命名空間:<xxx xmlns=””> 稚失,使用<標(biāo)簽>
顯式命名空間:<xxx xmlns:別名=””> 栋艳, 使用<別名:標(biāo)簽>

  • 實例:web-app_2_5.xsd
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" …>
    表示自定義schema約束文檔引用官方文檔作為顯示命名空間。如果要使用官方提供的元素或?qū)傩跃涓鳎仨毷褂脁sd前綴(自定義吸占,此處表示官方文檔晴叨,所以使用xsd)
    <xsd:schema>標(biāo)簽就有官方文檔提供,默認(rèn)命名空間直接使用矾屯。

  • 實例:web.xml
    <web-app xmlns=http://www.example.org/web-app_2_5 …>
    表示 xml 文檔引用“自定義約束文檔”作為默認(rèn)命名空間
    因為使用默認(rèn)命名空間兼蕊,<web-app>直接使用

  • 自定義約束:web-app_2_5.xsd
    <xsd:schema targetNamespace=http://www.example.org/web-app_2_5
    表示給當(dāng)前自定義約束文檔進(jìn)行起名,提供給xml文檔使用件蚕。

  • xml文檔:web.xml
    <web-app
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=http://www.example.org/web-app_2_5 web-app_2_5.xsd

    xmlns:xsi=”…” 固定寫法
    表示是一個schema實例文檔孙技,就是被schema文檔約束的xml文檔。
    xsi:schemaLocation=”名稱 路徑 名稱 路徑 名稱 路徑 …”
    表示用于確定當(dāng)前xml文檔使用到的schema文檔的位置骤坐⌒餍樱“名稱 路徑”是成對出現(xiàn),與xmlns引用命名空間對應(yīng)纽绍。

五蕾久、dom4j解析

當(dāng)將數(shù)據(jù)存儲在XML后,我們就希望通過程序獲得XML的內(nèi)容拌夏。如果我們使用Java基礎(chǔ)所學(xué)習(xí)的IO知識是可以完成的僧著,不過你需要非常繁瑣的操作才可以完成,且開發(fā)中會遇到不同問題(只讀障簿、讀寫)盹愚。人們?yōu)椴煌瑔栴}提供不同的解析方式,并提交對應(yīng)的解析器站故,方便開發(fā)人員操作XML皆怕。

1. 解析方式和解析器

開發(fā)中比較常見的解析方式有三種,如下:

  1. DOM:(Document Object Model, 即文檔對象模型) 是 W3C 組織推薦的解析XML 的一種方式西篓。要求解析器把整個XML文檔裝載到內(nèi)存愈腾,并解析成一個Document對象。
    a) 優(yōu)點(diǎn):元素與元素之間保留結(jié)構(gòu)關(guān)系岂津,故可以進(jìn)行增刪改查操作虱黄。
    b) 缺點(diǎn):XML文檔過大,可能出現(xiàn)內(nèi)存溢出顯現(xiàn)吮成。
  2. SAX:(Simple API for XML) 不是官方標(biāo)準(zhǔn)橱乱,但它是 XML 社區(qū)事實上的標(biāo)準(zhǔn),幾乎所有的 XML 解析器都支持它粱甫。是一種速度更快泳叠,更有效的方法。它逐行掃描文檔茶宵,一邊掃描一邊解析析二。并以事件驅(qū)動的方式進(jìn)行具體解析,每執(zhí)行一行,都將觸發(fā)對應(yīng)的事件叶摄。
    a) 優(yōu)點(diǎn):處理速度快属韧,可以處理大文件
    b) 缺點(diǎn):只能讀,逐行后將釋放資源蛤吓。
  3. PULL:Android內(nèi)置的XML解析方式宵喂,類似SAX。(了解)
  • 解析器:就是根據(jù)不同的解析方式提供的具體實現(xiàn)会傲。有的解析器操作過于繁瑣锅棕,為了方便開發(fā)人員,有提供易于操作的解析開發(fā)包淌山。


    解析器.png
  • 常見的解析開發(fā)包:
    JAXP:sun公司提供支持DOM和SAX開發(fā)包
    JDom:dom4j兄弟
    jsoup:一種處理HTML特定解析開發(fā)包
    dom4j:比較常用的解析開發(fā)包裸燎,hibernate底層采用。

  • DOM和SAX區(qū)別

    1. DOM
      支持回寫
      會將整個XML載入內(nèi)存泼疑,以樹形結(jié)構(gòu)方式存儲
      XML比較復(fù)雜的時候德绿,或者當(dāng)你需要隨機(jī)處理文檔中數(shù)據(jù)的時候不建議使用
    2. SAX
      相比DOM是一種更為輕量級的方案
      采用串行方法讀取 --- 逐行讀取
      編程較為復(fù)雜
      無法修改XML數(shù)據(jù)

2. DOM解析原理及結(jié)構(gòu)模型

XML DOM 和 HTML DOM類似,XML DOM 將 整個XML文檔加載到內(nèi)存退渗,生成一個DOM樹移稳,并獲得一個Document對象,通過Document對象就可以對DOM進(jìn)行操作会油。


XML DOM.png

DOM中的核心概念就是節(jié)點(diǎn)个粱,在XML文檔中的元素、屬性翻翩、文本等都许,在DOM中都是節(jié)點(diǎn)!


DOM中都是節(jié)點(diǎn).png

3. API使用

如果需要使用dom4j嫂冻,必須導(dǎo)入jar包胶征。


image.png

dom4j 必須使用核心類SaxReader加載xml文檔獲得Document,通過Document對象獲得文檔的根元素絮吵,然后就可以操作了弧烤。
常用API如下:

  1. SaxReader對象
    a) read(…) 加載執(zhí)行xml文檔
  2. Document對象
    a) getRootElement() 獲得根元素
  3. Element對象
    a) elements(…) 獲得指定名稱的所有子元素忱屑〉徘茫可以不指定名稱
    b) element(…) 獲得指定名稱第一個子元素≥航洌可以不指定名稱
    c) getName() 獲得當(dāng)前元素的元素名
    d) attributeValue(…) 獲得指定屬性名的屬性值
    e) elementText(…) 獲得指定名稱子元素的文本值
    f) getText() 獲得當(dāng)前元素的文本內(nèi)容

節(jié)點(diǎn)操作

1.獲取文檔的根節(jié)點(diǎn).
    Element root = document.getRootElement();
2.取得某個節(jié)點(diǎn)的子節(jié)點(diǎn).
    Element element=node.element(“書名");
3.取得節(jié)點(diǎn)的文字
    String text=node.getText();
4.取得某節(jié)點(diǎn)下所有名為“member”的子節(jié)點(diǎn)伴嗡,并進(jìn)行遍歷.
List nodes = rootElm.elements("member");
for (Iterator it = nodes.iterator(); it.hasNext();) 
{    Element elm = (Element) it.next();   // do something}

節(jié)點(diǎn)對象屬性

1.取得某節(jié)點(diǎn)下的某屬性  
   Element root=document.getRootElement();       //屬性名name
   Attribute attribute=root.attribute(“屬性”);//getValue()
2.取得屬性的文字  
String text=attribute.getText(); === getValue();
3.取得某屬性的文字
    String value=node.attributeValue(“屬性”);

解析web.xml文件:

public class Dom4jTest {
    @Test
    public void demo03() throws Exception{
        //#1 獲得document
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File("src/com/yzy/mytomcat/schema/web.xml"));

        //#2 獲得根元素
        Element rootElement = document.getRootElement();

        //打印version屬性值
        String version = rootElement.attributeValue("version");
        System.out.println(version);

        //#3 獲得所有子元素。例如:<servlet>/<servlet-mapping>
        List<Element> allChildElement = rootElement.elements();

        //#4 遍歷所有
        for (Element childElement : allChildElement) {
            // #5.1 打印元素名
            String childEleName = childElement.getName();
            System.out.println(childEleName);

            // #5.2 處理<servlet> ,并獲得子標(biāo)簽的內(nèi)容从铲。例如:<servlet-name> 等
            if("servlet".equals(childEleName)){
                // 方式1:獲得元素對象瘪校,然后獲得文本
                Element servletNameElement = childElement.element("servlet-name");
                String servletName = servletNameElement.getText();
                System.out.println("\t" + servletName);

                // 方式2:獲得元素文本值
                String servletClass = childElement.elementText("servlet-class");
                System.out.println("\t" + servletClass);

            }

            // #5.3 處理<servlet-mapping> 省略...

        }

    }

}

4. dom4j-xpath使用

XPath 是一門在 XML 文檔中查找信息的語言
XPath 可用來在 XML 文檔中對元素和屬性進(jìn)行遍歷
XPath簡化了Dom4j查找節(jié)點(diǎn)的過程
使用XPath必須導(dǎo)入jaxen-1.1-beta-6.jar否則出現(xiàn)NoClassDefFoundError: org/jaxen/JaxenException

在DOM4J中使用XPATH:
獲取所有符合條件的節(jié)點(diǎn)
selectNodes(String xpathExpression) 返回List集合
獲取符合條件的單個節(jié)點(diǎn)
selectSingleNode(String xpathExpression) 返回一個Node對象。
如果符合條件的節(jié)點(diǎn)有多個,那么返回第一個阱扬。


六泣懊、實例:編寫服務(wù)器軟件,訪問指定配置內(nèi)容

  • 1.創(chuàng)建實例工廠
    編寫接口
public interface MyServlet {
    
    public void init();     //1.初始化
    
    public void service();  //2.執(zhí)行
    
    public void destory();  //3.銷毀

}

實現(xiàn)接口

public class HelloMyServlet implements MyServlet {

    @Override
    public void init() {
        System.out.println("1.初始化");
    }

    @Override
    public void service() {
        System.out.println("2.執(zhí)行中....");
    }

    @Override
    public void destory() {
        System.out.println("3.銷毀");
    }

}

測試麻惶,創(chuàng)建實現(xiàn)類實例對象

public class TestApp {
    @Test
    public void demo01(){
        //手動創(chuàng)建執(zhí)行
        MyServlet myServlet = new HelloMyServlet();
        myServlet.init();
        myServlet.service();
        myServlet.destory();
    }
}
    1. 反射創(chuàng)建實例對象
      測試程序我們直接new HelloServlet馍刮,這種編程方式我們稱為硬編碼,及代碼寫死了窃蹋。為了后期程序的可擴(kuò)展卡啰,開發(fā)中通常使用實現(xiàn)類的全限定類名(cn.itcast.e_web.HelloMyServlet),通過反射加載字符串指定的類警没,并通過反射創(chuàng)建實例匈辱。
@Test
public void demo02() throws Exception{
    /* 反射創(chuàng)建執(zhí)行
     * 1) Class.forName 返回指定接口或類的Class對象
     * 2) newInstance() 通過Class對象創(chuàng)建類的實例對象,相當(dāng)于new Xxx();
     */
    String servletClass = "com.yzy.mytomcat.web.implement.HelloMyServlet";
    
    //3 獲得字符串實現(xiàn)類實例
    Class clazz = Class.forName(servletClass);
    MyServlet myServlet = (MyServlet) clazz.newInstance();
    //4 執(zhí)行對象的方法
    myServlet.init();
    myServlet.service();
    myServlet.destory();
}
  • 解析xml
    使用反射我們已經(jīng)可以創(chuàng)建對象的實例杀迹,此時我們使用的全限定類名亡脸,在程序是仍寫死了,我們將器配置到xml文檔中佛南。
    xml文檔內(nèi)容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
         version="2.5">

    <servlet>
        <servlet-name>HelloMyServlet</servlet-name>
        <servlet-class>com.yzy.mytomcat.web.implement.HelloMyServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloMyServlet</servlet-name>
        <url-pattern>/implement</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
    </welcome-file-list>

</web-app>

解析實現(xiàn)

 @Test
    public void demo03() throws Exception{
        /* 讀取xml配置文件梗掰,獲得<servlet-class>配置的內(nèi)容,取代固定字符串
         */

        //1.1 加載xml配置文件嗅回,并獲得document對象
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File("src/com/yzy/mytomcat/schema/web.xml"));
        //1.2 獲得根元素
        Element rootElement = document.getRootElement();
        //1.3 獲得第一個<servlet> 子元素
        Element servletElement = rootElement.element("servlet");
        //1.4 獲得字符串實現(xiàn)類 <servlet-class>的值
        String servletClass = servletElement.elementText("servlet-class");

        //3 獲得字符串實現(xiàn)類實例
        Class clazz = Class.forName(servletClass);
        MyServlet myServlet = (MyServlet) clazz.newInstance();
        //4 執(zhí)行對象的方法
        myServlet.init();
        myServlet.service();
        myServlet.destory();
    }

    1. 模擬瀏覽器路徑
      上面我們已經(jīng)解析xml及穗,不過我們獲得內(nèi)容是固定。我們希望如果用戶訪問的路徑是/implement绵载,將執(zhí)行com.yzy.mytomcat.web.implement.HelloMyServlet程序埂陆,如果訪問時/implement2,將執(zhí)行com.yzy.mytomcat.web.implement.HelloMyServlet2程序娃豹。
      在執(zhí)行測試程序前(@Before)焚虱,解析xml文件,將解析的結(jié)果存放在Map中懂版,map中數(shù)據(jù)的格式為:路徑=實現(xiàn)類鹃栽。
      image.png

xml文件內(nèi)容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
         version="2.5">

    <servlet>
        <servlet-name>HelloMyServlet</servlet-name>
        <servlet-class>com.yzy.mytomcat.web.implement.HelloMyServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloMyServlet</servlet-name>
        <url-pattern>/implement</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HelloMyServlet2</servlet-name>
        <servlet-class>com.yzy.mytomcat.web.implement2.HelloMyServlet2</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloMyServlet2</servlet-name>
        <url-pattern>/implement2</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
        <welcome-file></welcome-file>
    </welcome-file-list>

</web-app>

解析xml思路:先解析<servlet>,將結(jié)果存放map躯畴,name=class民鼓,然后再解析<servlet-mapping>通過name獲得class,再將url=class存放到map蓬抄,最后將name=class移除丰嘉。

//最終存放 key=請求路徑,value=實現(xiàn)類
    private Map<String, String> data = new HashMap<String,String>();
    @Before
    public void demo04Before() throws Exception{
        //在執(zhí)行前執(zhí)行嚷缭,解析xml饮亏,并將結(jié)果存放到Map<路徑耍贾,實現(xiàn)類>中
        //1 獲得document
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File("src/com/yzy/mytomcat/schema/web.xml"));
        //2 獲得根元素
        Element rootElement = document.getRootElement();
        //3 獲得所有的子元素 <servlet> 、<servlet-mapping>等
        List<Element> allChildElement = rootElement.elements();
        /* 4 遍歷所有
         * 1)解析到<servlet>路幸,將其子標(biāo)簽<servlet-name>與<servlet-class>存放到Map中
         * 2)解析到<servlet-mapping>荐开,獲得子標(biāo)簽<servlet-name>和<url-pattern>, 從map中獲得1的內(nèi)容,組合成 url = class 鍵值對
         */
        for (Element childElement : allChildElement) {
            //4.1 獲得元素名
            String eleName = childElement.getName();
            //4.2 如果是servlet简肴,將解析內(nèi)容存放到Map中
            if("servlet".equals(eleName)){
                String servletName = childElement.elementText("servlet-name");
                String servletClass = childElement.elementText("servlet-class");
                data.put(servletName, servletClass);
            }
            //4.3 如果是servlet-mapping誓焦,獲得之前內(nèi)容,組成成key=url,value=class并添加到Map中
            if("servlet-mapping".equals(eleName)){
                String servletName = childElement.elementText("servlet-name");
                String urlPattern = childElement.elementText("url-pattern");
                // 獲得<servlet-name>之前存放在Map中<servlet-class>值
                String servletClass= data.get(servletName);
                // 存放新的內(nèi)容 url = class
                data.put(urlPattern, servletClass);
                // 將之前存放的數(shù)據(jù)刪除
                data.remove(servletName);
            }

            //打印信息
            System.out.println(data);

        }
    }

模擬瀏覽器請求路徑着帽,通過url從map獲得class杂伟,并使用反射執(zhí)行實現(xiàn)類。

 @Test
    public void demo04() throws Exception{

        //1 模擬路徑
        //String url = "/implement";
        String url = "/implement2";

        //2 通過路徑獲得對應(yīng)的實現(xiàn)類
        String servletClass = data.get(url);

        //3 獲得字符串實現(xiàn)類實例
        Class clazz = Class.forName(servletClass);
        MyServlet myServlet = (MyServlet) clazz.newInstance();
        //4 執(zhí)行對象的方法
        myServlet.init();
        myServlet.service();
        myServlet.destory();
    }
 @Test
    public void demo05() throws Exception{
        //使用socket獲得請求路徑

        //1.1 給本地計算機(jī)綁定端口8888
        ServerSocket serverSocket = new ServerSocket(8888);
        //1.2 程序阻塞越平,等待瀏覽器請求。
        Socket accept = serverSocket.accept();
        //1.3 獲得請求所有數(shù)據(jù)
        BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
        //1.4 獲得第一行數(shù)據(jù)灵迫,請求行秦叛,例如:GET /hello HTTP/1.1
        String firstLine = reader.readLine();
        //1.5 請求行三部分?jǐn)?shù)據(jù)由空格連接,獲得中間數(shù)據(jù)瀑粥。表示請求路徑
        String url = firstLine.split(" ")[1];
        System.out.println(url);

        //2 通過路徑獲得對應(yīng)的實現(xiàn)類
        String servletClass = data.get(url);

        //3 獲得字符串實現(xiàn)類實例
        Class clazz = Class.forName(servletClass);
        MyServlet myServlet = (MyServlet) clazz.newInstance();
        //4 執(zhí)行對象的方法
        myServlet.init();
        myServlet.service();
        myServlet.destory();
        //5 釋放資源
        reader.close();

控制臺等待鏈接時:


image.png

輸入網(wǎng)址測試挣跋,控制臺效果:


image.png

image.png
image.png

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狞换,隨后出現(xiàn)的幾起案子避咆,更是在濱河造成了極大的恐慌,老刑警劉巖修噪,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查库,死亡現(xiàn)場離奇詭異,居然都是意外死亡黄琼,警方通過查閱死者的電腦和手機(jī)樊销,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脏款,“玉大人围苫,你說我怎么就攤上這事〕诿” “怎么了够吩?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵比然,是天一觀的道長丈氓。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么万俗? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任湾笛,我火速辦了婚禮,結(jié)果婚禮上闰歪,老公的妹妹穿的比我還像新娘嚎研。我一直安慰自己,他們只是感情好库倘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布临扮。 她就那樣靜靜地躺著,像睡著了一般教翩。 火紅的嫁衣襯著肌膚如雪杆勇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天饱亿,我揣著相機(jī)與錄音蚜退,去河邊找鬼。 笑死彪笼,一個胖子當(dāng)著我的面吹牛钻注,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播配猫,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼幅恋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泵肄?” 一聲冷哼從身側(cè)響起佳遣,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凡伊,沒想到半個月后零渐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡系忙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年诵盼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片银还。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡风宁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛹疯,到底是詐尸還是另有隱情戒财,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布捺弦,位于F島的核電站饮寞,受9級特大地震影響孝扛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幽崩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一苦始、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慌申,春花似錦陌选、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柒爵,卻和暖如春臼勉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背餐弱。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工宴霸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膏蚓。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓瓢谢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親驮瞧。 傳聞我的和親對象是個殘疾皇子湖苞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 1. XML簡介 以下內(nèi)容來自于http://www.w3school.com.cn/xml 基本知識 XML 和...
    WebSSO閱讀 1,907評論 1 7
  • 1. XML總結(jié) 1.1. XML簡介 XML : 可擴(kuò)展的標(biāo)記語言屡萤。(和HTML非常類似的) 可擴(kuò)展的。 自定義...
    Ethan_Walker閱讀 3,001評論 0 12
  • 課程內(nèi)容:XML 安裝MyEclipse開發(fā)工具 * 破解(看圖) * 配置 * 配置工作空間的編碼(UTF-...
    流年劃破容顏_cc55閱讀 1,182評論 0 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)荤堪,斷路器奏寨,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • 《生命四元素——占星與心理學(xué)》讀書筆記 NO6 太陽的元素揭露了一個人的基本能量椎咧,自我投射的勢力凌彬,日常生活里的經(jīng)驗...
    菲梵飛閱讀 216評論 0 1