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

    前一篇文章已经介绍了如何通过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文件:

    [cpp] view plaincopy
     
    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文件

    [cpp] view plaincopy
     
    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委托中的几个方法。

    [cpp] view plaincopy
     
    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,然后做一些相应的操作(具体的话待会看源代码)。

    [cpp] view plaincopy
     
    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等。那么对读到的标签进行判断后就可以进行存储操作啦!

    [cpp] view plaincopy
     
    1. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
    2. {    
    3.      
    4. }   

    这里标签参数就是elementName。

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

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

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

    .h文件

    [cpp] view plaincopy
     
    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文件

    [cpp] view plaincopy
     
      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 
  • 相关阅读:
    Struts2+Spring3+Mybatis3开发环境搭建
    spring+struts2+mybatis
    【LeetCode】Populating Next Right Pointers in Each Node
    【LeetCode】Remove Duplicates from Sorted Array
    【LeetCode】Remove Duplicates from Sorted Array II
    【LeetCode】Binary Tree Inorder Traversal
    【LeetCode】Merge Two Sorted Lists
    【LeetCode】Reverse Integer
    【LeetCode】Same Tree
    【LeetCode】Maximum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/yjg2014/p/4549075.html
Copyright © 2011-2022 走看看