iOS-----XML解析

XML解析

XML文件是一种平台无关的数据交换格式,当iOS应用需要与其他应用或应用服务器进行通信时,如果数据量较小,当让可以选择简单的文本数据。但当数据量较大而且数据之间具有严格的结构关系时,使用简单的文本数据就比较麻烦了,此时可以要么选择XML文档作为数据交换格式,要么选择JSON作为数据交换格式

DOM与SAX

  为了利用XML文档的结构化特征机型解析,现有两套比较流行的规范。

DOM

Documents Object Model,即文档对象模型,它是由W3C推荐的处理XML文档的规范。

SAX

Simple API for XML, 它并不是W3C推荐的标准,但却是整个XML行业的事实规范。

DOM的优缺点

缺点:XML需要一次性地读取整个XML文档,而且程序运行期间,整棵DOM树常驻内存,导致系统开销过大。

优点:简单易用,由于树在内存中是持久的,可以修改树的节点,对应为修改文档中元素的值,灵活修改。由于DOM一次性将整个XML文档全部读入内存,因此可以随机访问XML文档的每个元素,方便对XML文档中的数据进行重复读取。

SAX的优缺点

优点:SAX解析方式占用内存极小,速度更快。每当SAX解析器发现文档开始、元素开始、元素结束、文本和文档结束等事件时,就会向外发送一次事件,而程序员则通过编写事件监听这些事件来获取XML文档里的信息。

缺点:SAX解析器根本不创建任何对象,只是在遇到XML文档的各种标签时触发对应的事件,并将XML元素的内容封装成事件传出去。

在iPhone开发中,XML的解析有很多选择,iOS SDK提供了NSXMLParser和libxml2两个类库,另外还有很多第三方类库可选,例如GDataXML、TBXML、TouchXML、KissXML等

NSXMLParser

iOS SDK自带的解析器,基于SAX解析,纯Objective-C 实现的,性能并不好,而且使用起来也不太方便

libxml2

iOS SDK自带的解析器,它是一套开源的解析器,是Linux内核的系统上很常用的解析器,功能非常强大,可同时支持DOM和SAX解析,而且性能也很好,采用C语言实现的。

GDataXML

第三方提供的基于DOM的XML解析类库,功能强大,支持读取和修改XML文档,也支持XPath方式查询,而且性能也很快

TBXML

轻量级的基于DOM的XML解析类库,有很好的性能和低内存占用,可以在低内存损耗的条件下快速提取内容,但功能比较简单,不支持对XML文档进行校验,也不支持XPath方式查询,而且只能读,不能修改XML文档。

TouchXML

基于DOM的XML解析库,与TBXML的功能和特点几乎相同,唯一的优势是支持XPath方式查询。

KissXML

基于TouchXML的XML解析类库,在TounchXML继承上提供了对XML文档修改的功能。

调用的方便性来说,建议使用TouchXML、KissXML或GDataXML

如果需要读取和修改XML文档,则建议使用KissXML或GDataXML。

如果需要读取非常大的XML文档,则建议使用libxml.2或TBXML。

如果你不想去调用第三方类库,那么使用NSXMLParser也可以

 

使用NSXMLParser解析XML文档 

NSXMLParser 是基于 SAX的解析器,也就是所谓的“事件驱动“的解析器,使用 NSXMLParser 解析的关键就是实现 SAX的事件处理器-------该事件处理器负责处理 NSXMLParser解析 XML 过程中的各种事件.

NSXMLParser解析的事件处理采用了委托式事件处理,只要为 NSXMLParser 指定一个 delegate 对象即可,该 delegate 对象必须实现 NSXMLParserDelegate 协议,该协议定义了如下常用方法

- parserDidStartDocument:

开始处理XML文档时激发该方法

- parserDidEndDocument:

结束处理XML文档时激发该方法

- parser:didStartElement:namespaceURI:qualifiedName:attributes:

开始处理 XML 元素时激发该方法.

- parser:didEndElement:namespaceURI:qualifiedName:

 结束处理 XML元素时激发该方法

- parser:resolveExternalEntityName:systemID:

开始处理外部实体时激发该方法

-  parser:parseErrorOccurred:

解析出现错误时激发该方法

- parser:validationErrorOccurred:

XML 文档验证 错误时激发该方法

- parser:foundCharacters:

 解析 XML文档遇到字符串内容时激发该方法`

- parser:foundIgnorableWhitespace:

 解析 XML文档遇到空白时激发该方法.

- parser:foundProcessingInstructionWithTarget:data:

 解析 XML 文档的处理指令时激发该方法

- parser:foundComment:

处理 XML文档的注释时激发该方法

- parser:foundCDATA:

处理 XML文档的 CDATA 内容时激发该方法

使用 NSXMLParser解析 XML文档的步骤如下

1.创建 NSXMLParser 对象

2.为 NSXMLParser对象指定 delegate对象,该 delegate对象必须实现 NSXMLParserDelegate协议,并根据需要实现协议中特定的方法

3.调用 NSXMLParser对象的 parser方法开始解析

代码如下

 1 books.xml
 2 
 3 <? xml version=”1.0” encoding=”UTF-8”?>
 4 
 5 <books>
 6 
 7 <book id=”1”>
 8 
 9 <title>西游记</ title>
10 
11 <author>吴承恩</author>
12 
13 <remark>本书来自作者来自明朝</ remark>
14 
15 </book>
16 
17 <book id=”2”>
18 
19 <title>水浒传</ title>
20 
21 <author>施耐庵</author>
22 
23 <remark>本书作者来自于元末明初 </ remark>
24 
25 </book>
26 
27 <book id=”3”>
28 
29 <title>红楼梦</ title>
30 
31 <author>曹雪芹</author>
32 
33 <remark>本书作者来自于清朝</ remark>
34 
35 </book>
36 
37 </book>
38 
39 <book id=”4”>
40 
41 <title>三国演义 </ title>
42 
43 <author>罗贯中</author>
44 
45 <remark>本书作者来自于元末明初</ remark>
46 
47 </book>
48 
49 </ books>

 

    使用 NSXMLParser解析的关键就是为它实现 delegate对象,下面创建自己的委托类,该委托类必须实现 NSXMLParserDelegate 协议.该委托类的接口部分代码如下

1 XMLDelegate.h
2 
3 @ interface XMLParserDelegate: NSObject<NSXMLDelegate>
4 
5 //  定义一个 NSMutableArray 集合来保存解析 XML文档得到的数据
6 
7 @property (nonatomic, strong) NSMutableArray *books;
8 
9 @end

 

  1 XMLDelegate.m
  2 
  3 @implementation XMLParserDelegate
  4 
  5 // 定义一个Book对象,用于保存正在解析的<book>元素中的数据
  6 
  7 Book*  book;
  8 
  9 NSString* currentElementValue;
 10 
 11 //  当开始处理某个元素时触发该方法
 12 
 13 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
 14 
 15  namespaceURI:(NSString*)namespaceURI   qualifiedName:(NSString*)qName
 16 
 17  attributes:(NSDictionary*)attributesDict
 18 
 19 {
 20 
 21 NSLog(@”开始处理元素 %@”,  elementName);
 22 
 23 if([elementName isEqualToString:@”books”])
 24 
 25 {
 26 
 27   // 如果正在处理根元素,则在此初始化存储解析结果的NSMutableArray集合
 28 
 29   self.books = [[NSMutableArray alloc] init];
 30 
 31 }
 32 
 33 // 如果正在处理<book…/>元素
 34 
 35 else if([elementName isEqualToString:@”book”])
 36 
 37 {
 38 
 39     // 初始化Book对象
 40 
 41     book =[[Book alloc] init];
 42 
 43     //  从attributeDict中读取<book…/>元素的属性id的值
 44 
 45     book.bookID = [[attributes objectiForKey:@”id”] integerValue];
 46 
 47 }
 48 
 49 }
 50 
 51 // 当开始处理字符串内容时触发该方法
 52 
 53 - (void) parser:(NSXMLParser*)parser foundCharacters:(NSString *)string
 54 
 55 {
 56 
 57 NSLog(@”处理字符串内容: %@”,  string);
 58 
 59 // 如果当前的字符串值不为nil,则保存当前正在处理的元素的值
 60 
 61 if(string)
 62 
 63 {
 64 
 65     currentElementValue = string;
 66 
 67 }
 68 
 69 }
 70 
 71 // 当处理某个元素结束时触发该方法
 72 
 73 - (void) parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName
 74 
 75   namespaceURI:(NSString*)namespaceURI  qualifiedName:(NSString*)qName
 76 
 77 {
 78 
 79    // 如果处理根元素结束,则表明XML文档处理完成
 80 
 81    if([elementName isEqualToString:@”books”])
 82 
 83    {
 84 
 85       return;
 86 
 87 }
 88 
 89 // 如果处理<book…/>元素结束,则将封装的Book对象添加到NSMutableArray集合中
 90 
 91 else if([elementName isEqualToString:@”book”])
 92 
 93 {
 94 
 95    [self.books  addObject: book];
 96 
 97    book = nil;
 98 
 99 }
100 
101 else
102 
103 {
104 
105    // 如果既不是处理<books…/>元素,也不是处理<book…/>元素
106 
107   // 则使用KVC方式为当前Book对象的属性赋值
108 
109   [book setValue: currentElementVale forKey:elementName];
110 
111   currentElementValue = nil;
112 
113 }
114 
115 }
116 
117 @end

 

   该委托类只是实现了3个方法:开始处理XML元素时激发的方法;处理字符串内容时激发的方法;结束处理XML元素时激发的方法------当程序使用NSXMLParser处理XML文档时,这3个方法就会被自动触发,从而将XML文档中的数据提取出来.

     上面程序中还用到了一个Book类,提供bookID、title、author、remark这4个属性来封装XML文档中<book…/>元素的属性和子元素的值.

   最后在该界面的视图控制器类的实现部分调用NSXMLParser处理XML文档,并将解析结果显示出来.下面是该界面的视图控制器类的实现部分代码

 1 ViewController.m
 2 
 3 XMLParserDelegate* parserDelegate;
 4 
 5 - (void)viewDidLoad
 6 
 7 {
 8 
 9    [super viewDidLoad];
10 
11    //  获取要解析的XML文档所在的URL(使用URL即可解析本地XML文档,也可解析网络XML文档)
12 
13   NSURL* fileURL = [[NSBundle mainBundle]  URLForResource:@”books” withExtension:@”xml”];
14 
15    // 获取NSXMLParser实例对象
16 
17    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:fileURL];
18 
19    // 创建NSXMLParser解析的委托对象
20 
21    parserDelegate = [[XMLParserDelegate alloc] init];
22 
23    //  为NSXMLParser指定委托对象,该委托对象就负责处理解析事件
24 
25    parser.delegate = parserDelegate;
26 
27    // 开始解析,解析结果会保存在委托对象的books属性中
28 
29   [parser parser];
30 
31 }
32 
33 - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
34 
35 {
36 
37    // parserDeletage的books属性包含多少个元素,此处就显示多少个表格行
38 
39    return parserDelegate.books.count;
40 
41 }
42 
43 - (UITableViewCell *)tableView:(UITableView*)tableView
44 
45   cellForRowAtIndexPath:(NSIndexPath*)indexPath
46 
47 {
48 
49    // 获取可重用的单元格
50 
51    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:
52 
53 @”bookCell”  forIndexPath:indexPath];
54 
55    // 从可重用单元格中根据Tag分别取出3个UILabel控件
56 
57    UILabel* titleLabel = (UILabel*)[cell viewWithTag:1];
58 
59    UILabel* authorLabel = (UILabel*)[cell viewWithTag:2];
60 
61    UILabel* remarkLabel = (UILabel*)[cell viewWithTag:3];
62 
63    Book* book = [parserDelegate.books objectAtIndex:indexPath.row];
64 
65    // 为3个UILabel设置文本
66 
67    titleLabel.text = book.title;
68 
69    authorLabel.text = book.author;
70 
71    remarkLabel.text = book.remark;
72 
73    return cell;
74 
75 }
76 
77 @end

 

   上面程序中有关XML解析的只是4行红色字代码-----这4行粗体字代码创建了NSXMLParser对象,为该对象指定了delegate对象,接下来就是调用NSXMLParser的parser方法开始解析,解析的关键是实现XNLParserDelegate对象,该对象将会负责处理解析过程中的各种事件,从而提取到XML文档中的数据.

 

使用libxml2解析XML文档

  libxml2是使用C语言实现的库

  在iOS项目中使用libxml2库,进行如下准备工作

1.为项目添加libxml2.dylib库,在Xcode的导航面板中选择项目,然后选择Dock区域中TARGETS列表下的项目图标.在打开中间编辑区域中的”Build Phases”标签页,单击”Link Binary with Libraries”下方的”+”按钮

2.添加头文件的搜索路径.在Dock区域中TARGETS列表下的项目图标,在”Build Settings”标签页,在编辑区域搜索框中输入”search”, 找到”Header Search Paths”处,双击”Header Search Paths”项右边的编辑框,点击” + “号,将”/usr/include/libxml2”添加成该项目的头文件搜素路径

使用libxml2解析XML文档的步骤如下

1.创建xmlTextReaderPtr对象.如果以本地XML文档来创建xmlTextReaderPtr对象,则调用xmlNewTextReaderFilename()函数即可;如果以内存中的XML文档来创建该对象,则调用xmlReaderForMemory()函数即可.

2.依次调用xmlTextReadeXxx()函数来去读XML文档的元素名、元素值、属性等各种内容。其中xmlTextReaderXxx()函数是大量功能类似的函数,都用于读取XML文档的内容

提示:在使用xmlTextReaderXxx()函数进行读取之前,可调用xmlTextReaderNodeType()函数获取正在读取的内容的类型,并针对不同的类型进行相应的处理.

代码片段

  1 BookParser.m
  2 
  3 #include <libxml/xmlreader.h>
  4 
  5 #import “BooksParser.h”
  6 
  7 #import “Book.h”
  8 
  9  
 10 
 11 @implementation BooksParser
 12 
 13 // 定义一个Book对象,用于保存正在解析的<book>元素中的数据
 14 
 15 Book* book;
 16 
 17 - (void)readXml:(NSString*)xmlName
 18 
 19 {
 20 
 21   NSString* xmlPath = [[NSBundle mainBundle]
 22 
 23 pathForResource:xmlName  ofType:@”xml”];
 24 
 25 //  通过XML文档创建xmlTextReaderPtr
 26 
 27 xmlTextReaderPtr reader = xmlNewTextReaderFilename([xmlPath UTF8String]);
 28 
 29 //  如果需要通过内存中的XML文档创建reader,则可调用xmlReaderForMemory()函数
 30 
 31 //  xmlTextReaderPtr reader = xmlReaderForMemory(memory, size, NULL, “UTF-8”, 0);
 32 
 33 if(!reader)
 34 
 35 {
 36 
 37    NSLog(@”加载XML文档出现错误! ”);
 38 
 39 }
 40 
 41 else
 42 
 43 {
 44 
 45    char *temp;
 46 
 47    NSString *elementName = nil;
 48 
 49    NSString *currentElementValue = nil;
 50 
 51    // 采用循环,不断读取文档内容
 52 
 53    while(YES)
 54 
 55    {
 56 
 57       // 如果读取结束,则结束循环
 58 
 59       if(!xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)//
 60 
 61       {
 62 
 63          // 调用xmlTextReaderConstName()函数获取元素名
 64 
 65          temp = (char *)xmlTextReadConstName(reader);
 66 
 67          // 将C风格的字符串转换为Objective-C字符串
 68 
 69        elementName = [NSString stringWithCString:temp  encoding:NSUTF8StringEncoding];
 70 
 71 if([elementName isEqualToString:@”books”])
 72 
 73 {
 74 
 75    self.books = [NSMutableArray array];
 76 
 77 }
 78 
 79 else if([elementName isEqualToString:@”book”])
 80 
 81 {
 82 
 83   // 创建Book对象
 84 
 85   book = [[Book alloc] init];
 86 
 87   // 将book对象添加到books集合中
 88 
 89   [self.books addObject:book];
 90 
 91   // 读取book元素的id属性
 92 
 93   temp = (char*)xmlTextReaderGetAttribute(reader, (xmlChar*)”id”);
 94 
 95   // 将C风格的字符串转换为Objective-C字符串
 96 
 97   NSString* idValue = [NSString stringWithCString:temp encoding:NSUTF8StringEncoding];
 98 
 99   book.bookID = [idValue intValue];
100 
101 }
102 
103 else if([elementName isEqualToString:@”title”]
104 
105 || [elementName isEqualToString:@”author”]
106 
107 || [elementName isEqualToString:@”remark”])
108 
109 {
110 
111    // 调用xmlTextReaderReadString()函数获取元素中的文本内容
112 
113   temp = (char*)xmlTextReaderReadString(reader);
114 
115   // 将C风格的字符串转换为Objective-C字符串
116 
117   currentElementValue = [NSString stringWithCString:temp
118 
119 encoding:NSUTF8StringEncoding];
120 
121              // 使用KVC方式为当前Book对象的属性赋值
122 
123              [book setValue:currentElementValue forKey:elementName];
124 
125               currentElementValue = nil;
126 
127 }
128 
129 }
130 
131 }
132 
133 }
134 
135 // 关闭资源
136 
137 xmlTextReaderClose(reader);
138 
139 xmlFreeTextReader(reader);
140 
141 }
142 
143 @end

 

     上面程序中的①号红色字代码先调用了xmlTextReaderNodeType()函数判断正在读取的内容是否为元素,如果读取的内容是元素,则根据不同的元素名进行相应的处理

l  如果正在读取<books…/>元素,则创建NSMutableArray集合

l  如果正在读取<book…/>元素,则创建Book对象,并将它添加到NSMutableArray集合中.除此之外,还读取<book…/>元素的id属性值.

l  如果正在读取<book…/>元素的其他子元素,则使用KVC方法为Book对象的属性赋值,

上面程序中使用xmlTextReaderConstName()函数读取元素名,使用xmlTextReaderGetAttribute()函数读取属性值,使用xmlTextReaderReadString()函数读取元素值---------通过这些方式即可正常解析得到该XML文档的内容.

代码片段

 1 ViewController.m
 2 
 3 @implementation ViewController
 4 
 5 BookParser* booksParser;
 6 
 7 - (void)viewDidLoad
 8 
 9 {
10 
11    [super viewDidLoad];
12 
13    // 获取BooksParser实例对象
14 
15    booksParser = [[BooksParser alloc] init];
16 
17    // 解析XML文档
18 
19    [booksParser readXml:@”books”];
20 
21 }
22 
23 // 省略UITableViewDataSource协议中的两个方法
24 
25 ….
26 
27 @end

 

 

使用GDataXML解析XML文档

     GDataXML是第三方开源的XML解析库,它其实是对libxml2的包装,因此底层依然需要依赖libxml2.GDataXML的功能与libxml2差不多,既支持解析XML文档,也支持修改XML文档,而且支持XPath方式查询,提供了更好的面向对象封装

    

在iOS项目中使用GDataXML需要进行如下安装

1.由于GDataXML底层依赖libxml2,因此使用GDataXML同样需要将libxml2.dylib添加到项目中

2.由于GDataXML底层依赖libxml2,因此同样需要将”  /usr/include/libxml2  ” 路径添加到项目的头文件搜索路径中.

3.登录http://code.google.com/p/gdata-objectivec-client/source/browse/trunk/Source/XMLSupport/站点,找到XMLSupport文件夹,下载该文件夹下的GDataXMLNode.h和GDataXMLNode.m两个文件.这就是GDataXML的源代码了,将这两份文件添加到iOS项目中.

GDataXML并不支持ARC,需要在Xcode中对该类的编辑阶段添加”  –fno-objc-arc  ”选项

使用GDataXML解析XML文档的过程如下.

  1. 调用GDataXMLDocument的初始化方法根据XML文档或XML字符串初始化GDataXMLDocument对象
  2. 调用GDataXMLDocument对象的rootElement方法即可获取该文档的根元素
  3. 获取XML文档的根元素之后,接下来就可根据XML元素之间的父子关系来逐层遍历、访问该XML文档的每个元素,从而获取XML元素的内容。

解析XML文档所使用的解析器类的实现部分代码

  1 BookParser.m
  2 
  3 #import “BooksParser.h”
  4 
  5 #import “Book.h”
  6 
  7 #import “GDataXMLNode.h”
  8 
  9  
 10 
 11 @implementation BooksParser
 12 
 13 - (NSArray*)parserXML:(NSString*)xmlName
 14 
 15 {
 16 
 17    // 使用NSBundle对象获取到需要解析的XML文档的路径
 18 
 19    NSString *path = [[NSBundle  mainBundle] pathForResource:xmlName
 20 
 21 ofType:@”xml”];
 22 
 23    // 使用NSFileHandle对象根据文件路径获取到文件
 24 
 25    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
 26 
 27    // 读取文件内容返回NSData对象
 28 
 29    NSData *data = [file readDataToEndOfFile];
 30 
 31    //  根据NSData对象初始化GDataXMLDocument对象
 32 
 33    GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data
 34 
 35 options:0  error:nil];
 36 
 37  // 如果需要根据XML字符串来初始化GDataXMLDocument对象,则调用如下代码
 38 
 39 // GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:xmlStr
 40 
 41 //  options:0  error:nil];
 42 
 43  // 获取根元素,也就是获取<books…/>元素
 44 
 45  GDataXMLElement *rootElement = [doc rootElement];
 46 
 47  // 获取rootElement下所有的<book…/>元素,返回所有的<book…/>元素组成的集合
 48 
 49  NSArray *bookElements = [rootElement elementsForName:@”book”];
 50 
 51  // 初始化一个可变数组,用于存储将要获取的所有<book…/>元素的内容
 52 
 53  // 循环遍历每一个<book…/>元素
 54 
 55  for(GDataXMLElement *bookElement in bookElements)
 56 
 57 {
 58 
 59 // 初始化Book对象
 60 
 61 Book* book = [[Book alloc] init];
 62 
 63 //  获取id属性值,并且转成整型
 64 
 65 NSInteger bookID = [[[bookElement attributeForName:@”id”]
 66 
 67 stringValue] integerValue];
 68 
 69 //  获取title、author、remark元素内容
 70 
 71 NSString *title = [[[bookElement  elementsForName:@”title”]
 72 
 73 objectAtIndex:0] stringValue];
 74 
 75 NSString *author = [[[bookElement  elementsForName:@”author”]
 76 
 77 objectAtIndex:0] stringValue];
 78 
 79 NSString *remark = [[[bookElement  elementsForName:@”remark”]
 80 
 81 objectAtIndex:0] stringValue];
 82 
 83 // 将获取的属性值和元素内容存储到Book对象的属性中
 84 
 85 book.bookID = bookID;
 86 
 87 book.title = title;
 88 
 89 book.author = author;
 90 
 91 book.remark = remark;
 92 
 93 // 将每一个Book对象添加到可变数组中
 94 
 95 [books addObject:book];
 96 
 97 }
 98 
 99 // 返回books集合的副本
100 
101 return [books  copy];
102 
103 }
104 
105 @end

 

   上面程序中的第1行红色字代码利用已有的XML文档创建了GDataXMLDocument对象,接下来第2行红色字代码则用于获取该文档的根元素,剩下的红色字代码就是根据元素之间的父子关系逐层获取每个元素,并取出元素的内容.该解析器最后将所有解析得到的内容封装到NSMutableArray集合中,每个集合元素(Book对象)封装一个<book…/>元素的内容

代码片段

 1 ViewController.m
 2 
 3 @implementation ViewController
 4 
 5 NSArray* books;
 6 
 7 - (void)viewDidLoad
 8 
 9 {
10 
11    [super viewDidLoad];
12 
13    // 获取BooksParser实例对象
14 
15    BooksParser* booksParser = [[BooksParser alloc] init];
16 
17    // 解析XML文档,获取解析得到的NSArray集合
18 
19    books = [booksParser  parserXML:@”books”];
20 
21 }
22 
23 // 省略UITableViewDataSource协议中的两个方法
24 
25 …..
26 
27 @end

 

   上面两行红色字代码就是调用BooksParser完成对XML文档的解析,解析完成后,XML文档的内容就保存在该视图控制器的books集合中了.该控制器类依然需要实现UITableViewDataSource协议中的两个方法将books集合的数据显示出来,但这两个方法与前一个示例几乎完全相同

 

使用GDataXML生成、修改XML文档

GDataXML不仅可用于解析XML文档,还可用于生成、修改XML文档,而且使用GDataXML来生成、修改XML文档同样简单,只要按XML元素之间的父子关系添加子元素即可。

 

使用GDataXML生成XML文档的步骤如下

1.调用GDataXMLNode的elementWithName:方法创建GDataXMLElement对象,并以该对象作为XML文档的根元素.

2.调用GDataXMLNode的elementWithName:方法不断创建GDataXMLElement对象(XML元素),并利用元素之间的父子关系组织这些XML元素

3.调用GDataXMLDocument的initWithRootElement: 方法根据指定根元素来生成GDataXMLDocument对象--------它代表了XML文档在内存中的形式

4.调用GDataXMLDocument对象的XMLData的方法获取XML文档对应的NSData对象,调用NSData的输出方法将XML文档输出到指定文件或其他存储介质.

使用GDataXML修改XML文档的步骤如下

1.调用GDataXMLDocument的方法根据指定XML文档或者XML字符串来生成GDataXMLDocument对象-----它代表了XML文档在内存中的形式

2.获取GDataXMLDocument对象的根元素,然后利用元素之间的父子关系添加子元素、删除子元素或修改元素的内容。

3.调用GDataXMLDocument对象的XMLData的方法获取XML文档对应的NSData对象,调用NSData的输出方法将XML文档输出到指定文件或其他存储介质

代码片段

  1 ViewController.m
  2 
  3 @implementation ViewController
  4 
  5 - (void)viewDidLoad
  6 
  7 {
  8 
  9    [super viewDidLoad];
 10 
 11 }
 12 
 13 - (IBAction)finishEdit:(id)sender
 14 
 15 {
 16 
 17    // 放弃作为第一响应者,即关闭虚拟键盘
 18 
 19   [sender resignFirstResponder];
 20 
 21 }
 22 
 23 - (IBAction)add:(id)sender
 24 
 25 {
 26 
 27    //  获取应用界面上4个文本框内的值
 28 
 29   NSString* bookId = self.idField.text;
 30 
 31   NSString* bookName = self.nameField.text;
 32 
 33   NSString* author = self.authorField.text;
 34 
 35   NSString* remark = self.remarkField.text;
 36 
 37  
 38 
 39 if( bookId.length > 0 && bookName.length > 0
 40 
 41 author.length > 0 && remark.length > 0 )
 42 
 43 {
 44 
 45    // 使用NSFileHandle对象根据文件路径获取到文件
 46 
 47   NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:self.xmlPath];
 48 
 49   //  读取文件内容返回NSData对象
 50 
 51  NSData* data = [file readDataToEndOfFile];
 52 
 53  // 定义变量保存将要处理的XML文档对象
 54 
 55 GDataXMLDocument* doc;
 56 
 57 //  定义变量保存XML文档的根元素
 58 
 59 GDataXMLElement* rootEle;
 60 
 61 // 如果data存在,则表明该XML文档已经存在
 62 
 63 if(data)
 64 
 65 {
 66 
 67    // 根据NSData对象初始化GDataXMLDocument对象
 68 
 69   doc = [[GDataXMLDocument alloc] initWithData:data
 70 
 71 options:0 error:nil];
 72 
 73   //  获取XML文档的根元素
 74 
 75  rootEle = doc.rootElement; //
 76 
 77 }
 78 
 79 // 如果XML文档还不存在,则需要新建XML文档
 80 
 81 else
 82 
 83 {
 84 
 85    // 创建<books…/>元素
 86 
 87   rootEle = [GDataXMLNode elementWithName:@”books”];//
 88 
 89 }
 90 
 91 // 创建<book…/>元素
 92 
 93 GDataXMLElement* bookEle =[GDataXMLNode elementWithName:@”book”];
 94 
 95 // 创建id属性,属性值为bookId
 96 
 97 GDataXMLNode* attribute = [GDataXMLNode attributeWithName:@”id 98 
 99 stringValue:bookId];
100 
101 // 为<book…/>元素添加id属性
102 
103 [bookEle  addAttribute:attribute];
104 
105 //  依次创建<title…/>、<author…/>、<remark…/>3个元素
106 
107 GDataXMLElement*  titleEle =[GDataXMLNode elementWithName:@”title”
108 
109 stringValue:bookName];
110 
111 GDataXMLElement*  authorEle =[GDataXMLNode elementWithName:@”author”
112 
113 stringValue: author];
114 
115 GDataXMLElement*  remarkEle =[GDataXMLNode elementWithName:@”remark”
116 
117 stringValue: remark];
118 
119 // 将<title…/>、<author…/>、<remark…/>3个子元素添加到bookEle元素中
120 
121 [bookEle  addChild: titleEle];
122 
123 [bookEle  addChild: authorEle];
124 
125 [bookEle  addChild: remarkEle];
126 
127 // 将<book…/>元素添加为XML文档根元素的子元素
128 
129 [rootEle  addChild: bookEle];
130 
131 // 如果data不存在,即XML文档还不存在,则表明需要重新生成GDataXMLDocument对象
132 
133 if(!data)
134 
135 {
136 
137    // 以指定的根元素创建GDataXMLDocument对象
138 
139    doc = [[GDataXMLDocument alloc] initWithRootElement:rootEle];
140 
141 }
142 
143 // 将GDataXMLDocument转换为NSData后输出到指定文件中
144 
145 [doc.XMLData  wrtiteToFile:self.xmlPath atomically:YES] ; //
146 
147 self.idField.text = nil;
148 
149 self.nameField.text = nil;
150 
151 self.authorField.text = nil;
152 
153 self.remarkField.text = nil;
154 
155 // 创建并显示提示框
156 
157 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@”提示”
158 
159 message:@”添加成功!160 
161 delegate:nil
162 
163 cancelButtonTitle:@”确定”
164 
165 otherButtonTitles:nil];
166 
167 [alert  show];
168 
169 }
170 
171 else
172 
173 {
174 
175   // 创建并显示提示框
176 
177 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@”提示”
178 
179 message:@”您必须为所有信息都输入有效的值”
180 
181 delegate:nil
182 
183 cancelButtonTitle:@”确定”
184 
185 otherButtonTitles:nil];
186 
187 [alert  show];
188 
189 }
190 
191 }
192 
193 // 定义获取XML文档存储路径的方法
194 
195 - (NSString*)xmlPath
196 
197 {
198 
199    // 获取应用程序沙盒的Document路径
200 
201   NSArray*  paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
202 
203 NSUserDomainMask, YES);
204 
205 NSString* documentsDirectory = [paths objectAtIndex:0];
206 
207 // 返回XML文档的存储路径
208 
209     return [NSString  stringWithFormat:@%@/books.xml , documentsDirectory];
210 
211 }
212 
213 @end

 

   上面程序中的红色字代码是利用GDataXML生成或修改XML文档的关键代码,如果底层XML文档已经存在,则程序调用①号红色字代码获取已有XML文档的根元素;如果底层XML文档不存在,则调用②号红色字代码生成新的元素

一旦获取到XML文档的根元素之后,接下来即可利用元素之间的父子关系来添加新的子元素,或对已有的子元素进行修改---------这些就是上面程序中中间的红色字代码所完成的工作.

当整个XML文档生成、修改完成之后,接下来程序调用③号红色字代码将XML文档输出到指定文件.

XML文档保存在应用程序山河的Document目录下

 

posted @ 2015-12-22 14:51    阅读(609)  评论(0编辑  收藏  举报