1 XML文檔結構 html
1.1 簡介 git
XML 指可擴展標記語言(eXtensible Markup Language)。XML 被設計用來傳輸和存儲數據。其很是像HTML的標記語言,但與之不一樣的是,XML是用來傳輸和存儲數據;而HTML是用來顯示數據;同時XML 標籤沒有被預約義,須要自行定義標籤,而HTML的標籤是有明確的語義的。 github
XML 文檔必須包含根元素。該元素是全部其餘元素的父元素。XML 文檔中的元素造成了一棵文檔樹。這棵樹從根部開始,並擴展到樹的最底端。全部的元素均可以有子元素。 數組
圖 4 網絡
1 <?xml version=
"
1.0
" encoding=
"
ISO-8859-1
"?>
2 <bookstore>
3 <book category=
"
CHILDREN
">
4 <title>Harry Potter</title>
5 <author>J K. Rowling</author>
6 <year>
2005</year>
7 <price>
29.99</price>
8 </book>
9 <book category=
"
WEB
">
10 <title>Learning XML</title>
11 <author>Erik T. Ray</author>
12 <year>
2003</year>
13 <price>
39.95</price>
14 </book>
15 </bookstore>
1.2 語法規則 架構
XML 的語法規則很簡單,且頗有邏輯。這些規則很容易學習,也很容易使用。XML文檔的基本架構能夠分爲下面幾個部分: 框架
1) 聲明 less
如上述的<?xml version="1.0" encoding="ISO-8859-1"?>就是XML的聲明,它定義了XML文件的版本和使用的字符集,這裏爲1.0版,使用字符集爲ISO-8859-1。 ide
2) 根元素 函數
XML 文檔必須有一個元素是全部其餘元素的父元素。該元素稱爲根元素。
3) 子元素
XML 元素指的是從(且包括)開始標籤直到(且包括)結束標籤的部分。一個元素能夠包含:
4) 屬性
屬性(Attribute)提供有關元素的額外信息,屬性定義在開始標籤之中,而且屬性值必須被引號包圍,不過單引號和雙引號都可使用:
<file type=
"
gif
">computer.gif</file>
5) 命名空間
在 XML 中,元素名稱是由開發者定義的,當兩個不一樣的文檔使用相同的元素名時,就會發生命名衝突。爲了不這種元素名稱衝突,因此引入了命名空間,命名空間是在元素的開始標籤的 xmlns 屬性中定義的。命名空間聲明的語法以下。xmlns:前綴="URI"。
1 <root>
2
3 <h:table xmlns:h=
"
http://www.w3.org/TR/html4/
">
4 <h:tr>
5 <h:td>Apples</h:td>
6 <h:td>Bananas</h:td>
7 </h:tr>
8 </h:table>
9
10 <f:table xmlns:f=
"
http://www.w3cschool.cc/furniture
">
11 <f:name>African Coffee Table</f:name>
12 <f:width>
80</f:width>
13 <f:length>
120</f:length>
14 </f:table>
15
16 </root>
在上面的實例中,<table> 標籤的 xmlns 屬性定義了 h: 和 f: 前綴的合格命名空間。當命名空間被定義在元素的開始標籤中時,全部帶有相同前綴的子元素都會與同一個命名空間相關聯。
1.3 注意規則
1) 全部的 XML 元素都必須有一個關閉標籤
在XML 中,省略關閉標籤是非法的。全部元素都必須有關閉標籤,而且有兩種:顯示和非顯示的
<p>This
is a paragraph.</p>
<br />
2) XML 標籤對大小寫敏感
XML 標籤對大小寫敏感。標籤 <Letter> 與標籤 <letter> 是不一樣的。必須使用相同的大小寫來編寫開始標籤和關閉標籤。
3) 實體引用
在XML 中,一些字符擁有特殊的意義。若是您把字符 "<" 放在 XML 元素中,會發生錯誤,這是由於解析器會把它看成新元素的開始。爲了不這個錯誤,請用實體引用來代替 "<" 字符:
在XML中,有 5 個預約義的實體引用:
< |
< |
less than |
> |
> |
greater than |
& |
& |
ampersand |
' |
' |
apostrophe |
" |
" |
quotation mark |
4) XML 中的註釋
在 XML 中編寫註釋的語法與 HTML 的語法很類似。
<!-- This
is a comment -->
5) 在 XML 中,空格會被保留
HTML 會把多個連續的空格字符裁減(合併)爲一個,而在 XML 中,文檔中的空格不會被刪減。
6) XML 以 LF 存儲換行
在 Windows 應用程序中,換行一般以一對字符來存儲:回車符(CR)和換行符(LF)。 在 Unix 和 Mac OSX 中,使用 LF 來存儲新行。 在舊的 Mac 系統中,使用 CR 來存儲新行。 XML 以 LF 存儲換行。
2 XML文檔解析
解析XML文檔時,目前有兩種流行的模式:SAX和DOM。
2.1 解析模式
1) SAM模式
SAM時一種基於事件驅動的解析模式。解析XML文檔時,程序從上到下讀取XML文檔,若是遇到開始標籤、結束標籤和屬性等,就會觸發相應的事件。可是這種解析XML文件的方式有一個弊端,那就是隻能讀取XML文檔,不能寫入XML文檔,它的優勢是解析速度快適合大文件。
2) DOM模式
DOM模式將XML文檔映射爲一棵樹狀結構進行分析,獲取節點的內容以及相關屬性,或是新增、刪除和修改節點的內容。XML解析器在加載XML文件之後,DOM模式將XML文件的元素視爲樹狀結構的節點,一次性讀入到內存中。若是文檔比較大,解析速度就會變慢,因此該模式適合小文件。可是在DOM模式中,有一點是SAX沒法取代的,那就是DOM可以修改XML文檔。
2.2 解析框架
目前流行的解析框架有:
3 NSXMLParser框架
3.1 簡介
NSXMLParser框架採用SAM模式進行解析,即其是基於事件驅動的方式進行解析。NSXMLParser框架的解析工做是交給了NSXMLParserDelegate實現類去完成。在委託中定義了不少回調方法,當進行SAX解析XML文件過程當中,遇到開始標籤、結束標籤、文檔開始、文檔結束和字符串等XML語法時就會觸發相應的回調方法。
其中主要的有5個回調方法,其它相關的回調方法能夠參考Apple幫助文檔:
-
-parserDidStartDocument:(NSXMLParser *)parser:在文檔開始的時候觸發。
-
-parserDidEndDocument:(NSXMLParser *)parser:在文檔結束時觸發。
-
-parser:didStartElement:namespaceURI:qualifiedName:attributes:遇到開始標籤時觸發,其中namespaceURI是命名空間,attributes是字典類型的屬性集合。
-
- parser:didEndElement:namespaceURI:遇到結束標籤時觸發。
-
- parser:foundCharacters:遇到字符串時觸發。
3.2 第一個應用程序
1) XML文件:note.xml
1 <?xml version=
"
1.0
" encoding=
"
UTF-8
"?>
2 <Notes>
3 <Note id=
"
1
">
4 <CDate>
2012-
12-
21</CDate>
5 <Content>早上8點鐘到公司</Content>
6 <UserID>tony</UserID>
7 </Note>
8 <Note id=
"
2
">
9 <CDate>
2012-
12-
22</CDate>
10 <Content>發佈iOSBook1</Content>
11 <UserID>tony</UserID>
12 </Note>
13 <Note id=
"
3
">
14 <CDate>
2012-
12-
23</CDate>
15 <Content>發佈iOSBook2</Content>
16 <UserID>tony</UserID>
17 </Note>
18 <Note id=
"
4
">
19 <CDate>
2012-
12-
24</CDate>
20 <Content>發佈iOSBook3</Content>
21 <UserID>tony</UserID>
22 </Note>
23 <Note id=
"
5
">
24 <CDate>
2012-
12-
25</CDate>
25 <Content>發佈2016奧運會應用iPhone版本</Content>
26 <UserID>tony</UserID>
27 </Note>
28 <Note id=
"
6
">
29 <CDate>
2012-
12-
26</CDate>
30 <Content>發佈2016奧運會應用iPad版本</Content>
31 <UserID>tony</UserID>
32 </Note>
33 </Notes>
2) 委託類頭文件
1 @interface ViewController : UIViewController <NSXMLParserDelegate>
2
3 @property (strong,nonatomic) NSMutableArray *notes;
//
解析出的數據內部是字典類型的數組
4
@property (strong,nonatomic) NSString *currentTagName;
//
當前標籤的名字
5
6 -(
void)start;
//
自定義方法:開始解析
7
8 @end
3) 委託類源文件
1 @implementation ViewController
2 - (
void)viewDidLoad {
3 [super viewDidLoad];
4 [self start];
5 }
6
7 -(
void)start
8 {
9 NSString* path = [[NSBundle mainBundle] pathForResource:
@"
Notes
" ofType:
@"
xml
"];
//
獲取XML文件路徑
10
NSURL *url = [NSURL fileURLWithPath:path];
11
12 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//
建立NSXMLParser 對象
13
parser.
delegate = self;
//
設置委託對象
14
[parser parse];
//
開始進行解析
15
NSLog(
@"
解析完成...
");
16 }
17
18 - (
void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
//
遇到一個開始標籤時候觸發
19
namespaceURI:(NSString *)namespaceURI
20 qualifiedName:(NSString *)qualifiedName
21 attributes:(NSDictionary *)attributeDict
22 {
23 _currentTagName = elementName;
24
if ([_currentTagName isEqualToString:
@"
Note
"]) {
25 NSString *_id = [attributeDict objectForKey:
@"
id
"];
26 NSMutableDictionary *dict = [NSMutableDictionary
new];
27 [dict setObject:_id forKey:
@"
id
"];
28 [_notes addObject:dict];
//
爲新的標籤建立一個對應的字典,並添加到數組中
29
}
30 }
31
32 - (
void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)
string
//
遇到字符串時候觸發
33
{
34
//
替換回車符和空格
35
string =[
string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
36
if ([
string isEqualToString:
@""]) {
37
return;
38 }
39
//
NSLog(string);
40
NSMutableDictionary *dict = [_notes lastObject];
//
獲取數組中最後一個元素(即當前標籤所對應的字典)
41
if ([_currentTagName isEqualToString:
@"
CDate
"] && dict) {
42 [dict setObject:
string forKey:
@"
CDate
"];
//
往字典中添加鍵值對。
43
}
44
if ([_currentTagName isEqualToString:
@"
Content
"] && dict) {
45 [dict setObject:
string forKey:
@"
Content
"];
46 }
47
if ([_currentTagName isEqualToString:
@"
UserID
"] && dict) {
48 [dict setObject:
string forKey:
@"
UserID
"];
49 }
50 }
51
52 - (
void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
//
遇到結束標籤時候出發
53
namespaceURI:(NSString *)namespaceURI
54 qualifiedName:(NSString *)qName;
55 {
56 self.currentTagName = nil;
57 }
58 - (
void)parserDidStartDocument:(NSXMLParser *)parser
//
文檔開始的時候觸發
59
{
60 _notes = [NSMutableArray
new];
61 NSLog(
@"
文檔開始的時候觸發
");
62 }
63 - (
void)parserDidEndDocument:(NSXMLParser *)parser
//
遇到文檔結束時候觸發
64
{
65 [[NSNotificationCenter defaultCenter] postNotificationName:
@"
reloadViewNotification
"
object:self.notes userInfo:nil];
66 self.notes = nil;
67 }
68 - (
void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
//
文檔出錯的時候觸發
69
{
70 NSLog(
@"
%@
",parseError);
71 }
72 @end
3.3 XML解析過程
使用NSXMLParser解析XML文件很是簡單,只需實現NSXMLParserDelegate協議相應的方法便可,以下圖所示:
1) 首先,實現NSXMLParserDelegate協議,並在該協議相應的回調方法中,實現具體解析內容;
2) 而後,獲取XML文件的路徑;
3) 接着,調用NSXMLParser類的構造函數initWithContentsOFURL來建立NSXMLParser對象;
4) 最後,給NSXMLParser對象指定委託對象,最後調用該對象的Parse方法啓動解析;
4 TBXML解析
4.1 簡介
TBXML是輕量級的DOM模式解析庫,它只能讀取XML文檔,不能寫XML文檔,可是解析XML是最快的。
其中TBXML框架是一個開源項目,其相關的網絡地址爲:
從下載的TBXML.h文件中,能夠 瞭解其內部的結構和提供的功能方法:
1
//
================================================================================================
2
//
Structures
3
//
================================================================================================
4
/*
* The TBXMLAttribute structure holds information about a single XML attribute. The structure holds the attribute name, value and next sibling attribute. This structure allows us to create a linked list of attributes belonging to a specific element.
5
*/
6 typedef
struct _TBXMLAttribute {
7
char * name;
8
char * value;
9
struct _TBXMLAttribute * next;
10 } TBXMLAttribute;
11
12
/*
* The TBXMLElement structure holds information about a single XML element. The structure holds the element name & text along with pointers to the first attribute, parent element, first child element and first sibling element. Using this structure, we can create a linked list of TBXMLElements to map out an entire XML file.
*/
13 typedef
struct _TBXMLElement {
14
char * name;
15
char * text;
16
17 TBXMLAttribute * firstAttribute;
18
struct _TBXMLElement * parentElement;
19
20
struct _TBXMLElement * firstChild;
21
struct _TBXMLElement * currentChild;
22
23
struct _TBXMLElement * nextSibling;
24
struct _TBXMLElement * previousSibling;
25 } TBXMLElement;
26
27
/*
* The TBXMLElementBuffer is a structure that holds a buffer of TBXMLElements. When the buffer of elements is used, an additional buffer is created and linked to the previous one. This allows for efficient memory allocation/deallocation elements.
28
*/
29 typedef
struct _TBXMLElementBuffer {
30 TBXMLElement * elements;
31
struct _TBXMLElementBuffer * next;
32
struct _TBXMLElementBuffer * previous;
33 } TBXMLElementBuffer;
34
35
/*
* The TBXMLAttributeBuffer is a structure that holds a buffer of TBXMLAttributes. When the buffer of attributes is used, an additional buffer is created and linked to the previous one. This allows for efficient memeory allocation/deallocation of attributes.
36
*/
37 typedef
struct _TBXMLAttributeBuffer {
38 TBXMLAttribute * attributes;
39
struct _TBXMLAttributeBuffer * next;
40
struct _TBXMLAttributeBuffer * previous;
41 } TBXMLAttributeBuffer;
因爲提供的方法不方便粘貼進入文檔,因此具體方法能夠參考TBXML.h文件。
4.2 第一個應用程序
4.2.1 環境配置
由於TBXML框架是第三方的開發庫,因此在Xcode中使用須要手動添加相應的文件並相應配置一些內容。具體過程爲:
1) 添加以下四個TBXML所依賴的Framwork和庫
-
Foundation.framework
-
UIKit.framework
-
CoreGraphics.framework
-
Libz.tbd
圖 6
圖 7
2) 在Object-C語言中,須要在工程中添加預編譯頭問津啊PrefixHeader.pch,並在該文件中添加相應的兩行代碼。
圖 8
圖 9
3) 將在gidhut網站中下載的文件夾添加到工程中,如圖 10所示是已經添加完成的項目目錄。
圖 10
4.2.2 示例代碼
因爲解析XML文件必須有具體的XML文件內容格式,因此本例仍是以2.3.2小節的Note.xml文件進行解析。其中解析類的.h文件以下所示。
1 #import <UIKit/UIKit.h>
2 #import
"
TBXML.h
"
//
必須引入的頭文件
3
4 @interface ViewController : UIViewController
5
6
//
解析出的數據內部是字典類型
7
@property (strong,nonatomic) NSMutableArray *notes;
8
9
//
開始解析方法
10
-(
void)startTBXMLParser;
11
12 @end
而具體的.m文件內容以下:
1 -(
void)startTBXMLParser
2 {
3 _notes = [NSMutableArray
new];
4 TBXML* tbxml = [[TBXML alloc] initWithXMLFile:
@"
Notes.xml
" error:nil];
//
讀取XML文件,並以樹形結構建立對象。
5
TBXMLElement * root = tbxml.rootXMLElement;
//
獲取XML樹形的根節點
6
7
//
if root element is valid
8
if (root) {
9 TBXMLElement * noteElement = [TBXML childElementNamed:
@"
Note
" parentElement:root];
//
獲取第一個子元素
10
while ( noteElement != nil) {
11 NSMutableDictionary *dict = [NSMutableDictionary
new];
12 TBXMLElement *CDateElement = [TBXML childElementNamed:
@"
CDate
" parentElement:noteElement];
13
if ( CDateElement != nil) {
14 NSString *CDate = [TBXML textForElement:CDateElement];
//
獲取子元素的內容。
15
[dict setValue:CDate forKey:
@"
CDate
"];
16 }
17
18 TBXMLElement *ContentElement = [TBXML childElementNamed:
@"
Content
" parentElement:noteElement];
19
if ( ContentElement != nil) {
20 NSString *Content = [TBXML textForElement:ContentElement];
21 [dict setValue:Content forKey:
@"
Content
"];
22
//
NSLog(Content);
23
}
24
25 TBXMLElement *UserIDElement = [TBXML childElementNamed:
@"
UserID
" parentElement:noteElement];
26
if ( UserIDElement != nil) {
27 NSString *UserID = [TBXML textForElement:UserIDElement];
28 [dict setValue:UserID forKey:
@"
UserID
"];
29 }
30
31
//
得到ID屬性
32
NSString *_id = [TBXML valueOfAttributeNamed:
@"
id
" forElement:noteElement error:nil];
33 [dict setValue:_id forKey:
@"
id
"];
34 [_notes addObject:dict];
35 noteElement = [TBXML nextSiblingNamed:
@"
Note
" searchFromElement:noteElement];
36 }
37 }
38
39 NSLog(
@"
解析完成...
");
40 [[NSNotificationCenter defaultCenter] postNotificationName:
@"
reloadViewNotification
"
object:self.notes userInfo:nil];
41 self.notes = nil;
42 }
4.3 XML解析過程
利用TBXML框架解析XML的過程是以樹狀的結構加載XML文件,樹中的每一個節點都是XML的一個元素,因此就能夠遍歷樹中的每一個節點(XML的元素),從而便可解析整棵樹(整個XML文件)。
4.3.1 加載XML文件
XML文件在TBXML框架中以TBXML對象表示,而且該框架提供了多種方式加載XML文件。
TBXML * tbxml = [[TBXML tbxmlWithXMLFile:
@"
books.xml
"] retain];
TBXML * tbxml = [[TBXML tbxmlWithXMLFile:
@"
books
" fileExtension:
@"
xml
"] retain];
TBXML * tbxml = [[TBXML tbxmlWithXMLData:myXMLData] retain];
TBXML * tbxml = [[TBXML tbxmlWithURL:[NSURL URLWithString:
@"
http://www.w3schools.com/XML/note.xml
"]] retain];
TBXML * tbxml = [[TBXML tbxmlWithXMLString:
@"
<root><elem1 attribute1=\
"elem1-attribute1\
"
/><elem2 attribute2=\"attribute2\"/></root>
"] retain];
4.3.2 獲取XML元素
在XML文件中全部的節點都是元素,最頂端的是根元素,其它節點都是根元素的子元素(直接或是間接)。
每一個XML文檔都只有一個根元素,因此能夠獲取TBXML對象的rootXMLElement成員變量,如:
TBXMLElement * rootXMLElement = tbxml.rootXMLElement;
[TBXML childElementNamed:
@"
author
" parentElement:root]
4.3.3 獲取XML屬性
在XML文件中每一個元素均可能有元素,因此能夠利用TBXML對象的valueOfAttributeNamed: forElement:方法來查詢相應元素的屬性。
NSString *name = [TBXML valueOfAttributeNamed:
@"
name
" forElement:author];
4.3.4 獲取XML元素的文本
在獲取XML元素對象後,就能夠經過TBXML對象的textForElement:方法獲取指定元素的文本值。
NSString *description = [TBXML textForElement:descriptionElement];
4.3.5 遍歷不知名的元素或屬性
因爲XML文檔是一個樹狀的結構,每一個元素都有指向其第一個子元素的指針firstChild,從而可以獲取子元素。同時全部子元素都造成一條鏈表,全部能夠經過元素的nextSibling指針,獲取其兄弟元素。
對於XML元素中的屬性,也能夠經過一樣的方式進行遍歷。能夠經過TBXMLElement對象的firstAttribute指針獲取第一個元素,而後經過TBXMLAttribute屬性對象的next指針獲取下一個兄弟屬性。
1 - (
void)loadUnknownXML
2 {
3 tbxml = [[TBXML tbxmlWithXMLFile:
@"
books.xml
"] retain];
//
Load and parse the books.xml file
4
5
if (tbxml.rootXMLElement)
6 [self traverseElement:tbxml.rootXMLElement];
7
8 [tbxml release];
//
release resources
9
}
10
11 - (
void) traverseElement:(TBXMLElement *)element
12 {
13
do
14 {
15 NSLog(
@"
%@
",[TBXML elementName:element]);
//
Display the name of the element
16
17
//
Obtain first attribute from element
18
TBXMLAttribute * attribute = element->firstAttribute;
19
while (attribute)
20 {
21
//
Display name and value of attribute to the log window
22
NSLog(
@"
%@->%@ = %@
", [TBXML elementName:element],
23 [TBXML attributeName:attribute],
24 [TBXML attributeValue:attribute]);
25
26 attribute = attribute->next;
//
Obtain the next attribute
27
}
28
29
//
if the element has child elements, process them
30
if (element->firstChild)
31 [self traverseElement:element->firstChild];
//
遞歸查詢子元素
32
33 }
while ((element = element->nextSibling));
//
Obtain next sibling element
34
}
5 參考文獻
[1] Runoob.com;
[2] Introduction to Event-Driven XML Programming Guide for Cocoa;(simply need to parse XML and extract information from an existing source of XML。NSXMLParser )
[3] Introduction to Tree-Based XML Programming Guide for Cocoa;
[4] TBXML網站;