1. XML總結(jié)
1.1. XML簡介
XML : 可擴展的標記語言。(和HTML非常類似的)
- 可擴展的。
- 自定義的標簽。
與HTML區(qū)別: XML傳輸數(shù)據(jù),HTML是顯示數(shù)據(jù)。
XML的版本: XML1.0(幾乎都使用該版本) XML1.1(不向下兼容)
做什么用?=>描述有關系的數(shù)據(jù)
應用
- 作為配置文件。
- 可以在系統(tǒng)與系統(tǒng)之間進行數(shù)據(jù)的傳輸。
- webserivice soap XML封裝數(shù)據(jù)
- json 和XML概念相似
1.2. XML基本語法
- 文檔聲明(*****)
寫法: <?xml version="1.0" ?> 注意:<? 和xml之間不能有空格. xml和version、encoding、standalone 必須全部小寫
文檔聲明必須出現(xiàn)在xml文件的|--第一行和第一列--|(即該語句前面不能有空格,空行)的位置。
-
屬性:
- version="1.0" XML的版本 (必須寫)
- encoding="UTF-8" 編碼集 (可選的)決定解碼的方式
- standalone="yes或者no" 代表xml的文件是否是獨立的。(如果是no,不獨立,可以引入外部的文件)(可選的)
- 該屬性沒什么卵用,因為不寫該屬性,也可以引入外部的文件,即該值默認為 no 。
-
亂碼會伴隨你們一生?
- 產(chǎn)生的原因:保存文件時和打開文件時采用的編碼不一致。
- 解決辦法:保存文件和打開文件采用的編碼一致就ok。(MyEclipse不會產(chǎn)生亂碼問題,自動轉(zhuǎn)換好了)
- 元素(***)
-
開始標簽和結(jié)束標簽。
- 包含標簽主體: <abc>文本</abc>
- 不包含標簽主體: <abc/>
不能交叉嵌套
只能有一個根元素(必須有,并且只能有一個)
-
命名規(guī)范:
- 區(qū)分大小寫 錯誤的:<a></A> 代表兩個標簽
- 不能以數(shù)字和-中劃線開頭 錯誤的:<1a> <-a>
- 不能以XML(Xml XML xml)開頭 錯誤的:<xmlaa>
- 不能包含空格和冒號。
-
- 屬性(***)
- 自定義:命名規(guī)范同上。
- 在同一個元素上,不能有相同的屬性。(*****)
- 屬性值可以使用雙引號或者單引號。
-
注釋(*)
和HTML的注釋相同
注釋不能嵌套。
-
特殊字符
轉(zhuǎn)義字符< <> >& &單個雙引號 "單個單引號 '
其中 < 和 & 符號必須轉(zhuǎn)義,其他三個可以不用轉(zhuǎn)義
如何在網(wǎng)頁上顯示特定的字符串?(包含一堆特殊字符,全部轉(zhuǎn)義特別麻煩)
-
CDATA區(qū)
- 把標簽中的內(nèi)容作為字符串。
- 語法:
<![CDATA[ 內(nèi)容:當成字符串直接顯示 ]]>例:
<![CDATA[ if(2<3&&32>8){ "das"&&'ds'; } ]]> -
PI(處理指令)(沒用)
- 替換HTML
1.3. XML約束
約束的分類
- DTD
- schema
<myspring>
<bean>hello.java</bean>
<貓/>
</myspring>
- 格式良好的XML:遵循語法規(guī)范。
- 有效的XML:有約束。
1.3.1. XML約束--DTD 約束
- DTD的約束
快速入門
-
快速入門的步驟:
需要出現(xiàn)哪些標簽?
在DTD的文件中編寫元素
<!ELEMENT 元素名稱 (元素類型)>-
判斷元素是否是復雜還是簡單元素?
- 如果是簡單元素:(#PCDATA) 代表是字符串,必須有()
- 如果是復雜元素:(子節(jié)點1,子節(jié)點2 ...) 內(nèi)部是子結(jié)點的元素名稱
-
需要在book.xml引入外部DTD的文件
- <!DOCTYPE 根節(jié)點元素名 SYSTEM "DTD文件的地址">
-
DTD與XML文檔的關聯(lián)方式
可以在XML的文件中直接書寫DTD的代碼。(經(jīng)常使用)
<!DOCTYPE 根節(jié)點 [
DTD的代碼
]>引入本地的DTD文件(經(jīng)常使用)
<!DOCTYPE 根節(jié)點 SYSTEM "DTD文件的地址">引入網(wǎng)絡上的DTD文件(偶爾使用)
<!DOCTYPE 根節(jié)點 PUBLIC "DTD文件名稱" "DTD文件的地址">
* 元素定義
* 語法:<!ELEMENT 元素名稱 元素類型>
* (#PCDATA) 字符串,中間可以為空
* EMPTY 空,標簽內(nèi)部不能包含數(shù)據(jù),不能包括空格、換行
* ANY 任意的,中間可以為空,可以為字符串,可以為(子元素)
* (子元素)
* 子元素:
* 子元素之間的關系
, 子元素出現(xiàn)是有順序的
| 子元素只能出現(xiàn)一個
* 子元素出現(xiàn)的次數(shù)
+ 子元素出現(xiàn)1次或多次
* 子元素出現(xiàn)0次或多次
? 子元素出現(xiàn)0次或1次
在子元素名后,加上數(shù)量的限定
```xml
<!ELEMENT MYFILE ((TITLE*, AUTHOR?, EMAIL)* | COMMENT)>
<MYFILE>
<TITLE></TITLE>
<AUTHOR></AUTHOR>
<EMAIL></EMAIL>
<TITLE></TITLE>
<AUTHOR></AUTHOR>
<EMAIL></EMAIL>
<TITLE></TITLE>
<AUTHOR></AUTHOR>
<EMAIL></EMAIL>
</MYFILE>
```
* 屬性定義(AttributeList)
* 寫法:
```xml
<!ATTLIST 元素名稱
屬性名稱 屬性類型 屬性約束 和數(shù)據(jù)庫中表中數(shù)據(jù)的定義 相似
屬性名稱 屬性類型 屬性約束
>
```
* 屬性類型
* CDATA 字符串
* 枚舉(沒有提供關鍵字) (男人|女人)-->枚舉可能結(jié)果視為枚舉類型聲明
* ID 代表唯一的值,不能以數(shù)字開頭
* 屬性的約束
* #IMPLIED 可選的
* #REQUIRED 必須出現(xiàn)的
以下兩個屬性,在前面定義了,即使相應的元素中沒有寫,也存在,相應屬性是固定值/默認值
* #FIXED 固定值 ,格式為: #FIXED "值"
* 默認值 直接在屬性類型后加上該默認值 (很少用)
注意:一個元素內(nèi)只能有一個 ID 屬性,且 ID 屬性后面的約束只能是
#REQUIRED 或者 #IMPLIED,不能是 #FIXED 或者 默認值
例:
```xml
<!ARRLIST 書
頁數(shù) CDATA #REQUIRED 必須出現(xiàn)的
贈送 (贈送|非贈送) #IMPLIED 可選
編號 ID #REQUIRED ID類型
二維碼 CDATA #FIXED "哈哈哈" 固定值
出版國家 CDATA "中國" 默認值
>
```
* 實體定義(用的不多)
* <!ENTITY 別名 "值" >
在元素中引用 &別名; 最終在瀏覽器中顯示的是 "值"
* 需要在xml中引入別名,瀏覽器打開文件后,在引入的位置上顯示值的。
例:
dtd 內(nèi)容:
<!DOCTYPE 書架 [
<!ELEMENT ...>
<!ATTLIST ...>
<!ENTITY haha "臥槽">
]>
xml 內(nèi)容:
<書>&haha;</書>
這里的&haha; 在瀏覽器中顯示為 "臥槽"
示例: student.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT 班級 (學生+)>
<!ELEMENT 學生 (姓名,年齡,身高,體重)>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 年齡 (#PCDATA)>
<!ELEMENT 身高 (#PCDATA)>
<!ELEMENT 體重 (#PCDATA)>
<!ATTLIST 班級
編號 ID #REQUIRED
年級 CDATA "三年級"
學校名 CDATA #FIXED "西北工業(yè)大學"
>
<!ATTLIST 學生
編號 ID #REQUIRED
性別 (男|女) #REQUIRED
癖好 CDATA #IMPLIED
>
對應的 xml文件:
<?xml version="1.0" encoding="utf-8" ?>
<班級 編號="des3" 年級="大一" 學校='西工大' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.example.org/student"
xsi:schemaLocation=" http://www.example.org/student student.xsd">
<學生 編號="d3" 性別="女" >
<姓名>阿嬌</姓名>
<年齡>50</年齡>
<身高>150</身高>
<體重>40</體重>
</學生>
<學生 編號="df3" 性別="男">
<姓名>薛鵬</姓名>
<年齡>55</年齡>
<身高>175</身高>
<體重>70.32</體重>
</學生>
</班級>
1.3.2. XML約束--schema 約束
- schema約束:
- schema和DTD的對比(面試題):
- schema符合XML的語法結(jié)構(gòu)。
- DOM、SAX 可以很好地解析schema文檔。
- schema對名稱空間支持的好。
- schem支持更多的數(shù)據(jù)類型,自定義的數(shù)據(jù)類型。
- schema和DTD的對比(面試題):
* 預先定義元素和屬性
* schema的后綴名是.xsd
* 必須只能有一個根節(jié)點,名稱是schema。
- 開發(fā)步驟
開發(fā)schema的約束文檔
-
schema文檔聲明
<schema xmlns ="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.cn/1110" elementFormDefault="qualified" > -
引入W3C的名稱
- 在根節(jié)點上schema,使用屬性xmlns (全稱: xml namespace)
- xmlns="http://www.w3.org/2001/XMLSchema"
-
起名:targetNamespace 目標名稱空間(起名)
- 值是任意的:"http://www.itcast.cn/1110" 一般為域名
- elementFormDefault
qualified(使用):質(zhì)量好的
unqualified :質(zhì)量不好的↑
- elementFormDefault
在XML文檔中的--“根標簽”---引入自己編寫的schema文檔
<根標簽 屬性1="值1" 屬性2="值2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itcast.cn/1110" xsi:schemaLocation="http://www.itcast.cn/1110 student.xsd" >
-
引入W3C名稱空間,我是實例文檔。注意多了個 -instance
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" (這里的xsi 是別名)
-
引入自己編寫的schema的文檔
xmlns="http://www.itcast.cn/1110" xsd文檔中的 targetNamespace 內(nèi)容
-
問題:元素上不能有相同的屬性名稱
- 解決:起別名 :aa
- 技巧:在下面出現(xiàn)標簽的概率小起別名
-
引入自己編寫的schema文檔的地址
-
schemaLocation屬性是W3C提供的,如果W3C名稱空間要是有別名的話,先把別名寫上。
xsi:schemaLocation="名稱空間 schema文件的地址"-
名稱空間的概念
- 編寫完schema文檔,起唯一的名稱空間。
- 在編寫XML文檔,通過xmlns來引入名稱空間。
當標簽為簡單標簽,沒有屬性時,簡單文本的類型可直接在 主標簽中定義
<element name="name" type="double"></element>
表示標簽名為 name,標簽內(nèi)內(nèi)容為double 類型-
當標簽有屬性,不包含子標簽時,也必須設置成complexType,
且attribute屬性必須在文本類型標簽extension內(nèi),<element name="name"> <complexType> <simpleContent> <extension base="string"> <attribute name="salary" type="double" use="required"></attribute> <!-- attribute位置--> </extension> </simpleContent> </complexType> </element> 當標簽有屬性,且包含子標簽時, 需要Sequence/choice/all標簽,attribute標簽必須在sequence結(jié)束標簽和complexType標簽之間,
<element name="父標簽"> <complexType> <sequence> <element name="子標簽1"></element> <element name="子標簽2"></element> <element name="子標簽3"></element> </sequence> <attribute name="身高" ></attribute> <!-- attribute位置--> </complexType> </element> -
-
student.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/student"
xmlns:tns="http://www.example.org/student" elementFormDefault="qualified">
<element name="班級" >
<complexType>
<sequence>
<element name="學生" maxOccurs="2">
<complexType>
<sequence>
<element name="姓名" type="string"></element>
<element name="年齡" type="int"></element>
<element name="身高" type="double"> </element>
<element name="體重" type="double"></element>
</sequence>
<attribute name="編號" type="string" use="required"> </attribute>
<attribute name="性別" type="string" use="required"> </attribute>
</complexType>
</element>
</sequence>
<attribute name="編號" type="string" use="required"></attribute>
<attribute name="年級" type="string" use= "required"></attribute>
<attribute name="學校" type="string" ></attribute>
</complexType>
</element>
</schema>
student.xml
<?xml version="1.0" encoding="utf-8" ?>
<班級 編號="des3" 年級="大一" 學校='西工大'
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.example.org/student"
xsi:schemaLocation=" http://www.example.org/student student.xsd"
>
<學生 編號="d3" 性別="女" >
<姓名>阿嬌</姓名>
<年齡>50</年齡>
<身高>150</身高>
<體重>40</體重>
</學生>
<學生 編號="df3" 性別="男">
<姓名>薛鵬</姓名>
<年齡>55</年齡>
<身高>175</身高>
<體重>70.32</體重>
</學生>
</班級>
1.4. XML 解析(重點)
1.4.1. 解析方式簡介
- 常用的有兩種?DOM和SAX
- 區(qū)別:
-
DOM解析XML
- 在內(nèi)存中形成樹狀結(jié)構(gòu)
- 缺點:如果文檔過大,容易產(chǎn)生內(nèi)存溢出的問題。
- 優(yōu)點:方便做增刪改的操作
-
SAX解析
- 基于事件驅(qū)動,邊讀邊解析
- 優(yōu)點:不會產(chǎn)生內(nèi)存溢出問題。
- 缺點:不能做增刪改操作。
-
(DOM4J在內(nèi)存生成樹狀結(jié)構(gòu),但是很少出現(xiàn)內(nèi)存溢出,故一般使用 DOM4J 解析 xml)
1.4.1.1. DOM(JAXP Crimson解析器)
DOM是用與平臺和語言無關的方式表示XML文檔的官方W3C標準。DOM是以層次結(jié)構(gòu)組織的節(jié)點或信息片斷的集合。這個層次結(jié)構(gòu)允許開發(fā)人員在樹中尋找特定信息。分析該結(jié)構(gòu)通常需要加載整個文檔和構(gòu)造層次結(jié)構(gòu),然后才能做任何工作。由于它是基于信息層次的,因而DOM被認為是基于樹或基于對象的。DOM以及廣義的基于樹的處理具有幾個優(yōu)點。首先,由于樹在內(nèi)存中是持久的,因此可以修改它以便應用程序能對數(shù)據(jù)和結(jié)構(gòu)作出更改。它還可以在任何時候在樹中上下導航,而不是像SAX那樣是一次性的處理。DOM使用起來也要簡單得多。
1.4.1.2. SAX
SAX處理的優(yōu)點非常類似于流媒體的優(yōu)點。分析能夠立即開始,而不是等待所有的數(shù)據(jù)被處理。而且,由于應用程序只是在讀取數(shù)據(jù)時檢查數(shù)據(jù),因此不需要將數(shù)據(jù)存儲在內(nèi)存中。這對于大型文檔來說是個巨大的優(yōu)點。事實上,應用程序甚至不必解析整個文檔;它可以在某個條件得到滿足時停止解析。一般來說,SAX還比它的替代者DOM快許多。
選擇DOM還是選擇SAX? 對于需要自己編寫代碼來處理XML文檔的開發(fā)人員來說, 選擇DOM還是SAX解析模型是一個非常重要的設計決策。 DOM采用建立樹形結(jié)構(gòu)的方式訪問XML文檔,而SAX采用的事件模型。
各自的優(yōu)點/缺點:
DOM解析器把XML文檔轉(zhuǎn)化為一個包含其內(nèi)容的樹,并可以對樹進行遍歷。用DOM解析模型的優(yōu)點是編程容易,開發(fā)人員只需要調(diào)用建樹的指令,然后利用navigation APIs訪問所需的樹節(jié)點來完成任務??梢院苋菀椎奶砑雍托薷臉渲械脑?。然而由于使用DOM解析器的時候需要處理整個XML文檔,所以對性能和內(nèi)存的要求比較高,尤其是遇到很大的XML文件的時候。由于它的遍歷能力,DOM解析器常用于XML文檔需要頻繁的改變的服務中。
SAX解析器采用了基于事件的模型,它在解析XML文檔的時候可以觸發(fā)一系列的事件,當發(fā)現(xiàn)給定的tag的時候,它可以激活一個回調(diào)方法,告訴該方法制定的標簽已經(jīng)找到。SAX對內(nèi)存的要求通常會比較低,因為它讓開發(fā)人員自己來決定所要處理的tag。特別是當開發(fā)人員只需要處理文檔中所包含的部分數(shù)據(jù)時,SAX這種擴展能力得到了更好的體現(xiàn)。但用SAX解析器的時候編碼工作會比較困難,而且很難同時訪問同一個文檔中的多處不同數(shù)據(jù)。
1.4.1.3. JDOM
JDOM的目的是成為Java特定文檔模型,它簡化與XML的交互并且比使用DOM實現(xiàn)更快。由于是第一個Java特定模型,JDOM一直得到大力推廣和促進。正在考慮通過“Java規(guī)范請求JSR-102”將它最終用作“Java標準擴展”。從2000年初就已經(jīng)開始了JDOM開發(fā)。
JDOM與DOM主要有兩方面不同。首先,JDOM僅使用具體類而不使用接口。這在某些方面簡化了API,但是也限制了靈活性。第二,API大量使用了Collections類,簡化了那些已經(jīng)熟悉這些類的Java開發(fā)者的使用。
JDOM文檔聲明其目的是“使用20%(或更少)的精力解決80%(或更多)Java/XML問題”(根據(jù)學習曲線假定為20%)。JDOM對于大多數(shù)Java/XML應用程序來說當然是有用的,并且大多數(shù)開發(fā)者發(fā)現(xiàn)API比DOM容易理解得多。JDOM還包括對程序行為的相當廣泛檢查以防止用戶做任何在XML中無意義的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情況下的錯誤)。這也許是比學習DOM或JDOM接口都更有意義的工作。
JDOM自身不包含解析器。它通常使用SAX2解析器來解析和驗證輸入XML文檔(盡管它還可以將以前構(gòu)造的DOM表示作為輸入)。它包含一些轉(zhuǎn)換器以將JDOM表示輸出成SAX2事件流、DOM模型或XML文本文檔。JDOM是在Apache許可證變體下發(fā)布的開放源碼。
1.4.1.4. DOM4J(重點)
雖然DOM4J代表了完全獨立的開發(fā)結(jié)果,但最初,它是JDOM的一種智能分支。它合并了許多超出基本XML文檔表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文檔或流化文檔的基于事件的處理。它還提供了構(gòu)建文檔表示的選項,它通過DOM4J API和標準DOM接口具有并行訪問功能。從2000下半年開始,它就一直處于開發(fā)之中。
為支持所有這些功能,DOM4J使用接口和抽象基本類方法。DOM4J大量使用了API中的Collections類,但是在許多情況下,它還提供一些替代方法以允許更好的性能或更直接的編碼方法。直接好處是,雖然DOM4J付出了更復雜的API的代價,但是它提供了比JDOM大得多的靈活性。
在添加靈活性、XPath集成和對大文檔處理的目標時,DOM4J的目標與JDOM是一樣的:針對Java開發(fā)者的易用性和直觀操作。它還致力于成為比JDOM更完整的解決方案,實現(xiàn)在本質(zhì)上處理所有Java/XML問題的目標。在完成該目標時,它比JDOM更少強調(diào)防止不正確的應用程序行為。
DOM4J是一個非常非常優(yōu)秀的Java XML API,具有性能優(yōu)異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件。如今你可以看到越來越多的Java軟件都在使用DOM4J來讀寫XML,特別值得一提的是連Sun的JAXM也在用DOM4J。
1.4.2. 解析
1.4.2.1. JAXP 下的 DOM 解析
解析
- 獲取 DocumentBuilderFactory(解析器工廠類)對象
public static DocumentBuilderFactory newInstance(); 獲取 DocumentBuilderFactory 的新實例。
- 獲取 DocumentBuilder(解析器)對象
public abstract DocumentBuilder newDocumentBuilder() (雖然是抽象方法,但多態(tài)調(diào)用子類的實現(xiàn)方法)使用當前配置的參數(shù)創(chuàng)建一個新的 DocumentBuilder 實例。
- 解析XML文檔
public Document parse(String path) 解析XML文檔,返回Document對象
- 根據(jù)需求獲得NodeList 集合
NodeList nodeList = document.getElementsByTagName("作者");
- 遍歷NodeList集合 獲取每個Node內(nèi)的內(nèi)容
NodeList:
Node item(int index); 根據(jù)下標獲取NodeList集合中的Node對象
Node:
String getTextContent(); 獲取Node對象(標簽)中的文本內(nèi)容
for(int i=0;i<nodeList.getLength();i++){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}
示例:
解析XML(Document parse(String uri) )
// 獲取解析器工廠類
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 獲取解析器對象
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析XML的文檔,返回document對象
Document document = builder.parse("src/book2.xml");
// 獲取作者元素對象的集合,返回NodeList,注意返回的是NodeList(ELement的父類)而不是Element
NodeList nodeList = document.getElementsByTagName("作者");
// 循環(huán)遍歷,拿到每一個作者,打印文本的內(nèi)容,getTextContent()
for(int i=0;i<nodeList.getLength();i++){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}
//獲取標簽的屬性值
Document doc = JaxpDomutil.getDocument("src/book1.xml");
Node node = doc.getElementsByTagName("書").item(0);
NamedNodeMap attMap = node.getAttributes();
注意這里返回的是NamedNodeMap子類對象(實際上是屬性集合)
System.out.println("--------------------");
System.out.println(attMap.getLength());
for(int i=0;i<attMap.getLength();i++){
Node att=attMap.item(i); node ---content
System.out.println(att.getTextContent());
}
//遞歸得到 Node 中的所有節(jié)點名稱(前序遍歷)
public static void getNodeName(Node node){
if(node.getNodeType() == Node.ELEMENT_NODE){
System.out.println(node.getNodeName());
}
NodeList nodeList = node.getChildNodes();
for(int i=0;i<nodeList.getLength();i++){
Node child = nodeList.item(i);
getNodeName(child);
}
}
回寫
- 獲取回寫的工廠類
- 獲取回寫對象
- 調(diào)用回寫的方法進行回寫。
修改 document對象中的內(nèi)容之后進行回寫
// 創(chuàng)建回寫類的工廠
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// 獲取回寫類
Transformer transformer = transformerFactory.newTransformer();
// 調(diào)用回寫的方法
transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
//將獲取Document對象和 回寫封裝到方法中
public class JaxpDomutil {
public static Document getDocument(String path) throws Exception{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
return builder.parse(path);
}
public static void writeXML(Document doc,String path) throws Exception{
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult(path));
}
// 在指定的節(jié)點之前添加子節(jié)點
public static void InsertBefore(Node newNode,Node refNode){
Node parentNode = refNode.getParentNode();
parentNode.insertBefore(newNode, refNode);
}
}
1.4.2.2. JAXP 下的 SAX 解析
SAX的解析原理:
解析器采用SAX方式在解析某個XML文檔時,它只要解析到XML文檔的一個組成部分(邊讀邊解析)
都會去調(diào)用事件處理器的一個方法,解析器在調(diào)用事件處理器的方法時,
會把當前解析到的xml文件內(nèi)容作為方法的參數(shù)傳遞給事件處理器。
事件處理器由程序員編寫,程序員通過事件處理器中方法的參數(shù),
就可以很輕松地得到sax解析器解析到的數(shù)據(jù),從而可以決定如何對數(shù)據(jù)進行處理。
解析過程
- 獲取解析器的工廠
SAXParserFactory saxParseFactory = SAXParserFactory.newInstance();
- 獲取解析器對象
SAXParser saxParser = saxParseFactory.newSAXParser();
- 解析XML(XML的文件的地址,事件處理器)
saxParser.parse(path,new MyHandler()); // 其中MyHandler() 繼承自DefaultHandler()
-
事件處理器(DefaultHandler)?
自己編寫的類MyHandler(),需要繼承DefalutHandler類,重寫三個方法。- startElement(qName) 開始標簽名
- characters(char[] ch,int start,int length) 標簽內(nèi)部文本內(nèi)容
- endElement(qName) 結(jié)束標簽名
通過傳進來的參數(shù)qName、char[] 、qName 獲取開始標簽內(nèi)容、文本內(nèi)容、結(jié)束標簽內(nèi)容
1.4.3. DOM4j
- DOM4J的解析(必須會,企業(yè)中用的多)
- 先下載DOM4J相應的jar包。導入工程中,才能使用。
- 把dom4j-1.6.1.jar導入到工程中。
- WEB項目:復制dom4j-1.6.1.jar到 WebRoot -- WEB-INF -- lib里面。就ok。
- Java項目:右鍵工程項目,選擇Build Path
解析過程
- 獲取解析器對象
SAXReader saxReader=new SAXReader();
- 解析獲取Document對象
Document doc = saxReader.read("src/book1.xml");
- 獲取文檔根結(jié)點
Element root = doc.getRootElement();
DOM4j中,獲得Document對象的方式有三種:
- 讀取XML文件,獲得document對象
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));
- 解析XML形式的文本,得到document對象.
String text = "<members></members>";
Document document = DocumentHelper.parseText(text);
- 主動創(chuàng)建document對象.
Document document = DocumentHelper.createDocument(); //創(chuàng)建根節(jié)點
Element root = document.addElement("members");
節(jié)點方法
- 獲取文檔的根節(jié)點.
Element root = document.getRootElement();
- 取得某個節(jié)點的子節(jié)點.
Element element=root.element("書名");
- 取得節(jié)點的文本內(nèi)容
String text=node.getText();
- 取得某節(jié)點下所有名為“member”的子節(jié)點,并進行遍歷.
List nodes = rootElm.elements("member"); -->獲取所有子元素結(jié)點
for (Iterator it = nodes.iterator(); it.hasNext();) {
Element elm = (Element) it.next();
// do something
}
- 對某節(jié)點下的所有子節(jié)點進行遍歷.
for(Iterator it=root.elementIterator();it.hasNext();){
Element element = (Element) it.next();
// do something??
}
- 在某節(jié)點下添加子節(jié)點.
Element ageElm = newMemberElm.addElement("age");
(可通過父結(jié)點root添加
List<Element> eles = root.elements();
Element newEle=DocumentHelper.createElement("age");
newEle.setText("16");
eles.add(1,newEle); -->插入子節(jié)點集合中的1位置
)
- 設置節(jié)點文字.
element.setText("29");
- 刪除某節(jié)點.
parentElm.remove(childElm); //childElm是待刪除的節(jié)點,parentElm是其父節(jié)點
- 添加一個CDATA節(jié)點.
Element contentElm = infoElm.addElement("content");
contentElm.addCDATA(diary.getContent());
屬性方法:
attribute.getQualifiedName() getValue()/getText()
屬性名 屬性值
- 取得某節(jié)點下的某屬性
Element root=document.getRootElement(); //屬性名name
Attribute attribute=root.attribute("size");
- 取得屬性的文字
String text=attribute.getText();
- 刪除某屬性
Attribute attribute=root.attribute("size");
root.remove(attribute);
- 遍歷某節(jié)點的所有屬性
Element root=document.getRootElement();
方法一:推薦
for(int i=0;i<root.attributeCount();i++){
Attribute attribute = root.attribute(i);
System.out.println(attribute.getQualifiedName()+"\""+attribute.getValue+"\"");
}
方法二:
for(Iterator it=root.attributeIterator();it.hasNext();){
Attribute attribute = (Attribute) it.next();
String text=attribute.getText();
System.out.println(text);
}
- 設置某節(jié)點的屬性和文字.
newMemberElm.addAttribute("name", "sitinspring");
- 設置屬性的文字
Attribute attribute=root.attribute("name"); ---> 獲取屬性名為 name 的屬性對象
attribute.setText("sitinspring"); ---> 設置屬性值
將文檔寫入XML
- 文檔中全為英文,不設置編碼,直接寫入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();
- 文檔中含有中文,設置編碼格式寫入的形式.
OutputFormat format = OutputFormat.createPrettyPrint(); // 指定XML編碼
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);
writer.write(document);
writer.close();
字符串與XML的轉(zhuǎn)換
- 將字符串轉(zhuǎn)化為XML
String text = "<members> <member>sitinspring</member></members>";
Document document = DocumentHelper.parseText(text);
2.將文檔或節(jié)點的XML轉(zhuǎn)化為字符串.
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));
String docXmlText=document.asXML(); --> 將XML文檔轉(zhuǎn)換成XML格式的字符串
Element root=document.getRootElement();
String rootXmlText=root.asXML(); --> 將根結(jié)點轉(zhuǎn)換成XML格式的字符串
Element memberElm=root.element("member");
String memberXmlText=memberElm.asXML(); --> 將元素結(jié)點轉(zhuǎn)換成XML格式的字符串
- DOM4J對XPATH的支持
導入包。jaxen-1.1-beta-6.jar。
怎么使用?
selectNodes("/AAA") 返回集合
selectSingleNode() 一個Node對象-
參數(shù)就是xpath的語法
/ 考慮層級關系 / / 不考慮層級關系/AAA/BBB 獲取BBB的節(jié)點 //AAA/BBB A不考慮層級,B考慮層級 / /BBB 無論層級關系,找到BBB的節(jié)點 * 代表是所有 /AAA/BBB[1] 找到BBB的第一個 /AAA/BBB[last()] 最后一個 上面這種只能用單斜線 不能用雙斜線 @ 屬性 /*/*/*/BBB 代表三層標簽下的 BBB標簽
將文檔寫入XML
1.文檔中全為英文,不設置編碼,直接寫入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();
2.文檔中含有中文,設置編碼格式寫入的形式.
OutputFormat format = OutputFormat.createPrettyPrint();?// 指定XML編碼????? ????????????
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);
writer.write(document);
writer.close();
1.4.4. Pull解析
與Sax一樣.都屬于事件驅(qū)動的解析方式.
相比Sax解析過程更加靈活.
sax一旦開始解析就是從頭讀到尾.不解析完整個文檔不會停
pull解析較為靈活.是以事件為單位.手動向下繼續(xù). 如果獲得到我們要找的內(nèi)容. 可以停止繼續(xù)解析.
缺點:只能進行查詢,不能做增刪改
public static List<Student> parseXML(InputStream is) throws Exception{
//1:創(chuàng)建解析器工廠
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//2:使用工廠獲得解析器
XmlPullParser parser = factory.newPullParser();
//3: 使用解析器讀取XML流
parser.setInput(is, "UTF-8");
//4: 獲得當前事件的狀態(tài)
int type = parser.getEventType();
List<Student> list =null;
Student stu = null;
//5:判斷當前事件狀態(tài)
while(type!=XmlPullParser.END_DOCUMENT){
switch(type){
case XmlPullParser.START_TAG:
if("students".equals(parser.getName())){
list = new ArrayList<Student>();
}else if("student".equals(parser.getName())){
stu = new Student();
}else if("name".equals(parser.getName())){
String name = parser.nextText();
stu.setName(name);
}else if("age".equals(parser.getName())){
int age = Integer.parseInt(parser.nextText());
stu.setAge(age);
}else if("height".equals(parser.getName())){
double height = Double.parseDouble(parser.nextText());
stu.setHeight(height);
}
break;
case XmlPullParser.END_TAG:
if("student".equals(parser.getName())){
list.add(stu);
stu = null;
}
break;
default:
break;
}
//讓解析器向下解析一行,并返回改行的事件常量
type = parser.next();
}
return list;
}