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

一、XML介紹

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

xml的作用:
XML 是各種應用程序之間進行數(shù)據(jù)傳輸?shù)淖畛S玫墓ぞ?,并且在信息存儲和描述領域變得越來越流行。簡單的說,我們在開發(fā)中使用XML主要有以下兩方面應用:
a. XML做為數(shù)據(jù)交換的載體,用于數(shù)據(jù)的存儲與傳輸
b. XML做為配置文件

應用場景:

  • 配置文件
<?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標簽必須有關閉標簽
    xml標簽對大小寫敏感
    xml的屬性值須加引號
    特殊字符必須轉義
    xml中的標簽名不能有空格
    空格/回車/制表符在xml中都是文本節(jié)點
    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中所有元素形成了一棵樹。父,子及同胞等術語描述了元素之間的關系。所有的元素都可以擁有子元素。相同層級上的子元素成為同胞。
所有元素都可以擁有文本內容和屬性。
Root 根元素
Element 元素
Attribute 屬性
Text 文本
在開發(fā)中,我們將上述內容也統(tǒng)稱為Node(節(jié)點)。
接下來,我們就分析一下,對于一個xml文檔它的主要組成部分有哪些?

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

    1. 文檔聲明必須為<?xml開頭,以?>結束;
    2. 文檔聲明必須從文檔的0行0列位置開始;
    3. 文檔聲明只有三個屬性:
      a) versioin:指定XML文檔版本。必須屬性,因為我們不會選擇1.1,只會選擇1.0;
      b) encoding:指定當前文檔的編碼。可選屬性,默認值是utf-8;
      c) standalone:指定文檔獨立性。可選屬性,默認值為yes,表示當前文檔是獨立文檔。如果為no表示當前文檔不是獨立的文檔,會依賴外部文件。
  2. 元素
    <servlet>

    1. 元素是XML文檔中最重要的組成部分,
    2. 普通元素的結構開始標簽、元素體、結束標簽組成。例如:<hello>大家好</hello>
    3. 元素體:元素體可以是元素,也可以是文本,例如:<b><a>你好</a></b>
    4. 空元素:空元素只有開始標簽,而沒有結束標簽,但元素必須自己閉合,例如:<c/>
    5. 元素命名:
      a) 區(qū)分大小寫
      b) 不能使用空格,不能使用冒號:
      c) 不建議以XML、xml、Xml開頭
    6. 良好的XML文檔,必須有一個根元素。
  3. 屬性
    <web-app version="2.5">

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

  5. 轉義字符
    XML中的轉義字符與HTML一樣。
    因為很多符號已經(jīng)被XML文檔結構所使用,所以在元素體或屬性值中想使用這些符號就必須使用轉義字符,例如:“<”、“>”、“’”、“””、“&”。


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

當大量的轉義字符出現(xiàn)在xml文檔中時,會使xml文檔的可讀性大幅度降低。這時如果使用CDATA段就會好一些。
在CDATA段中出現(xiàn)的“<”、“>”、“””、“’”、“&”,都無需使用轉義字符。這可以提高xml文檔的可讀性。
在CDATA段中不能包含“]]>”,即CDATA段的結束定界符。

三、DTD約束

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

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

<?xml version="1.0" encoding="UTF-8"?>
<!--
    模擬servlet2.3規(guī)范,如果開發(fā)人員需要在xml使用當前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內容編寫

<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. 內部DTD,在XML文檔內部嵌入DTD,只對當前XML有效。
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<!DOCTYPE web-app [
    ... //具體的語法
]>
<web-app>
</web-app>
  1. 外部DTD—本地DTD,DTD文檔在本地系統(tǒng)上,公司內部自己項目使用。
<?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)絡上,一般都有框架提供。
<?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 表示內容是文檔,不能是子標簽


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

  • 屬性聲明

屬性的語法:

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

元素名:屬性必須是給元素添加,所有必須先確定元素名
屬性名:自定義
屬性類型:ID、CDATA、枚舉 …
ID : ID類型的屬性用來標識元素的唯一性
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強大很多,是DTD 替代者;
Schema本身也是XML文檔,但Schema文檔的擴展名為xsd,而不是xml。
Schema 功能更強大,數(shù)據(jù)類型更完善
Schema 支持名稱空間

Schema與dtd區(qū)別:
XML從SGML中繼承了DTD,并用它來定義內容的模型,驗證和組織元素。同時,它也有很多局限:
? DTD不遵守XML語法;
? DTD不可擴展;
? DTD不支持名稱空間的應用;
? DTD沒有提供強大的數(shù)據(jù)類型支持,只能表示很簡單的數(shù)據(jù)類型。

Schema完全克服了這些弱點,使得基于Web的應用系統(tǒng)交換XML數(shù)據(jù)更為容易。下面是它所展現(xiàn)的一些新特性:
? Schema完全基于XML語法,不需要再學習特殊的語法;
? Schema能用處理XML文檔的工具處理,而不需要特殊的工具;
? Schema大大擴充了數(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支持屬性組。我們一般聲明一些公共屬性,然后可以應用于所有的元素,屬性組允許把元素、屬性關系放于外部定義、組合;
? 開放性。原來的DTD只能有一個DTD應用于一個XML文檔,現(xiàn)在可以有多個Schema運用于一個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使用當前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內容編寫

<?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關系
當W3C提出Schema約束規(guī)范時,就提供“官方約束文檔”。我們通過官方文檔,必須“自定義schema 約束文檔”,開發(fā)中“自定義文檔”由框架編寫者提供。我們提供“自定義文檔”限定,編寫出自己的xml文檔。

聲明命名空間
默認命名空間:<xxx xmlns=””> ,使用<標簽>
顯式命名空間:<xxx xmlns:別名=””> , 使用<別名:標簽>

  • 實例:web-app_2_5.xsd
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" …>
    表示自定義schema約束文檔引用官方文檔作為顯示命名空間。如果要使用官方提供的元素或屬性,必須使用xsd前綴(自定義,此處表示官方文檔,所以使用xsd)
    <xsd:schema>標簽就有官方文檔提供,默認命名空間直接使用。

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

  • 自定義約束:web-app_2_5.xsd
    <xsd:schema targetNamespace=http://www.example.org/web-app_2_5
    表示給當前自定義約束文檔進行起名,提供給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=”名稱 路徑 名稱 路徑 名稱 路徑 …”
    表示用于確定當前xml文檔使用到的schema文檔的位置?!懊Q 路徑”是成對出現(xiàn),與xmlns引用命名空間對應。

五、dom4j解析

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

1. 解析方式和解析器

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

  1. DOM:(Document Object Model, 即文檔對象模型) 是 W3C 組織推薦的解析XML 的一種方式。要求解析器把整個XML文檔裝載到內存,并解析成一個Document對象。
    a) 優(yōu)點:元素與元素之間保留結構關系,故可以進行增刪改查操作。
    b) 缺點:XML文檔過大,可能出現(xiàn)內存溢出顯現(xiàn)。
  2. SAX:(Simple API for XML) 不是官方標準,但它是 XML 社區(qū)事實上的標準,幾乎所有的 XML 解析器都支持它。是一種速度更快,更有效的方法。它逐行掃描文檔,一邊掃描一邊解析。并以事件驅動的方式進行具體解析,每執(zhí)行一行,都將觸發(fā)對應的事件。
    a) 優(yōu)點:處理速度快,可以處理大文件
    b) 缺點:只能讀,逐行后將釋放資源。
  3. PULL:Android內置的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載入內存,以樹形結構方式存儲
      XML比較復雜的時候,或者當你需要隨機處理文檔中數(shù)據(jù)的時候不建議使用
    2. SAX
      相比DOM是一種更為輕量級的方案
      采用串行方法讀取 --- 逐行讀取
      編程較為復雜
      無法修改XML數(shù)據(jù)

2. DOM解析原理及結構模型

XML DOM 和 HTML DOM類似,XML DOM 將 整個XML文檔加載到內存,生成一個DOM樹,并獲得一個Document對象,通過Document對象就可以對DOM進行操作。


XML DOM.png

DOM中的核心概念就是節(jié)點,在XML文檔中的元素、屬性、文本等,在DOM中都是節(jié)點!


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

3. API使用

如果需要使用dom4j,必須導入jar包。


image.png

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

  1. SaxReader對象
    a) read(…) 加載執(zhí)行xml文檔
  2. Document對象
    a) getRootElement() 獲得根元素
  3. Element對象
    a) elements(…) 獲得指定名稱的所有子元素??梢圆恢付Q
    b) element(…) 獲得指定名稱第一個子元素??梢圆恢付Q
    c) getName() 獲得當前元素的元素名
    d) attributeValue(…) 獲得指定屬性名的屬性值
    e) elementText(…) 獲得指定名稱子元素的文本值
    f) getText() 獲得當前元素的文本內容

節(jié)點操作

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

節(jié)點對象屬性

1.取得某節(jié)點下的某屬性  
   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> ,并獲得子標簽的內容。例如:<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 文檔中對元素和屬性進行遍歷
XPath簡化了Dom4j查找節(jié)點的過程
使用XPath必須導入jaxen-1.1-beta-6.jar否則出現(xiàn)NoClassDefFoundError: org/jaxen/JaxenException

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


六、實例:編寫服務器軟件,訪問指定配置內容

  • 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,這種編程方式我們稱為硬編碼,及代碼寫死了。為了后期程序的可擴展,開發(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)建類的實例對象,相當于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文檔內容:
<?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>配置的內容,取代固定字符串
         */

        //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,不過我們獲得內容是固定。我們希望如果用戶訪問的路徑是/implement,將執(zhí)行com.yzy.mytomcat.web.implement.HelloMyServlet程序,如果訪問時/implement2,將執(zhí)行com.yzy.mytomcat.web.implement.HelloMyServlet2程序。
      在執(zhí)行測試程序前(@Before),解析xml文件,將解析的結果存放在Map中,map中數(shù)據(jù)的格式為:路徑=實現(xiàn)類。
      image.png

xml文件內容:

<?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>,將結果存放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,并將結果存放到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>,將其子標簽<servlet-name>與<servlet-class>存放到Map中
         * 2)解析到<servlet-mapping>,獲得子標簽<servlet-name>和<url-pattern>, 從map中獲得1的內容,組合成 url = class 鍵值對
         */
        for (Element childElement : allChildElement) {
            //4.1 獲得元素名
            String eleName = childElement.getName();
            //4.2 如果是servlet,將解析內容存放到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,獲得之前內容,組成成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);
                // 存放新的內容 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 通過路徑獲得對應的實現(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 給本地計算機綁定端口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 請求行三部分數(shù)據(jù)由空格連接,獲得中間數(shù)據(jù)。表示請求路徑
        String url = firstLine.split(" ")[1];
        System.out.println(url);

        //2 通過路徑獲得對應的實現(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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

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

友情鏈接更多精彩內容