前段时间想找点事做,就是试着看能不能用豆瓣的API做点什么,于是就碰到了这个问题——XML解析。

  老师还没讲,只能自己去查。

  XML文档解析主要有SAX和DOM两种模式,IOS上两种模式都可以用,这里就不做过多介绍,我选择的SAX模式。

IOS解析XML用的是自带的NSXML框架,框架的核心是NSXMLParser类和它的委托协议NSXMLParserDelegate,其主要的解析工作是在NSXMLParserDelegate实现类中完成的。委托中定义了许多回掉方法,在SAX解析器从上到下遍历XML文档的过程中,遇到开始标签、结束标签、文档开始、文档结束和字符串结束是就会触发这些方法。这些方法有很多,下面我们列出5个常用的方法。

在文档开始时触发

 -(void)parserDidStartDocument:(NSXMLParser *)parser      

  遇到一个新标签是触发,其中namespaceURI是命名空间,qualifiedName是限定名,attributes是字典类型的属性集合。

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

  找到字符串时触发

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

  遇到结束标签时触发

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

  在文档结束时触发

-(void)parserDidEndDocument:(NSXMLParser *)parser         

下面通过一个具体的例子来看整个的调用与解析过程

首先这是我们将要解析的XML文件 "info.xml"

    ​    ​    ​<?xml version="1.0" encoding="UTF-8"?>

    ​    ​    ​<root>  ​    ​

    ​    ​    ​    ​ <person id="1">

    ​    ​    ​    ​    ​ <firstName>Wythe</firstName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <lastName>xu</lastName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <age>22</age> ​ ​ ​ ​ ​ ​ ​ ​ </person>
​ ​ ​
​ ​ ​ ​ <person id="2">
​ ​ ​ ​
​ ​ ​ ​ ​ <firstName>li</firstName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <lastName>si</lastName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <age>31</age>
​ ​ ​ ​
​ ​ ​ ​ </person>
​ ​ ​ ​
​ ​ ​ ​ ​<person id="3">
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <firstName>Dipen</firstName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <lastName>Shah</lastName>
​ ​ ​ ​ ​
​ ​ ​ ​ ​ <age>24</age>
​ ​ ​ ​
​ ​ ​ ​ </person>
​ ​ ​ ​
​ ​ ​</root>

接来来是一个头文件 "ViewController.h"

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<NSXMLParserDelegate>

@property NSXMLParser *parser;
@property NSMutableArray *person;
@property NSString *currenttag; @end

然后是它的实现文件  "ViewController.m"

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize  parser = _parser , person = _person , currenttag = _currenttag;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
} - (void)viewDidLoad
{
[super viewDidLoad]; NSString *xmlFilePath = [[NSBundle mainBundle]pathForResource:@"info"ofType:@"xml"]; NSData *data = [[NSData alloc]initWithContentsOfFile:xmlFilePath]; self.parser = [[NSXMLParser alloc]initWithData:data]; self.parser.delegate = self; [self.parser parse]; NSLog(@"%@",_person); } - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} #pragma mark delegate method -(void)parserDidStartDocument:(NSXMLParser *)parser
{
_person = [[NSMutableArray alloc]init];
NSLog(@"start parse 1");
} -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
_currenttag = elementName; if ([_currenttag isEqualToString:@"person"]) {
NSString *_id = [attributeDict objectForKey:@"id"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
[dict setObject:_id forKey:@"id"];
[_person addObject:dict];
} NSLog(@"start element");
} -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSMutableDictionary *dict = [_person lastObject]; if ([_currenttag isEqualToString:@"firstName"] && dict) {
[dict setObject:string forKey:@"firstName"]; }
if ([_currenttag isEqualToString:@"lastName"] && dict) {
[dict setObject:string forKey:@"lastName"];
}
if ([_currenttag isEqualToString:@"age"] && dict) {
[dict setObject:string forKey:@"age"];
} NSLog(@"found characters");
} -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
_currenttag = nil; NSLog(@"end element");
} -(void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"parse end");
}
@end

通过断电和输出信息,我们可以知道整个解析过程是 开始解析文档、开始标签、找到字符串、结束标签、文档结束。

-- ::32.920 xmlforblog[:60b] start parse
-- ::32.921 xmlforblog[:60b] start element
-- ::32.922 xmlforblog[:60b] found characters
-- ::32.922 xmlforblog[:60b] start element
-- ::32.922 xmlforblog[:60b] found characters
-- ::32.922 xmlforblog[:60b] start element
-- ::32.923 xmlforblog[:60b] found characters
-- ::32.923 xmlforblog[:60b] end element
-- ::32.923 xmlforblog[:60b] found characters
-- ::32.923 xmlforblog[:60b] start element
-- ::32.924 xmlforblog[:60b] found characters
-- ::32.924 xmlforblog[:60b] end element
-- ::32.924 xmlforblog[:60b] found characters
-- ::32.924 xmlforblog[:60b] start element
-- ::32.925 xmlforblog[:60b] found characters
-- ::32.925 xmlforblog[:60b] end element
-- ::32.925 xmlforblog[:60b] found characters
-- ::32.925 xmlforblog[:60b] end element
-- ::32.926 xmlforblog[:60b] found characters
-- ::32.926 xmlforblog[:60b] start element
-- ::32.928 xmlforblog[:60b] found characters
-- ::32.929 xmlforblog[:60b] start element
-- ::32.929 xmlforblog[:60b] found characters
-- ::32.929 xmlforblog[:60b] end element
-- ::32.930 xmlforblog[:60b] found characters
-- ::32.930 xmlforblog[:60b] start element
-- ::32.930 xmlforblog[:60b] found characters
-- ::32.930 xmlforblog[:60b] end element
-- ::32.931 xmlforblog[:60b] found characters
-- ::32.931 xmlforblog[:60b] start element
-- ::32.931 xmlforblog[:60b] found characters
-- ::32.931 xmlforblog[:60b] end element
-- ::32.931 xmlforblog[:60b] found characters
-- ::32.932 xmlforblog[:60b] end element
-- ::32.932 xmlforblog[:60b] found characters
-- ::32.932 xmlforblog[:60b] start element
-- ::32.932 xmlforblog[:60b] found characters
-- ::32.933 xmlforblog[:60b] start element
-- ::32.933 xmlforblog[:60b] found characters
-- ::32.933 xmlforblog[:60b] end element
-- ::32.933 xmlforblog[:60b] found characters
-- ::32.934 xmlforblog[:60b] start element
-- ::32.934 xmlforblog[:60b] found characters
-- ::32.934 xmlforblog[:60b] end element
-- ::32.934 xmlforblog[:60b] found characters
-- ::32.935 xmlforblog[:60b] start element
-- ::32.935 xmlforblog[:60b] found characters
-- ::32.935 xmlforblog[:60b] end element
-- ::32.935 xmlforblog[:60b] found characters
-- ::32.936 xmlforblog[:60b] end element
-- ::32.936 xmlforblog[:60b] found characters
-- ::32.936 xmlforblog[:60b] end element
-- ::32.936 xmlforblog[:60b] parse end
-- ::32.936 xmlforblog[:60b] (
{
age = ;
firstName = Wythe;
id = ;
lastName = xu;
},
{
age = ;
firstName = li;
id = ;
lastName = si;
},
{
age = ;
firstName = Dipen;
id = ;
lastName = Shah;
}
)

执行结果

而我们的处理主要是在 开始标签、找到字符串 (

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

中。

遇到开始标签时,我们现判断标签,名字,如果是person,表明接下来就是person的信息,这样我们就先创建一个可变字典,以便将来存放它的值。

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
_currenttag = elementName; if ([_currenttag isEqualToString:@"person"]) {
NSString *_id = [attributeDict objectForKey:@"id"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
[dict setObject:_id forKey:@"id"];
[_person addObject:dict];
} NSLog(@"start element");
}

在找到字符串时,我们就是通过判断当前标签名,将对应的信息保存到刚刚创建的字典中

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSMutableDictionary *dict = [_person lastObject]; if ([_currenttag isEqualToString:@"firstName"] && dict) {
[dict setObject:string forKey:@"firstName"]; }
if ([_currenttag isEqualToString:@"lastName"] && dict) {
[dict setObject:string forKey:@"lastName"];
}
if ([_currenttag isEqualToString:@"age"] && dict) {
[dict setObject:string forKey:@"age"];
} NSLog(@"found characters");
}

不断循环这样的过程,最后我们就可以解析出整个XML文档。

另外说一句,这只是解析一般的文档,如果你跟我曾经一样学会这个就去解析豆瓣API的XML文档,会发现行不通。这时因为许多网站因为它的数据较多,为了避免标签的重复,使用了命名空间,带有命名空间的XML文档解析和这稍有不同。

以后我会写带命名空间的XML文档解析,敬请期待。

拖了快一个月了,今天终于写完。以后不能这么懒了

IOS 解析XML文档的更多相关文章

  1. Objective-C ,ios,iphone开发基础:使用GDataXML解析XML文档,(libxml/tree.h not found 错误解决方案)

    使用GDataXML解析XML文档 在IOS平台上进行XML文档的解析有很多种方法,在SDK里面有自带的解析方法,但是大多情况下都倾向于用第三方的库,原因是解析效率更高.使用上更方便 这里主要介绍一下 ...

  2. 网络电视精灵~分析~~~~~~简单工厂模式,继承和多态,解析XML文档,视频项目

    小总结: 所用技术: 01.C/S架构,数据存储在XML文件中 02.简单工厂模式 03.继承和多态 04.解析XML文档技术 05.深入剖析内存中数据的走向 06.TreeView控件的使用 核心: ...

  3. 使用dom4j解析XML文档

    dom4j的包开源包,不属于JDK里面,在myeclipse中要单独导入在项目中,这里不累赘了 做这个过程,很慢,因为很多方法没用过不熟悉,自己得去查帮助文档,而且还得去试,因为没有中文版,英文翻译不 ...

  4. 四种生成和解析XML文档的方法详解(介绍+优缺点比较+示例)

    众所周知,现在解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J 下面首先给出这四种方法的jar包下载地址 DOM:在现在的Java JDK里都自带了,在xml- ...

  5. java解析xml文档(dom)

    DOM解析XML文档 读取本地的xml文件,通过DOM进行解析,DOM解析的特点就是把整个xml文件装载入内存中,形成一颗DOM树形结构,树结构是方便遍历和和操纵. DOM解析的特性就是读取xml文件 ...

  6. java 解析XML文档

    Java 解析XML文档 一.解析XML文档方式: 1.DOM方式:将整个XML文档读取到内存中,按照XML文件的树状结构图进行解析. 2.SAX方式:基于事件的解析,只需要加载XML中的部分数据,优 ...

  7. DOM生成XML文档与解析XML文档(JUNIT测试)

    package cn.liuning.test; import java.io.File; import java.io.IOException; import javax.xml.parsers.D ...

  8. [置顶] stax解析xml文档的6种方式

    原文链接:http://blog.csdn.net/u011593278/article/details/9745271 stax解析xml文档的方式: 基于光标的查询: 基于迭代模型的查找: 基于过 ...

  9. 浅谈用java解析xml文档(四)

    继续接上一文,这一阵子因为公司项目加紧,导致最后一个解析xml文档的方式,还没有总结,下面总结使用dom4J解析xml. DOM4J(Document Object Model for Java) 使 ...

随机推荐

  1. VTK初学一,vtkDelaunay2D创建球冠曲面

    #ifndef INITIAL_OPENGL #define INITIAL_OPENGL #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRend ...

  2. 精通CSS+DIV基础总结(二)

    上一篇我们已经总结了部分CSS+DIV相关知识,这篇我们接着总结,从下边几个方面学习一下: 一,我们看如何设置网页的背景,顾名思义背景可以通过颜色和图片来设置,下边我们看一下如何设置: 颜色的设置非常 ...

  3. Linux C 程序的开发环境

    1.开发环境的构成 编辑器 vim,vi 编译器 gcc 调试器 gdb 函数库glibc 系统头文件glibc_header 2.gcc编译器 功能强大.性能优越的多平台编译器,gcc可以将c.c+ ...

  4. [20160711][在Windows下调用neven链接库]

    相关说明 这篇文档是接前篇[20160711][neven代码移植Windows]和[20160711][VS2012配置OpenCV2.4.9]下完成,首先需要通过篇文档编译出neven动态链接库和 ...

  5. Net包管理NuGet(3)搭建私服及引用私服的包

    1,打开vs创建项目(ASP.NET WEB空项目)假设命名为MyNuGet 空项目解决方案如图 2,右键引用>管理NuGet程序包>切到浏览搜索NuGet.Server然后安装(3.1. ...

  6. Spring的原理性总结

    一.Bean的生命过程 Bean的生命过程可以借鉴Servlet的生命过程,了解其生命过程对于不管是思想还是以后的使用都很有帮助: Bean可以通过两种方式进行加载,分别是使用BeanFactory ...

  7. MVC源码分析 - View

    感觉好久没有学习了, 汗. 年就这么过完了, 感觉没有尝到过年的味道. 现在的年过的有些冷清了. 除了体重证明着我过了一个年, 还有一件值得开心的事情, 终于把女朋友变成未婚妻了. 这是一大进步吧. ...

  8. 【译】EntityFramework6与EntityFrameworkCore的区别

    EntityFramework6 EF6 是一个久经考验的数据库访问技术,发展多年,拥有许多特性,并且成熟稳定.2008年EF作为 .Net 3.5 Sp1 和Visual Studio 2008 S ...

  9. bootstrap自适应栅格系统布局

  10. 不能使用控制器“XXXController”的单个实例处理多个请求。如果正在使用自定义控制器工厂,请确保它为每个请求创建该控制器的新实例。

    原因:应用@{Html.RenderAction("aaa","XXX");}时路径路由和动作控制器不能是相同的,不然会的错. 比如:http://localh ...