• 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目录下

  • 相关阅读:
    C++中的指针常量与常量指针
    Ubuntu16.04下安装ROS kinetic常见问题及解决方法
    关于安装ROS的资料备份
    后台模块--删除、修改用户信息
    客车网上售票系统--查询、添加用户
    客车网上售票系统--登录
    客车网上售票系统--需求分析(一)
    简单的邮件发送器(二)
    简单的邮件发送器(一)
    在CMD上用telnet远程登录发送邮件测试记录
  • 原文地址:https://www.cnblogs.com/congli0220/p/5066650.html
Copyright © 2020-2023  润新知