文档章节

ios XML解析

AK_47
 AK_47
发布于 2014/07/13 23:16
字数 3357
阅读 25
收藏 1

网络数据的XML解析


网络应用中的数据解析,因为最近的应用,无论是Android的和ios平台的,一直用也是建议用的都是Json解析,

xml解析都有点被遗忘了。

然后最近自己在做着玩一个ios的小应用,涉及网络数据的抓取,一些网站可能都提供了自己api平台,这些一般都是支持

我们对于数据协议格式的设定的。但是后来我在找寻到一些Rss资源时,发现返回的数据都是xml格式的,

因此,那就只好用xml解析了。


XML解析其实这个概念出现了算够久了,以前javaweb什么到处都在用。这边我们主要大致介绍下,然后在在ios编程如何使用。


XML解析一般分两种模式SAX和DOM,事件和文档。具体解析google去吧,有详细。不过看了下面的两个例子,一般就了解了。


一:XML解析之SAX解析,以及对NSXMLParser的应用。

sax解析说白了,就是一个事物模型解析,从头开始读取文档然后根据读取到的头标签标签时要怎么处理,读完头标签后,理论上是读取标签值了,

然后读取后遇到结束标签等

简单举个例子

<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> 头标签,里面的xmlns,可以看成是属性
<channel>
<title>呵呵呵呵</title>结束标签,中间的“呵呵呵呵”是首尾标签标签值空间

.......

好了,那么在ios开发中如何使用。

SDK本身是提供了NSXMLParser解析器。

[cpp]  view plain copy
  1. -(BOOL)parser:(NSString*)string  
  2. {  
  3.     //系统自带的  
  4.         NSXMLParser *par = [[[NSXMLParser alloc] initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]]autorelease];  
  5.         [par setDelegate:self];//设置NSXMLParser对象的解析方法代理    
  6.         return [par parse];//调用代理解析NSXMLParser对象,看解析是否成功   }  
  7.   
  8. }  
  9.   
  10. #pragma mark xmlparser  
  11. //step 1 :准备解析  
  12. - (void)parserDidStartDocument:(NSXMLParser *)parser  
  13. {  
  14. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  15.    
  16. }  
  17. //step 2:准备解析节点  
  18. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict  
  19. {  
  20. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  21. }  
  22. //step 3:获取首尾节点间内容  
  23. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string  
  24. {  
  25.     NSLog(@"%@",NSStringFromSelector(_cmd) );  
  26. }  
  27.   
  28. //step 4 :解析完当前节点  
  29. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName  
  30. {  
  31.    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  32. }  
  33.   
  34. //step 5;解析结束  
  35. - (void)parserDidEndDocument:(NSXMLParser *)parser  
  36. {  
  37. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  38. }  
  39. //获取cdata块数据  
  40. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock  
  41. {  
  42. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  43. }  

1.初始化解析器,传入你要解析的数据。

2.parse,启动解析,返回一个是否解析成功Bool值。

3.基本你要处理的就在下面实现的1-5个代理方法了。

其实代理方法和详细,就是一个事物进行流程:

step1是准备解析,然后没意外就是执行到了——>

step2读取到第一个头节点了,然后如果内部有属性值,你可以获取出来,读完头节点,我们会进去值域——》

step3对于简单的节点,可能直接就是一个string值了,但是看例子我们会知道,很多情况下,该节点的值域包含的于是一个节点——》

这步其实分两种,如果是值,那么就是执行step4,获取值的字窜,如果是子节点呢,我们一看就知道,它又是进行了step2,

即读取到头标签了,其实你是很人读一片文章流程一样,只不过我们脑中有个印象<xxx>是头标签了,我们要做什么,独到 头标签的最后一个符号">"

下面进去值域,独到了字窜的话就调用了foundCharacters:(NSString *)string,如果又读到<xxx>这样的,那就又是头标签了。——》

step5就是读到开始尾标签符号了。

最后一个方法

foundCDATA:(NSData *)CDATABlock,其实也是一个格式

[html]  view plain copy
  1. <content:encoded>  
  2. <![CDATA[ 
  3. <img src="http://img1.douban.com/mpic/s10489201.jpg" style="float:right;margin-left:16px"/><a href="http://www.douban.com/people/maldini/">减卐肥™</a>评论: <a href="http://movie.douban.com/subject/6799191//">搜索</a><br/> <br/>评价: 力荐<br/><br/> 
  4. ]]>  
  5. </content:encoded>  

好了,方法和流程大致了解了,拿一个我最近遇到的例子,好多时候,我们会遇到这样读取一组类似于json中数组形式的数据

[html]  view plain copy
  1. <channel>  
  2. <title>我是标题</title>  
  3. <link>http://write.blog.csdn.net/postedit</link>  
  4. <description>...</description>  
  5. <language>zh-cn</language>  
  6. <pubDate>Fri, 03 Aug 2012 06:20:31 GMT</pubDate>  
  7. <item>...</item>  
  8. <item>...</item>  
  9. <item>...</item>  
  10. <item>...</item>  
  11. <item>...</item>  
  12. <item>...</item>  
  13. <item>...</item>  
  14. <item>...</item>  
  15. <item>...</item>  
  16. <item>...</item>  
  17. <item>...</item>  
  18. <item>...</item>  
  19. <item>...</item>  
  20. <item>...</item>  
  21. <item>...</item>  
  22. <item>...</item>  
  23. <item>...</item>  
  24. <item>...</item>  
  25. <item>...</item>  
  26. <item>...</item>  
  27. </channel>  

一般来说,我们要的数据其实都是这20个item,对吧,每个item下都是相同的3个标签,title,author,time。形式上
其实一种数组形式
那么要怎么解析呢
1,首先我们可能先申明一个array数组容器用来存放这个20个对象,然后每个item对象中又有3个元素,那么我们可以
考虑用一个字典数据结构来表示每个item。
2.需要至少申请两个空间来作为类似于“哨兵”存储当前执行到的节点名,以及节点的值。
3.然后每次执行到读取到item时,初始化我们上面说道的一个字典数据结构。
4.在foundCharacters:方法中一直保存当前最新的值(当然,这里面其实会有个小瑕疵,下面会说到)。
5.在标签结束的方法,我们把标签名和值已键值对存入上面初始化的字典容器中。
[cpp]  view plain copy
  1. #pragma mark xmlparser  
  2. //step 1 :准备解析  
  3. - (void)parserDidStartDocument:(NSXMLParser *)parser  
  4. {  
  5. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  6.       
  7.     parserObjects = [[NSMutableArray alloc]init];  
  8. }  
  9. //step 2:准备解析节点  
  10. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict  
  11. {  
  12. //    NSLog(@"%@",NSStringFromSelector(_cmd) );  
  13.       
  14.     self.currentText = [[NSMutableString alloc]init];  
  15.     [currentText release];  
  16.     if ([elementName isEqualToString:@"item"]) {  
  17.         NSMutableDictionary *newNode = [[ NSMutableDictionary alloc ] initWithCapacity : 0 ];  
  18.         twitterDic = newNode;  
  19.         [parserObjects addObject :newNode];  
  20.         [newNode release];  
  21.     }  
  22.     else if(twitterDic) {  
  23.         NSMutableString *string = [[ NSMutableString alloc ] initWithCapacity : 0 ];  
  24.         [twitterDic setObject :string forKey :elementName];  
  25.         [string release ];  
  26.         currentElementName = elementName;  
  27.     }  
  28.   
  29.       
  30. }  
  31. //step 3:获取首尾节点间内容  
  32. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string  
  33. {  
  34.     NSLog(@"%@",NSStringFromSelector(_cmd) );  
  35.     [currentText appendString:string];  
  36. }  
  37.   
  38. //step 4 :解析完当前节点  
  39. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName  
  40. {  
  41.     if ([elementName isEqualToString:@"item"]) {  
  42.         twitterDic = nil;  
  43.     }else   
  44.         if ([elementName isEqualToString:currentElementName]) {  
  45.           
  46.             if ([elementName isEqualToString:@"description"]  
  47.                 ||[elementName isEqualToString:@"content:encoded"]) {  
  48.                 [twitterDic setObject:Cdata forKey:currentElementName];  
  49.             }else {  
  50.                 [twitterDic setObject:currentText forKey:currentElementName];  
  51.             }  
  52.     }  
  53.   
  54. }  
  55.   
  56. //step 5;解析结束  
  57. - (void)parserDidEndDocument:(NSXMLParser *)parser  
  58. {  
  59. }  
  60. //获取cdata块数据  
  61. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock  
  62. {  
  63.   
  64.     Cdata =[[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];  
  65. }  

对于上面代码说几点
1.我次奥,有几处内存泄露~~~
2.在获取值为什么不直接currentString = string
这是实践发现的问题
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
 注意这个代理方法的注释
   // This returns the string of the characters encountered thus far. You may not necessarily get the longest character run. The parser reserves the right to hand these to the delegate as potentially many calls in a row to -parser:foundCharacters:
下面是google翻译。
这将返回迄今为止遇到的字符的字符串。你不一定得到的最长字符运行。解析器有权交行解析器可能多次呼吁这些委托:foundCharacters:
这个说明,在获取一个标签首尾间的字符数据时,这个方法可能被调用多次。
举个我碰到的最简单的列子
<copyright>&copy; 2012, douban.com.</copyright>
我在解析这个节点时,上面方法就调用了两次,
第一次只返回&,紧接着第二次返回copy; 2012, douban.com.
因此你如果要获取完整的的,应该用string的append方法来获取完整的一条记录。
3.解析速度的优化,比如我们只需要item中数据,那么在独到非这个域内的标签,我们的哨兵不需要追中的保存key和value值。
因此我做了一处字典的释放和判断,在found中想减少string的赋值,当然你也可以在全局添加个标记位来控制
但是总体来说,这种优化基本微乎其微,而且造成我内存莫名其妙的泄露了~~
4.以上思路可以参考,代码因为写的太冲忙,有写内存上的问题,就不要参考了,呵呵,过几天我子在改改,
可以做一个很好rss解析的模板。


二:Dom文档解析模型,TBXML第三方包应用。
dom解析模型就像一个树结构,节点,子节点,兄弟节点等等。
这个其实最后被我抛弃了,这个解析器太简化了,太简洁的东西导致控制的入口点太少,就比如一个一键优化的软件的概念是一样的,
一键清楚缓存,优化配置,文件归类等等。人为控制就少了,导致我解析上面那个模型时,只知道遍历存储~。但是这个解析期对部分要求不高的xml解析其实挺好分,真的很简洁。
[cpp]  view plain copy
  1. //- (void)recurrence:(TBXMLElement *)element {  
  2. //      
  3. //    NSString *eleName = [TBXML elementName:element];   
  4. //    NSString *eleText = [TBXML textForElement:element];  
  5. //    if ([eleName isEqualToString:@"item"]) {  
  6. //        self recurrence:element  
  7. //    }  
  8. //      
  9. //      
  10. //      
  11. //      
  12. //    do {  
  13. //          
  14. //        NSString *eleName = [TBXML elementName:element];   
  15. //        NSString *eleText = [TBXML textForElement:element];   
  16. //          
  17. //        //递归处理子树  
  18. //        if (element->firstChild) {  
  19. //            NSLog(@"<%@>:",eleName);// Display the name of the element  
  20. //              
  21. //            [self recurrence:element->firstChild];  
  22. //        }else {  
  23. //            NSLog(@"<%@>:%@",eleName,eleText);// Display the name of the element  
  24. //              
  25. //            TBXMLElement *parent = element->parentElement;  
  26. //            if ([[TBXML elementName:parent] isEqualToString:@"item"]) {  
  27. //                NLRssInfo *info = [[[NLRssInfo alloc]init] autorelease];  
  28. //                  
  29. //                if ([eleName isEqualToString:@"title"]) {  
  30. //                    info.title = eleText;   
  31. //                }  
  32. //                  
  33. //                  
  34. //                [dataArr addObject:info];  
  35. //            }  
  36. //              
  37. //        }  
  38. //          
  39. //          
  40. //        //迭代处理兄弟树  
  41. //    } while ((element = element->nextSibling));  
  42. //}  
递归遍历,常规的树操作,具体内容可以网上搜搜,很多。
并且开源库的好处就是有源代码,也就3个类,6个文件,有兴趣可以研究研究,貌似大部分代码是用C写的。

转载http://blog.csdn.net/nono_love_lilith/article/details/7829732

解析 web Service 的XML内容一直是一个难点,很多开发者在这一部分都十分的费力。下面我就我自己写的一个XML的例子来从头到尾的讲一遍其相关的内容。

在很多的情况下,一个服务是通过某种网络API暴露的,它规定客户端发送什么,服务会在响应里发送什么,一般的来说大部分都返回xml格式的数据。
我们来一个拿个接口实例来说一下:  http://data.3g.sina.com.cn/api/index.php?page=1&test=1&wm=b100&cid=43
这个一个网络请求地址,当网web Sevice发送这样的一个请求的时候返回的是这样的一个xml的数据:

上面的代码是connection的代理方法,很容易的看出来twitterData里就是我们取得的XML数据,就是我们后面要解析的东西。 [ self startTwitterParser] 这个方法被调用就是要正式的解析XML数据了,如下:

//开始对返回的 data进行解析 ————

-(void )startTwitterParser

{

NSXMLParser *parser =[[ NSXMLParser alloc ] initWithData : twitterData ];

parser.delegate = self ;

[parser parse ];

[parser release ];

}

然后就是难点了-如何解析出你想要的内容。

#pragma mark NSXMLParserDelegate--->

 

- (void )parserDidStartDocument:(NSXMLParser *)parser

{

twitterDic = [[ NSMutableDictionary alloc] initWithCapacity: 0 ]; // 每一条信息都用字典来存;

parserObjects = [[ NSMutableArray alloc ] init ]; //每一组信息都用数组来存,做后得到的数据就在这个数组中

}

 

- (void )parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

{

if ([elementName isEqualToString :@"item" ]) // 找节点进行解析

{

NSMutableDictionary *newNode = [[ NSMutableDictionary alloc ] initWithCapacity : 0 ];

[parserObjects addObject :newNode];

twitterDic = newNode;

}

else if ( twitterDic)

{

 

if ([elementName isEqualToString :@"enclosure" ])

{

//NSLog(@"%@",attributeDict);//存到字典下了

if ([[attributeDict valueForKey :@"url" ] hasSuffix :@"jpg" ]) // 把 encolsuer 下的节点放在字典中

{

[twitterDic setObject :[attributeDict valueForKey :@"url" ] forKey :@"image" ];

}

else

{

[twitterDic setObject :[attributeDict valueForKey :@"url" ] forKey :@"video" ];

}

 

}

else

{

NSMutableString *string = [[ NSMutableString alloc ] initWithCapacity : 0 ];

[twitterDic setObject :string forKey :elementName];

[string release ];

currentText = [[NSString alloc ] init ];

currentElementName = elementName;

}

}

}

 

- (void )parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

{

currentText = [[ NSString alloc] initWithString:string];

}

 

 

- (void )parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString *)qName

{

if ([elementName isEqualToString :currentElementName ])

{

[ twitterDic setObject : currentText forKey : currentElementName]; // 把其他节点放在字典中

}

}

 

 

-(void )parserDidEndDocument:(NSXMLParser *)parser// 得到的解析结果

{

NSLog( @"%d %@" ,[ parserObjects count],[[ parserObjects objectAtIndex: 0 ] valueForKey: @"title" ]);

}

#pragma mark NSXMLParserDelegate end----->


上面这个些方法都是NSXMLParser的代理方法,分别扮演着不同的角色
首先是  - (void )parserDidStartDocument:(NSXMLParser *)parser
这个方法是解析的开始的方法,我在这一步做的就是初始化了数组和字典了---就是以后存储数据的容器。
接着就是第一步的解析:

- (void )parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

{

if ([elementName isEqualToString :@"item" ]) // 找节点进行解析

{

NSMutableDictionary *newNode = [[ NSMutableDictionary alloc initWithCapacity : 0 ];

[parserObjects addObject :newNode];

twitterDic = newNode;

}

else if ( twitterDic)

{

 

if ([elementName isEqualToString :@"enclosure" ])

{

//NSLog(@"%@",attributeDict);//存到字典下了

if ([[attributeDict valueForKey :@"url" ] hasSuffix :@"jpg" ]) // 把 encolsuer 下的节点放在字典中

{

[twitterDic setObject :[attributeDict valueForKey :@"url" ] forKey :@"image" ];

}

else

{

[twitterDic setObject :[attributeDict valueForKey :@"url" ] forKey :@"video" ];

}

 

}

else

{

NSMutableString *string = [[ NSMutableString alloc initWithCapacity : 0 ];

[twitterDic setObject :string forKey :elementName];

[string release ];

currentText = [[NSString alloc ] init ];

currentElementName = elementName;

}

}

}

 

- (void )parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

{

currentText = [[ NSString allocinitWithString:string];

}

 

 

- (void )parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

{

if ([elementName isEqualToString :currentElementName ])

{

[ twitterDic setObject : currentText forKey : currentElementName]; // 把其他节点放在字典中

}

}

 

-(void )parserDidEndDocument:(NSXMLParser *)parser// 得到的解析结果

{

NSLog( @"%d %@" ,[ parserObjects count],[[ parserObjects objectAtIndex: 0 valueForKey: @"title"]);

}

 

通过分析xml内容的格式来看整个XML 是以<item>为节点的20条信息内容,而且每个<item>节点下有这着不同的信息,其中有个信息 是<enolsure>,它的下面又有几条信息。按照这样的格式分析,写下了以上代码。大家在写代码的时候要根据自己的需求来写的。通过不停 的触发这些代理方法,直到XML被解析完毕,20条信息就存在数组parserObjects里面了,而且每条信息都以字典的形式存在。于是一个我们可以 随时用的内容就生成了,上面最后一个代理方法的输出就是:20 和title下对应的字符串;


转载http://blog.csdn.net/sjzsp/article/details/6314714

© 著作权归作者所有

AK_47
粉丝 16
博文 533
码字总数 569998
作品 0
嘉定
程序员
私信 提问
2018 iOS 面试题大全(补充完整版)

原文地址:2018 iOS 面试题大全 由于原作者并没有继续更新,这里我转过来继续更新下 这个栏目将持续更新--请iOS的小伙伴关注! 1、iOS 应用导航模式有哪些? 2、iOS 中持久化方式有哪些? 3、...

Theendisthebegi
2018/11/15
0
0
基于原生的移动跨平台研究和实践

基于原生主要是针对基于webview+h5比较来说的,基于H5的我不想再讨论了,我想尝试的是从UI到功能都是原生,而不是用H5模拟的所谓原生体验。 背景 我们从开发角度来考虑,但凡想从事长远的开发...

voxer
2017/03/26
160
0
诚聘Ios/Android开发(上海知名券商)

Ios开发: Job Description 1、响应产品需求、完成IOS客户端相关内容的开发与设计; 2、新技术预研,协助完成方案选型和设计; 3、参与相关软件质量管理活动,确保设计、实现、测试工作按时保...

Jimmy007
2016/04/07
371
0
获取iOS设备上崩溃日志(Crash Log)的方法

获取iOS设备上崩溃日志(Crash Log)的方法:http://www.weste.net/2013/5-20/91509.html iOS怎么分析AppStore上面的Crash Log:http://m.blog.csdn.net/blog/tianjf0514/45201549 iOS Cra......

智能小松鼠
2015/08/25
1K
0
EBMIDE——服务脚本IOS(三):IOS语言

IOS简介 IOS是In/Out Script(输入/输出脚本)的简称,在我的设计中,用in,out,script3个节点来描述一个服务调用。 目前的问题 目前的IOS脚本部分是用XML节点来描述的,这样做降低了脚本语法...

彭博
2012/03/09
133
0

没有更多内容

加载失败,请刷新页面

加载更多

Java注解合并,注解继承

spring中有时候一个类上面标记很多注解。 实际上Java注解可以进行继承(也就是把多个注解合并成1个) 比如说SpringMVC的注解 @RestController@RequestMapping("/person") 可以合并为一个 @P...

物种起源-达尔文
18分钟前
4
0
撤消Git中一个文件的工作副本修改?

在最后一次提交之后,我修改了工作副本中的一堆文件,但是我想撤消对这些文件之一的更改,例如将其重置为与最新提交相同的状态。 但是,我只想撤消仅一个文件的工作副本更改,而没有其他操作...

技术盛宴
53分钟前
4
0
Qt编写气体安全管理系统28-模拟工具

一、前言 模拟工具在一些涉及到硬件通信的程序中特别有用,也特别需要,回顾这十年来做过的项目,95%的项目都是软硬件交互的,貌似软硬件结合的项目更有生命力一些,纯软件的或者纯硬件的,并...

飞扬青云
今天
4
0
关于生活方式

生活就是生活,但难免和工作混在一起,所以要建立自己的生活方式,把工作稍微隔开点。 首先呢,每周放假的两天肯定会: 洗衣服,收拾屋子,列计划是必须要做的事情。 (这里可能还包含一些处...

T型人才追梦者
今天
6
0
JVM

一、JVM一些基本概念 1、JVM和普通虚拟机 JVM:Java Virtual Machine,程序自己独立的运行环境;堆栈、寄存器、字节码指令;可以运行多种语言:Java、Scala、Grovvy; 普通虚拟机:能完整提供...

请把小熊还给我_m
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部