标签:xml xml解析 nsxmlparser sax xpath
<pre name="code" class="objc"><span style="font-family:Arial, Helvetica, sans-serif;"><span style="font-size:14px;"><span style="background-color: rgb(255, 255, 255);"></span></span></span><address><span style="font-size:14px;"> </span></address>
向服务器请求数据,那么数据必须以某个特定的格式存放,然后一方把数据按这种格式组织起来,另一方按相同的方式把数据解析数来,就像是我们人之间讲话交流,我们的话会转变成振动、在空气中传播、然后对方的耳朵感受这种振动,然后把振动转化为话,所以我认为格式的组织是为了更好的传递数据。一般网络数据会封装成两种格式进行传递:XML和json。
1、”解析“:
XML长得和HTML很像,打开浏览器的显示源码功能,可以看到一串串的<>标签,而解析XML也依靠于这些标签。首先说下我理解的“解析”,不管是XML还是json,实际就是一大段字符串,解析就是按XML或json的格式规范把这个字符串变成字典或数组,这样才能自由的获取里面的数据。比如:
<span style="font-size:14px;"><weather>晴转多云</weather> <wind>微风</wind> <temperature>34 ~ 23℃</temperature></span>weather标签里面是”晴转多云“,就是说天气是晴转多云,那么这就是字典里面的一个键值对,weather是键,晴转多云是值。XML、json和数组字典都是组织数据的东西,“解析”就是把数据从某种组织格式转为另一种。
2、DOM和SAX:
这是XML的两种解析方式,DOM是把XML文档整个的加载,对于这个文档里数据的结构都清楚了;然后可以使用XPath直接获取某个节点;而SAX是从XML头部逐条逐个标签的向下读,遇到一个什么东西就通知一下,所以它不需要XML文档已经全部获取,但是它只管得了当前读到的地方,前面读过的就取不到了,所以在结构上不是很清楚,但是相对快速、耗内存小。个人觉得DOM解析操作起来更方便一些。
3、关于解析类库的选择:
参看文章:iOS平台XML解析类库对比概述
4、系统的NSXMLParser的使用:
XML数据选择使用百度天气接口的数据,地址:http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&ak=5slgyqGDENN7Sy7pw29IUvrZ 。关于天气接口的配置,可以参考:百度天气接口
(1)获取数据:
<span style="font-size:14px;">-(void )getXMLData{ NSString * URLStr = @"http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&ak=5slgyqGDENN7Sy7pw29IUvrZ"; NSURL * url = [NSURL URLWithString:URLStr]; NSURLRequest * request = [[NSURLRequest alloc]initWithURL:url]; _XMLData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; }</span>
(2)构建NSXMLParser:
<span style="font-size:14px;">-(void )parserXMLData{ _parser = [[NSXMLParser alloc]initWithData:_XMLData]; _parser.delegate = self; if (![_parser parse]) { NSLog(@"Parser start error"); } } </span>这里是使用NSData对象构建,也可以使用文档资源地址构建- (id)initWithData:(NSData *)data、使用输入流构建:- (id)initWithStream:(NSInputStream *)stream。调用parse开启解析。需要设置委托对象,这样在解析到某个元素变迁或是字符的时候,会让委托对象调用委托方法,而就是在这些方法里面进行数据的处理。
<span style="font-size:14px;">-(void )parserDidStartDocument:(NSXMLParser *)parser{ //开始解析文档是调用 NSLog(@"doucment start"); } -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ //每次解析到一个标签的时候调用,例如上面<span style="font-family: Arial, Helvetica, sans-serif;"><weather>晴转多云</weather>中的</span><span style="font-family: Arial, Helvetica, sans-serif;"><weather>标签</span> _currentElement = elementName; //把当前的标签保存下来,便于下面方法里判断 if ([_currentElement isEqualToString:@"weather_data"]) { //当开始解析<span style="font-family: Arial, Helvetica, sans-serif;">weather_data这个标签的时候构建数组,用于保存多天的天气信息。</span> _weatherArray = [[NSMutableArray alloc]init]; }else if ([_currentElement isEqualToString:@"date"]&&_weatherArray){//因为date标签是每一天天气信息的开始变迁,所以在解析到date标签的时候构建一个字典,用来保存某一天的天气信息,并且加入到<span style="font-family: Arial, Helvetica, sans-serif;">_weatherArray里面</span> NSMutableDictionary * oneDayWeather = [[NSMutableDictionary alloc]init]; [_weatherArray addObject:oneDayWeather]; } } -(void )parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{ //每次解析到一个字符串,在XML文档里,除了标签,就是数据,而数据有些数字符串,所以字符串数据时会调用这个方法,例如上面的<span style="font-family: Arial, Helvetica, sans-serif;"><weather>晴转多云</weather>中的晴转多云。</span> string = [string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" \n\r"]]; //通过这个方法去掉空格、换行字符串,保证把有用的字符串存进来 if (_weatherArray&&string.length>0) { if ([_currentElement isEqualToString:@"date"]) { //使用<span style="font-family: Arial, Helvetica, sans-serif;">_currentElement的值来判断当前是处于哪一个标签内部</span> NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; //因为SAX解析从上到下,所以lastObject就是最新的一个字典,也就是当前需要存入数据的字典 [oneDayWeather setObject:string forKey:@"date"]; }else if ([_currentElement isEqualToString:@"dayPictureUrl"]){ NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; [oneDayWeather setObject:string forKey:@"dayPictureUrl"]; }else if ([_currentElement isEqualToString:@"nightPictureUrl"]){ NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; [oneDayWeather setObject:string forKey:@"nightPictureUrl"]; }else if ([_currentElement isEqualToString:@"weather"]){ NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; [oneDayWeather setObject:string forKey:@"weather"]; }else if ([_currentElement isEqualToString:@"wind"]){ NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; [oneDayWeather setObject:string forKey:@"wind"]; }else if ([_currentElement isEqualToString:@"temperature"]){ NSMutableDictionary * oneDayWeather = _weatherArray.lastObject; [oneDayWeather setObject:string forKey:@"temperature"]; } } } -(void )parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock{ //和上面的字符串类似,有些数据不是字符串,而是字节,这里就是NSData对象 NSLog(@"%@",[[NSString alloc]initWithData:CDATABlock encoding:NSUTF8StringEncoding]); } -(void )parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ // 当解析到一个标签的结束的时候调用,每一个标签都是开头、结尾两个成对存在的,例如<span style="font-family: Arial, Helvetica, sans-serif;"><weather>晴转多云</weather>中的<weather>和</weather>,当解析到</weather>的时候就是一个标签的结束,也就会调用这个方法。</span> //NSLog(@" elementName : %@ , namespaceURI : %@ , qualifiedName : %@ ",elementName,namespaceURI,qName); } -(void )parserDidEndDocument:(NSXMLParser *)parser{ //这是文档整个解析完毕的时候调用 NSLog(@"document end"); NSLog(@"%@",_weatherArray); } </span>上面列举了一些解析过程中调用的委托方法,还有许多其他方法,参考文档中NSXMLParserDelegate。似乎方法很详细,把解析过程的每个细节的考虑到了,但是感觉把XML中的数据合理的存放到数组字典里,真不是件容易的事,不想json,一句话就搞定了。SAX解析最大的不便是,当解析到某个标签的时候,你不知道它上一层的标签是什么,更不知道上上层的标签是什么,也就是说没有东西能告诉你整个文档的结构是什么样的。上面的例子是将链接中获得的天气XML文档中天气的部分取出来放进数组_weatherArray里面,也就是<weather_data>...</weather_data>这个标签内的内容。
SAX解析总的来说,不是很方便,如果数据的层次结构比较复杂,处理起来会很麻烦,所以要考虑DOM解析和json格式。
标签:xml xml解析 nsxmlparser sax xpath
原文地址:http://blog.csdn.net/u014131398/article/details/38705765