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网站;