天天看點

xml基礎知識

XML(eXtensible Markup Language)是網際網路聯盟(World Wide Web Consortium W3C)定義的一種可擴充标志語言。

可擴充性指允許使用者按照XML規則自定義标記(tags 标簽)。

強項:輕松表達多層結構的資料;可擴充。

優點:平台無關,語言無關。設計目标是描述資料并集中于資料的内容,與顯示分離。

提醒:不能用XML來直接寫網頁。即便是包含了XML資料,依然要轉換成HTML格式才能在浏覽器上顯示。

文法規則:

XML檔案有且僅有一個根标記,其他标記必須封裝在根标記中,檔案的标記必須形成樹狀結構。

大小寫敏感。

标記的屬性必須用""或''括起來。

XML細節:

一、 聲明

大多數XML文檔以XML聲明作為開始,它向解析器提供了關于文檔的基本資訊。

建議使用XML聲明,但它不是必需的。如果有的話,那麼它一定是文檔的第一行内容。

如:<?xml version="1.0" encoding="UTF-8" standalone="no"?>

聲明最多可以包含三個名稱-值對(許多人稱它們為屬性,盡管在技術上它們并不是)。

<?xml 問号與xml之間不能有空格。

1)version 是使用的XML 版本:1.0, 1.1

2)encoding 是該文檔所使用的字元集。該聲明中引用的ISO-8859-1 字元集包括大多數西歐語言用到的所有字元。

預設字元在UTF-8字元集中,這是一個幾乎支援世界上所有語言的字元和象形文字的Unicode 标準。

3)standalone(可以是yes 或no)定義了是否孤立處理該文檔。

如果XML文檔沒有引用任何其它檔案,則可以指定 standalone="yes"。

如果XML文檔引用其它描述該文檔可以包含什麼的檔案(如DTD),則 standalone="no"。預設值為"no"

二、 标記

左尖括号“<“和右尖括号“>“之間的文本

1. 在< >中的稱為開始标記;在</ >中的稱為結束标記

2. 空标記:不包含元素的标記。空标簽必須以“/>”結束。格式: <空标記的名稱/> <空标記的名稱 屬性清單/>

注意:

除空标記外,标簽必須成對:有始有終。所有的開始标簽和結束标簽必須比對。

在标記符“<“和"标記的名稱"之間不能含有空格。在标記符"/>"前面可以有空格或回行。

标簽必須嵌套正确。

XML标記必須遵循下面的命名規則:

 1.名字中可以包含字母、數字以及其它字母或文字;還可包含下劃線(_)、點(.)、連字元(-)

 2.名字不能以數字開頭;可以用字母、文字或者下劃線開頭。

 3.名字不能以字母xml (或XML 或Xml ..) 開頭;

 4.名字中不能包含空格。

三、 元素

位于開始标記與結束标記間

一份文檔有且隻有一個根元素。

根元素下的所有元素叫“子元素”。

不包含自子元素的元素叫“葉子”;包含子元素的元素叫“分支”。

如: <eric>…… </eric>

四、 屬性

一個元素的開始标志中的名稱-值對

所有的屬性值必須位于單引号或雙引号中。

每一個元素的屬性不允許出現超過一次。

開始标志内,類似指派語句

如:<eric age="80">……</eric>

五、 注釋

注釋可以出現在文檔的任何位置。(但不建議放在聲明前面,部分浏覽器會報錯)

注釋以 <!-- 開始,以 --> 結束。

注釋内不能包含雙連字元(--);除此之外,注釋可以包含任何内容。

注釋内的任何标記都被忽略

六、 處理指令

處理指令是為使用一段特殊代碼而設計的标記,簡稱為PI。

大多數XML 文檔都是以XML 聲明開始,該聲明本身就是特殊的處理指令。

處理指令對應用程式特定的資料進行編碼。一條處理指令包含一個目标,後跟資料。用<?和?>定界符将處理指令包起來。

目标确定應用程式,而對應用程式不能識别的目标,其會忽略這些處理指令。

七、 實體

XML 規範預定義了五個實體。

< ==== <

> ==== >

" ==== ”

' ==== ‘

& ==== &

自定義實體:在DTD中定義 <!ENTITY 實體标志 "實體内容">

在xml中引用自定義實體,用 &實體标志; 代表實體内容。

另外,無法從鍵盤輸入的字元可以使用字元引用,就是用字元的Unicode代碼點來引用該字元。

以"&#x"開始字元引用,以分号結尾,x必須為小寫,使用十六進制。如: = 表示等于号。

也可以使用字元引用來引用 <,>,',",& "

檢視字元的代碼點(附件-> 系統工具-> 字元映射表)。

八、 CDATA

當一段文本中出現很多實體引用和字元引用時,會導緻文本資料的讀寫困難,CDATA段就是為了解決這一問題引入的。

DATA區段開始于 "<![CDATA[" 結束于 "]]>"

CDATA内部的所有東西都會被解析器忽略解析,不用檢查它的格式。

但是CDATA段中不能嵌套另一個CDATA段。

九、 屬性

屬性是标記的屬性,可以為标記添加附加資訊。

(1)屬性的組成

屬性是一個名值對,必須由名稱和值組成,屬性必須在标記的開始标記或空标記中聲明,用"="為屬性指定一個值。

文法如下:

<标記名稱 屬性清單/>

<标記名稱 屬性清單>XXX</标記名稱>

例如: <桌子 width="40" height='100'/>

(2)使有屬性的原則

屬性不展現資料的結構,隻是資料的附加資訊;

一個資訊是作為一個标記的屬性或子标記,取決于具體問題,不要因為屬性的頻繁使用破壞XML的資料結構。

下面是一個結構清晰的XML檔案:

<樓房 height="23m" width="12m">

<結構>混凝土</結構>

<類别>商用</類别>

</樓房>

下面是一個結構不清晰的XML檔案:

<樓房 height="23m" width="12m" 結構="混凝土" 建築商="華海集團" 類别="商用"></樓房>

十、 名稱空間/包

XML檔案允許自定義标記,是以可能出現同名字的标記,為了區分這些标記,就需要使用名稱空間。

名稱空間的目的是有效的區分相同的标記,其實并不真實存在。

文法: 聲明有字首的名稱空間 xmlns:字首名=名稱空間的名字

聲明無字首的名稱空間 xmlns=名稱空間的名字 (預設)

注意:當且僅當它們的名字相同時稱二個名稱空間相同,也就是說,對于有字首的名稱空間,如果二個名稱空間的名字相同,即使字首不相同,也是相同的名稱空間,返之同然。字首隻是友善引用而已。

基本術語

一、序言Prolog:包括XML聲明(XML Declaration)和文檔類型聲明(Document Type Declaration)。

二、良構(well-formed 規範的):符合W3C定義的XML文檔。

驗證

為什麼需要驗證?

對XML檔案施加額外的限制,以便交流。

一、DTD驗證

文檔類型定義(Document Type Definition)

DTD定義了XML文檔内容的結構,保證XML以一緻的格式存儲資料。精确的定義詞彙表,對XML的内容施加限制。

符合DTD的規範XML文檔稱為有效的文檔。由DTD定義的詞彙表以及文檔文法,XML解析器可以檢查XML文檔内容的有效性。

規範的XML檔案不一定是有效的;有效的一定是規範的。

1、 DTD聲明

1) DTD聲明可以在單獨的一個檔案中

2) DTD聲明可以内嵌在XML檔案中

3) DTD聲明可以一部分在單獨的檔案中,另一部分内嵌在XML檔案中

2、 引入外部DTD檔案

<!DOCTYPE data SYSTEM "Client.dtd">

Data:根節點名稱

Client.dtd:dtd檔案路徑

3、 DTD四種标記聲明

元素(ELEMENT)、屬性(ATTLIST)、實體(ENTITY)、符号(NOTATION)

1) 元素(ELEMENT) XML元素類型聲明

聲明元素: <!ELEMENT elementName (contentModel)>

元素的内容通過内容模式來描述。

DTD 内容模式的種類有:

EMPTY 元素不能包含任何資料,但可以有屬性(前提是必須聲明其屬性)。

不能有子元素。不能有文本資料(包括空白,換行符)。

DTD中定義: <!ELEMENT elementName EMPTY>

XML中:<elementName/>(推薦) 或者:<elementName></elementName>

(#PCDATA) 規定元素隻包含已析的字元資料,而不包含任何類型的子元素的内容類型。

DTD中定義: <!ELEMENT student (#PCDATA)>

XML中合法内容: <student>watching TV</student>

(Elements) 元素由内容模式部件指定。

<!ELEMENT name (child particles) >

内容模式部件可以是下表列出的内容。

<!ELEMENT name (a,b)> 子元素a、b必須出現,且按照清單的順序

<!ELEMENT name (a|b)> 選擇;子元素a、b隻能出現一個

<!ELEMENT name (a) > 子元素a隻能且必須出現一次

<!ELEMENT name (a)+ > 子元素a出現一次或多次

<!ELEMENT name (a)* > 子元素a出現任意次(包括零次、一次及多次)

<!ELEMENT name (a)? > 子元素a出現一次或不出現

Mixed 混合模式:子元素中既可有文本資料又可有下級子元素。

<!ELEMENT rn (#PCDATA| an | en)*>“|”和“*”必須寫。

上句表示在 rn 内,字元資料 或 en及an 可以出現任意多次,順序不限。

優先寫(#PCDATA) 如:(#PCDATA|name)* 正确 (name|#PCDATA)* 錯誤

ANY 元素可以包含任何類型的資料。子元素(必須在DTD中有定義) 和 文本資料(包括空白)。

DTD中定義: <!ELEMENT a ANY> <!ELEMENT b ANY>

XML中合法内容: <a>somngthing</a> 或者 <a/> 或者 <a><b>oo</b></a>

2) 屬性(ATTLIST) 特定元素類型可設定的屬性&屬性的允許值聲明

<!ATTLIST elementName

attributeName1 attributeType attributeDefault

.......

attributeNameN attributeType attributeDefault>

屬性類型 (Attribute Type):

CDATA該屬性隻能包含字元資料(注意與CDATA段、PCDATA的差別)

NMTOKEN 是CDATA的子集,它的字元隻能是字母,數字,句點,破折号,下劃線或冒号。

NMTOKENS 類似NMTOKEN,但這個可以包含多個值,每個值之間用空格隔開。

ID 該屬性的取值在同一文檔内是唯一的。一個元素隻能有一個ID類型的屬性。

IDREF 類似指針,指向文檔中其他地方聲明的ID值。如果該屬性取值和指向的ID值不比對,則傳回錯誤。

IDREFS 類似IDREF,但它可以具有由空格分隔開的多個引用。

ENTITY 該屬性的值必須對應一個在文檔内部聲明的但還沒有分析過的實體。

ENTITYS 類似ENTITY,但它可以包含由空格分隔開的多個實體。

NOTATION 該屬性的值必須引用在文檔中其他地方聲明的某個注釋的名稱。

(enumerated) 類似枚舉的變量,該屬性必須比對所列的值。各值用“|”分隔開。

如: (春|夏|秋|冬) 實際内容文檔隻能從中取一個。

屬性特性 (Attribute Default) :

#REQUIRED 必須有且隻能有一個屬性。

#IMPLIED 可有可無。

#FIXED 在DTD中定義預設值,XML中可以不指定,指定則必須等于該預設值。

attribute-value 如果不指定則用DTD定義的預設值,指定則用指定的值。

<![CDATA[############ 屬性(ATTLIST)的舉例 ############## ]]>

例一(#REQUIRED)

DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at1 NMTOKENS #REQUIRED at2 CDATA #REQUIRED>

XML中,正确: <el at1 = "10 20" at2="10" >something</el>

XML中,錯誤: <el at="10">something</el> (沒有寫另一個#REQUIRED的屬性 at2 )

例二(#IMPLIED,#FIXED)

DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA #FIXED "10" at2 CDATA #IMPLIED >

XML中,正确: <el at2="20" >something</el> (at有預設值"10",at2 可寫可不寫)

XML中,錯誤: <el at="11" >something</el>(at要麼不寫,要寫隻能寫成跟預設值相同的)

例三(attribute-value)

DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA "10" at2 CDATA "20" >

XML中,正确: <el at="11" >something</el>

例四(enumerated + attribute-value)

DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at (10|20|30) "10">

XML中,正确: <el at="20">something</el> (at要麼不寫,預設值 10;要麼在(10|20|30)中選一個寫)

<![CDATA[############ 屬性(ATTLIST)舉例 完畢 ############## ]]>

3) 實體(ENTITY) 可重用的内容聲明

在DTD中定義 <!ENTITY 實體标志 "實體内容">

在xml中引用自定義的實體,用 &實體标志; 代表實體内容。

4) 符号(NOTATION) 不要解析的外部内容的格式聲明。

3、 内部實體:在xml檔案裡面寫(少用)

外部實體:另外在xml同一檔案夾下建立一個dtd檔案(提倡)

<!--**************** 内外部的實體舉例 ***************** -->

外部的:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!DOCTYPE root SYSTEM "goodsInfo.dtd"><!--用這句引用外部dtd-->

<root><goodsInfo>

<goodsName>goodsName</goodsName>

<goodsPrice>goodsPrice</goodsPrice>

</goodsInfo></root>

以下是名為"goodsInfo.dtd"檔案

<!ELEMENT root (goodsInfo)>

<!ELEMENT goodsInfo (goodsName,goodsPrice)>

<!ELEMENT goodsName (#PCDATA)>

<!ELEMENT goodsPrice (#PCDATA)>

内部的:

<?xml version="1.0"?>

<!DOCTYPE root [

<!ELEMENT root(student)>

<!ELEMENT student (#PCDATA)>

<!ENTITY CCTV "中央電視台">

]> <!--把DTD檔案寫在體内-->

<root><student>

student watch &CCTV;<!--使用自定義實體 CCTV-->

</student></root>

<!--***************** 内外部的實體舉例 完畢 ********************** -->

XML處理模式

一、 DOM 文檔對象模式

1.DOM特點:

以樹型結構通路XML文檔。 一棵DOM樹包含全部元素節點和文本節點。可以前後周遊樹中的每一個節點。

整個文檔樹在記憶體中,便于操作;支援删除、修改、重新排列等多種功能。

将整個文檔調入記憶體(包括無用的節點),浪費時間和空間。

一旦解析了文檔還需多次通路這些資料;硬體資源充足(記憶體、CPU)情況下使用。

2.DOM樹與節點

XML文檔被解析成樹型結構。

樹由節點組成。共有12種不同的節點。

節點可以包含其他節點(依賴于節點的類型)。

父節點包含子節點。葉子節點沒有子節點。

3.節點類型

Document node 包含:一個根Element節點。一個或多個處理指令節點。

Document Fragment node

Element node包含:其他Element節點。若幹個Text節點。若幹個Attribute節點。

Attribute node 包含:一個Text節點。

Text node

Comment node

Processing instruction node

Document type node

Entity node

Entity reference node

CDATA section node

Notation node

二、 SAX 基于事件處理模式

解析器向一個事件處理程式發送事件,比如元素開始和元素結束,而事件處理器則處理該資訊。

然後應用程式本身就能夠處理該資料。原始的文檔仍然保留完好無損。

<![CDATA[################## SAX處理器(周遊XML) ###########################]]>

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.SAXParseException;

import org.xml.sax.helpers.DefaultHandler;

public class TestSAXParser {

/** 基于SAX方式解析XML文檔 */

public static void main(String[] args)

throws SAXException,ParserConfigurationException,IOException{

SAXParserFactory factory = SAXParserFactory.newInstance(); //建立SAX解析器工廠

factory.setValidating(true); //讓error方法生效

SAXParser parser = factory.newSAXParser(); //生成一個具體的SAX解析器

parser.parse("src/file/student.xml",new XMLreader()); //開始解析

}}

class XMLreader extends DefaultHandler {

// 隻需覆寫我們感興趣的方法

private int counter = 0;// 定義一個計數器,儲存XML文檔觸發事件的次數

@Override // 文檔開始事件觸發

public void startDocument() throws SAXException {

counter++;

System.out.println(counter + ".解析XML檔案開始...");}

@Override // 文檔結束事件觸發

public void endDocument() throws SAXException {

System.out.println("\r\n"+counter + ".解析XML檔案結束...");}

@Override // 元素開始事件觸發

public void startElement(String uri, String localName, String qName,

Attributes atts) throws SAXException {

System.out.print(counter+".<"+qName);

for(int i=0; i<atts.getLength();i++){ //讀取标志的所有屬性

System.out.print(" "+atts.getLocalName(i)+"="+atts.getValue(i));

}System.out.print(">"); }

@Override // 元素結束事件觸發

public void endElement(String uri, String localName, String qName) throws SAXException {

System.out.print(counter +".</"+qName+">");}

@Override // 文本事件觸發 列印時盡量不要換行,否則很難看

public void characters(char[] ch, int start, int length)throws SAXException {

String text = new String(ch, start, length); // 目前元素的文本值

System.out.print(counter + ".Text=" + text);}

@Override //這是可恢複錯誤。需在SAXParserFactory設定有效性錯誤才能生效

public void error(SAXParseException e) throws SAXException {

System.out.println("xml文檔有效性錯誤:"+e);}

@Override //嚴重錯誤

public void fatalError(SAXParseException e) throws SAXException {

System.out.println("xml文檔嚴重的有效性錯誤:"+e);}

}

<![CDATA[################## SAX處理器(周遊XML)結束 ###########################]]>

三、 DOM

<![CDATA[######################### DOM周遊方式 ###########################]]>

import java.io.File;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NamedNodeMap;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

/**基于DOM的解析XML文檔*/

public class TestDOMParser {

throws ParserConfigurationException,SAXException,IOException{

//建立一個DOM解析器工廠

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

//從工廠中生成一個DOM解析器; throws ParserConfigurationException

DocumentBuilder builder = factory.newDocumentBuilder();

//綁定需要解析的XML檔案

File xmlFile = new File("src/file/student.xml");//相對位址,相對于這個工程

//開始解析 ;throws SAXException,IOException

Document document = builder.parse(xmlFile);

//取出唯一的根元素

Element rootElement = document.getDocumentElement();

//調用業務方法: 周遊根元素

printElement(rootElement);

/** 周遊元素,包含: 子元素、屬性、文本内容 */

private static void printElement(Element e){

//列印出元素的标簽名

System.out.print("<"+e.getTagName());

//擷取開始标簽的屬性

NamedNodeMap attMap = e.getAttributes();

//循環周遊所有的屬性

for (int i=0;i<attMap.getLength();i++){

Attr attr = (Attr)attMap.item(i);

System.out.print(" "+attr.getName()+"=\""+attr.getValue()+"\"");}

System.out.print(">");

//擷取目前元素的所有子節點

NodeList nl = e.getChildNodes();

for (int j=0;j<nl.getLength();j++){

Node n = nl.item(j);

if (Node.ELEMENT_NODE==n.getNodeType()){

printElement((Element)n);//遞歸調用,以周遊下一個元素

} else {

System.out.print(n.getTextContent());

//列印結束标簽

System.out.print("</"+e.getTagName()+">");

<![CDATA[ ###################### DOM周遊 完畢 ##########################]]>

比較DOM與SAX:

DOM:處理大型檔案時其性能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構占用的記憶體較多,而且DOM必須在解析檔案之前把整個文檔裝入記憶體,适合對XML的随機通路

優點:1.提供随機定義元素操作,來回移動指針

2.将整個XML檔案一次性加載到記憶體,形成虛的記憶體樹

缺點:1.如果XML檔案較大,記憶體空間占用較大

2.強制将較大的XML檔案加載到記憶體中,有可能損害檔案

3.功能通用性

SAX:不同于DOM,SAX是事件驅動型的XML解析方式。它順序逐行讀取XML檔案,不需要一次全部裝載整個檔案。當遇到像檔案開頭,文檔結束,或者标簽開頭與标簽結束時,它會觸發一個事件,使用者通過在其回調事件中寫入處理代碼來處理XML檔案,适合對XML的順序通路