zoukankan      html  css  js  c++  java
  • iOS 详解NSXMLParser方法解析XML数据方法

    转载于:http://blog.csdn.net/crayondeng/article/details/8738811

    前一篇文章已经介绍了如何通过URL从网络上获取xml数据。下面介绍如何将获取到的数据进行解析。

    下面先看看xml的数据格式吧!

    [html] view plaincopy
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <Books>  
    3. <Book id="1">  
    4. <title>Circumference</title>  
    5. <author>Nicholas Nicastro</author>  
    6. <summary>Eratosthenes and the Ancient</summary>  
    7. </Book>  
    8. <Book id="2">  
    9. <title>Copernicus Secret</title>  
    10. <author>Jack Repcheck</author>  
    11. <summary>How the scientific revolution began</summary>  
    12. </Book>  
    13. <Book id="3">  
    14. <title>Angels and Demons</title>  
    15. <author>Dan Brown</author>  
    16. <summary>Robert Langdon is summoned to a Swiss</summary>  
    17. </Book>  
    18. </Books>  
    显然在这个xml中包括三本书的一些基本数据:id   title   author   summary  解析的过程就是将这些数据提取出来。

    先简单介绍一下xml数据解析吧。xml数据的解析一般有两种方式:SAX(Simple API for XML)和DOM (Document Object Model),事件和文档。

    dom实现的原理是把整个xml文档一次性读出,放在一个树型结构里。在需要的时候,查找特定节点,然后对节点进行读或写。他的主要优势是实现简单,读写平衡;缺点是比较占内存,因为他要把整个xml文档都读入内存,文件越大,这种缺点就越明显。

    sax的实现方法和dom不同。他只在xml文档中查找特定条件的内容,并且只提取需要的内容。这样做占用内存小,灵活。

    NSXMLParser 实现的是sax方法解析xml文件。

    下面进入主题介绍如何对xml进行解析:

    一、将上面的xml数据保存为Books.xml作为本地xml数据,并导入项目中。

    二、由于book中含有几个属性,所以这里第一个book类。

    Book.h文件:

    1. #import <Foundation/Foundation.h>  
    2.   
    3. @interface Book : NSObject  
    4.   
    5. @property (nonatomic, readwrite) NSInteger bookID;  
    6. @property (nonatomic, retain) NSString  *title;  
    7. @property (nonatomic, retain) NSString  *author;  
    8. @property (nonatomic, retain) NSString  *summary;  
    9.   
    10. @end  

    Book.m文件

    1. #import "Book.h"  
    2.   
    3. @implementation Book  
    4.   
    5. @synthesize bookID;  
    6. @synthesize title;  
    7. @synthesize author;  
    8. @synthesize summary;  
    9.   
    10. @end  

    三、要实现对xml数据的解析实际上是通过实现NSXMLParserDelegate委托中的几个方法。

    1. #pragma mark xmlparser    
    2. //step 1 :准备解析    
    3. - (void)parserDidStartDocument:(NSXMLParser *)parser    
    4. {    
    5.    
    6. }    
    7. //step 2:准备解析节点    
    8. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict    
    9. {    
    10.    
    11. }    
    12. //step 3:获取首尾节点间内容    
    13. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string    
    14. {    
    15.        
    16. }    
    17.     
    18. //step 4 :解析完当前节点    
    19. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
    20. {    
    21.      
    22. }    
    23.     
    24. //step 5:解析结束    
    25. - (void)parserDidEndDocument:(NSXMLParser *)parser    
    26. {    
    27.    
    28. }    
    29. //step 6:获取cdata块数据    
    30. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock    
    31. {    
    32.   
    33. }    


    在实现xml解析过程以上方法中的step3 、4、5是必须的,而step1、5可选。

    下面分别介绍:

    Step 1: 在开始解析之前的一些准备工作,例如初始化一些存储变量。在我的这个例子中,使用了一个Book实例变量来存储一本书(也即是一组信息),一个可变数组来存储这三本书(即每一组信息都当成这个数组中的一个元素),(此次要注意理解数据变量之间的关系),其他变量就暂不介绍啦(待会看源代码就可以了)。


    Step 2: 当解析器遇到xml的根标签和一组信息的开始标签时就开始调用这个方法,在这个xml文件中,遇到Books(xml文件的根标签),Book(一组信息的开始标签)时就会调用这个方法。那么也就可以知道这个方法在程序运行过程中被调用了多次。那么就可以用 if 语句判断遇到的是Books还是Book,然后做一些相应的操作(具体的话待会看源代码)。

    1. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict    
    2. {    
    3.    
    4. }    
    注意其中的参数:elementName表示遇到的标签,在这个程序中会遇到的是Books和Book;  解析到一个标签时,开始的 标签可能会有一些属性,例如在这里<Book id="1">

    那么id就是属性啦,在这个方法中他是用一个字典来保存的即(NSDictionary *)attributeDict,那么对这个字典操作就可以得到你要的value和key啦。

    Step 3:当解析器找到开始标签和结束标签之间的字符时,就调用这个方法,读取其中的内容。 注意:这里读取到的string在这个函数里面我们并不知道是那个属性的内容,意思就是假如string的内容是Circumference(Book 的title),但是我们不知道这个是title的内容;那么在哪里才知道,然后对它进行存储操作呢,不要着急,就是Step4啦!

    Step 4:当解析器读到结束标签时,就会调用这个方法。例如读到Books,Book,title等。那么对读到的标签进行判断后就可以进行存储操作啦!

    1. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
    2. {    
    3.      
    4. }   
    这里标签参数就是elementName。


    Step 5:对整个xml文件解析结束后的一些操作。

    Step 6:这个暂不解释(我还没有用到)。


    四、下面就是上代码的时候啦

    .h文件

    1. #import <UIKit/UIKit.h>  
    2.   
    3. @class AppDelegate,Book;  
    4. @interface ViewController : UIViewController <NSXMLParserDelegate> {  
    5.       
    6.     NSMutableString *currentElementValue;  //用于存储元素标签的值  
    7.       
    8.     NSMutableArray *books;  //用于存储一组书籍  
    9.       
    10.     Book *aBook;  //书籍实例,代表一本书  
    11.       
    12.     BOOL storingFlag; //查询标签所对应的元素是否存在  
    13.       
    14.     NSArray *elementToParse;  //要存储的元素  
    15. }  
    16. - (IBAction)xmlButton:(id)sender;  
    17.   
    18. @end  

    说明:这里我用一个按键来触发xml解析。

    .m文件

    1. #import "ViewController.h"  
    2. #import "AppDelegate.h"  
    3.   
    4. @interface ViewController ()  
    5.   
    6. @end  
    7.   
    8. @implementation ViewController  
    9.   
    10. - (void)viewDidLoad  
    11. {  
    12.     [super viewDidLoad];  
    13.     // Do any additional setup after loading the view, typically from a nib.  
    14.     //初始化要解析的元素标签  
    15.     elementToParse = [[NSArray alloc] initWithObjects:@"title",@"author",@"summary", nil];  
    16. }  
    17.   
    18. - (void)didReceiveMemoryWarning  
    19. {  
    20.     [super didReceiveMemoryWarning];  
    21.     // Dispose of any resources that can be recreated.  
    22. }  
    23.   
    24. - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {  
    25.     if([elementName isEqualToString:@"Books"]) {  
    26.         //Initialize the array.  
    27.         //在这里初始化用于存储最终解析结果的数组变量,我们是在当遇到Books根元素时才开始初始化  
    28.         books = [[NSMutableArray alloc] init];  
    29.         }  
    30.     else if([elementName isEqualToString:@"Book"]) {  
    31.           
    32.         //Initialize the book.  
    33.         //当碰到Book元素时,初始化用于存储Book信息的实例对象aBook  
    34.           
    35.         aBook = [[Book alloc] init];  
    36.           
    37.         //Extract the attribute here.  
    38.         //从attributeDict字典中读取Book元素的属性  
    39.           
    40.         aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue];  
    41.           
    42.         NSLog(@"ID:%i", aBook.bookID);  
    43.         }  
    44.     storingFlag = [elementToParse containsObject:elementName];  //判断是否存在要存储的对象  
    45. }  
    46.   
    47. - (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {  
    48.     // 当用于存储当前元素的值是空时,则先用值进行初始化赋值  
    49.     // 否则就直接追加信息  
    50.     if (storingFlag) {  
    51.         if (!currentElementValue) {  
    52.             currentElementValue = [[NSMutableString alloc] initWithString:string];  
    53.         }  
    54.         else {  
    55.             [currentElementValue appendString:string];  
    56.         }  
    57.     }  
    58.       
    59. }  
    60.   
    61. // 这里才是真正完成整个解析并保存数据的最终结果的地方  
    62. - (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {  
    63.       
    64.     if ([elementName isEqualToString:@"Book"]) {  
    65.         [books addObject:aBook];  
    66.         aBook = nil;  
    67.     }  
    68.       
    69.     if (storingFlag) {  
    70.         //去掉字符串的空格  
    71.         NSString *trimmedString = [currentElementValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
    72.           
    73.         //将字符串置空  
    74.         [currentElementValue setString:@""];  
    75.           
    76.         if ([elementName isEqualToString:@"title"]) {  
    77.             aBook.title = trimmedString;  
    78.             NSLog(@"title :%@",aBook.title);  
    79.         }  
    80.         if ([elementName isEqualToString:@"author"]) {  
    81.             aBook.author = trimmedString;  
    82.             NSLog(@"author :%@",aBook.author);  
    83.         }  
    84.         if ([elementName isEqualToString:@"summary"]) {  
    85.             aBook.summary = trimmedString;  
    86.             NSLog(@"summary :%@",aBook.summary);  
    87.         }  
    88.     }  
    89.       
    90. }  
    91.   
    92. - (IBAction)xmlButton:(id)sender {  
    93.     //打开xml文件,读取数据到NSData  
    94.     NSString *path = [[NSBundle mainBundle] pathForResource:@"Books" ofType:@"xml"];  
    95.     NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];  
    96.     NSData *data = [file readDataToEndOfFile];  
    97.     [file closeFile];  
    98.       
    99.     //测试从xml接受到的数据  
    100.     NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
    101.     NSLog(@"%@",dataString);  
    102.       
    103.     NSXMLParser *m_parser = [[NSXMLParser alloc] initWithData:data];  
    104.     //设置该类本身为代理类,即该类在声明时要实现NSXMLParserDelegate委托协议  
    105.     [m_parser setDelegate:self];  //设置代理为本地  
    106.       
    107.     BOOL flag = [m_parser parse]; //开始解析  
    108.     if(flag) {  
    109.         NSLog(@"解析指定路径的xml文件成功");  
    110.     }  
    111.     else {  
    112.         NSLog(@"解析指定路径的xml文件失败");  
    113.     }      
    114. }  
    115. @end  


    说明:

    1、其中我用了一些NSLog来输出相关的信息验证,实际使用过程中,去掉就ok啦!

    2、结合我上面的解释和代码,应该可以理解整个xml解析的过程的。

    3、这里我用的是本地的xml文件,如果是想进行网络xml数据的解析的话,那也是很简单的,就是通过url获取xml数据替换掉这里的本地xml,通过url获取xml可以参考上一篇博文。

  • 相关阅读:
    ASP.NET MVC preview 1升级到ASP.NET MVC preview 2的一些更改
    今天遇到一个非常奇怪的问题
    Microsoft ASP.NET MVC中Membership登陆的实现
    自己用的一个ASP.Net MVC分页拿出来分享下
    KnockoutJs学习笔记(一)
    KnockoutJs学习笔记(三)
    KnockoutJs学习笔记(二)
    KnockoutJs学习笔记(四)
    学习网站不定期更新
    一些好的网站
  • 原文地址:https://www.cnblogs.com/songfeixiang/p/3733654.html
Copyright © 2011-2022 走看看