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文档的过程如下. |
|
解析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目录下 |