Json和XML解析

NSXMLParse

关于XML,有两种解析方式,分别是SAX(Simple API for XML,基于事件驱动的解析方式,逐行解析数据,采用协议回调机制)和DOM(Document Object Model ,文档对象模型。解析时需要将XML文件整体读入,并且将XML结构化成树状,使用时再通过树状结构读取相关数据,查找特定节点,然后对节点进行读或写)。苹果官方原生的NSXMLParse类库采用第一种方式,即SAX方式解析XML,它基于事件通知的模式,一边读取文档一边解析数据,不用等待文档全部读入以后再解析,所以如果你正打印解析的数据,而解析过程中间出现了错误,那么在错误节点之间的数据会正常打印,错误后面的数据不会被打印。解析过程由NSXMLParserDelegate协议方法回调。

插句题外话先,我在写这种方式解析XML数据的Demo时折腾了整整一天,说起来都有些不好意思了。程序运行的时候一直出现不能完成解析的情况,各种查各种试,真的是整了整整一天的时间。就在崩溃的边缘的时候,我竟然发现在我自己写XML文件时少写了一个“/。。。瞬间感觉整个世界都崩塌了。所以特地记下来警示自己也顺便给大家提个醒,在这种低级失误上浪费整整一天的时间,要多不值有多不值。谨记,谨记。

我们遵循MVC,首先我们创建模型,新建一个person类,存放XML文件中描述的person属性。再来一个解析XML文件的工具类XMLUtil,我们在里面实现文件的获取,代理方法的实现。

先来看这两个类的代码:

//person.h

#import <Foundation/Foundation.h>

@interface person : NSObject
@property (nonatomic, copy) NSString *pid;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, copy) NSString *age;
@end
//XMLUtil.h

#import <Foundation/Foundation.h>
#import "person.h"
//声明代理
@interface XMLUtil : NSObject<NSXMLParserDelegate>
//添加属性
@property (nonatomic, strong) NSXMLParser *par;
@property (nonatomic, strong) person *person;
//存放每个person
@property (nonatomic, strong) NSMutableArray *list;
//标记当前标签,以索引找到XML文件内容
@property (nonatomic, copy) NSString *currentElement;

//声明parse方法,通过它实现解析
-(void)parse;
@end

//XMLUtil.m

#import "XMLUtil.h"

@implementation XMLUtil

- (instancetype)init{
    self = [super init];
    if (self) {
        //获取事先准备好的XML文件
        NSBundle *b = [NSBundle mainBundle];
        NSString *path = [b pathForResource:@"test" ofType:@".xml"];
        NSData *data = [NSData dataWithContentsOfFile:path];
        self.par = [[NSXMLParser alloc]initWithData:data];
        //添加代理
        self.par.delegate = self;
        //初始化数组,存放解析后的数据
        self.list = [NSMutableArray arrayWithCapacity:5];
    }
    return self;
}

//几个代理方法的实现,是按逻辑上的顺序排列的,但实际调用过程中中间三个可能因为循环等问题乱掉顺序
//开始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidStartDocument...");
}
//准备节点
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict{

    self.currentElement = elementName;

    if ([self.currentElement isEqualToString:@"student"]){
        self.person = [[person alloc]init];

    }

}
//获取节点内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{

    if ([self.currentElement isEqualToString:@"pid"]) {

        [self.person setPid:string];
    }else if ([self.currentElement isEqualToString:@"name"]){
        [self.person setName:string];
    }else if ([self.currentElement isEqualToString:@"sex"]){
        [self.person setSex:string];
    }else if ([self.currentElement isEqualToString:@"age"]){

        [self.person setAge:string];
    }
}

//解析完一个节点
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName{

    if ([elementName isEqualToString:@"student"]) {
        [self.list addObject:self.person];
    }
    self.currentElement = nil;
}

//解析结束
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidEndDocument...");
}

//外部调用接口
-(void)parse{
    [self.par parse];

}

@end

OK,总算是大功告成,如果对代理的使用比较熟悉的话,这部分内容其实还蛮简单的。如果被代码转来转去弄晕了的话可以在每个block的最后都加一个打印输出,做好标记,你就能弄懂程序的执行顺序了。

我们点击NSXMLParse,有了!

GDataXML

来看GDataXML,它是一种DOM方式的解析类库。DOM实现的原理是把整个xml文档一次性读出,放在一个树型结构里。在需要的时候,查找特定节点,然后对节点进行读或写。

在使用之前呢,我们还是先从网上下载GDataXML包,里面两个文件GDataXMLNode.h和GDataXMLNode.m导入到项目中来,编译,发现报错了,这是因为GDataXML是依赖libmxl2的,我们要去项目的Target中做一些设置。

  • 找到项目的Tarfet,进入Build Phases里面的Link Binary With Libraries,点击“加号”,搜索libxml,把出现的包添加进去,这里最新版的XCode7和iOS9中,是libxml.2.2.tbd。
  • 再来到Build Settings,我们可以搜索一下,找到Header Search Paths,添加路径“/usr/include/libxml2”。
  • 再找到Other Link Flags,添加“-libxml2“
  • 还有就是如果你下载的GDataXML是不支持ARC的,那么你就要像上面那样去添加“-fno-objc-arc”,这个视你下载的GDataXML包版本而定。

再次编译,就顺利通过了。

接下来看看我们怎么用这个东西。贴代码之前我真的想说一句,比起苹果原生的类库,这些开源的第三方类库真的在用起来的时候不知道有多舒服,懒人必备啊。在实际的开发中可以为我们节省很多的时间与精力,但是还是要搞懂人家原生的东西,这样才叫学会了么。

//ViewController.m

- (IBAction)GDataXML:(id)sender {

    NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"xml"];
    NSData *data = [[NSData alloc]initWithContentsOfFile:path];
    //对象初始化
    GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data error:nil];
    //获取根节点
    GDataXMLElement *rootElement = [doc rootElement];
    //获取其他节点
    NSArray *students = [rootElement elementsForName:@"student"];
    //初始化可变数组,用来显示到textView
    self.GDatatext = [[NSMutableString alloc]initWithString:@""];
    for (GDataXMLElement *student in students) {
        //获取节点属性
        GDataXMLElement *pidElement = [[student elementsForName:@"pid"] objectAtIndex:0];
        NSString *pid = [pidElement stringValue];

        GDataXMLElement *nameElement = [[student elementsForName:@"name"] objectAtIndex:0];
        NSString *name = [nameElement stringValue];

        GDataXMLElement *sexElement = [[student elementsForName:@"sex"] objectAtIndex:0];
        NSString *sex = [sexElement stringValue];

        GDataXMLElement *ageElement = [[student elementsForName:@"age"] objectAtIndex:0];
        NSString *age = [ageElement stringValue];

        //调整一下姿势,添加到可变长字符串~~
        NSString *t = [NSString stringWithFormat:@"学号:%@ 姓名:%@ 性别:%@ 年龄:%@\n", pid, name, sex, age];
        [self.GDatatext appendString:t];
    }
    self.textView.text = self.GDatatext;
}

就一段,是不是看起来非常的舒服呢!

跑一下,跟我们刚才使用的NSXMLParse是不是一样呢?

哈,搞定!

XML解析总结

上述两种解析用到的类库分别代表了两种典型的XML数据解析方式,SAX和DOM,各有优势,比如在应对比较大数据量的XML文件时,后者由于需要先读取整个文档,性能和速度上就必然不及前者了。

其实现在在实际应用中XML已经越来越少了,但是说起iOS中的网络编程,就免不了和XML格式的数据打交道。还有就是,我们在这里仅仅介绍了两种常用的XML解析方式,如同解析Json数据一样,解析XML文件也有很多种方法,除了上述两种,还有比如像TBXML, TouchXML, KissXML, TinyXML等等,具体的使用方法可以去Github上找,都有使用方法的说明的。

文/神兽gcc(简书作者)
原文链接:http://www.jianshu.com/p/a54d367adb2a
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-11-06 17:03:39

Json和XML解析的相关文章

iOS - - JSON 和 XML解析

JSON 和 XML 一.JSON 1.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) 2.JSON的格式很像OC中的字典和数组 {"name" : "jack", "age" : 10} {"names" : ["jack", "rose", "jim"]} 标准JSON

.net Json和Xml解析

引言    Json和Xml是现在跨平台传输数据的主流格式,关于它们的解析,网上资料很多,我稍作整理,写成一个小demo,方便日后使用. JSON解析     能进行json解析的类库有很多,例如JavaScriptSerializer,DataContractJsonSerializer和开源类库Newtonsoft.Json.这里使用Newtonsoft.Json作个演示. 1.定义示例的类 public class Data { public string Name { get; set;

网络HTTP、JSON、XML解析等 复习

一.一个HTTP请求的基本要素1.请求URL:客户端通过哪个路径找到服务器 2.请求参数:客户端发送给服务器的数据* 比如登录时需要发送的用户名和密码 3.返回结果:服务器返回给客户端的数据* 一般是JSON数据或者XML数据 二.基本的HTTP请求的步骤(移动客户端)1.拼接"请求URL" + "?" + "请求参数"* 请求参数的格式:参数名=参数值* 多个请求参数之间用&隔开:参数名1=参数值1&参数名2=参数值2* 比如:

iOS XML解析使用-韩国庆

欢迎-------(北京-iOS移动开发金牌教师QQ:2592675215)韩老师给你带来XML解析课程 今天给大家讲解下xml解析的第三方简单用法:首先我解释下,json和xml解析格式. JSON格式,轻量级解析,一般都是字典套数组,或者数组套字典.非常简单. XML格式,一般都是节点形式的存在如: <?xml version="1.0" ?> <students> <student name="aa" gender="男

多线程与网络之JSON和XML数据的解析

*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } a { color: #4183C4; } a.absent { color: #cc0000; } a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: pointer; position: absolute

ios之json,xml解析

JSON解析步骤: 1.获取json文件路径 NSString*path = [[NSBundle mainBundle] pathForResource:@"Teacher"ofType:@"json"]; 2.读取文件中的data NSData *data = [NSData dataWithContentsOfFile:path]; 3.把data转化为可变数组或者可变字典 是字典还是数组要看json最外层数据是什么.NSJSONSerialization是重

ios 解析json,xml

一.发送用户名和密码给服务器(走HTTP协议) // 创建一个URL : 请求路径    NSString *urlStr = [NSString stringWithFormat:@"http://localhost:8080/MJServer/login?username=%@&pwd=%@",usernameText, pwdText];    NSURL *url = [NSURL URLWithString:urlStr];        // 创建一个请求    N

iOS开发——网络Swift篇&amp;JSON与XML数据解析

JSON与XML数据解析 JSON数据解析(内置NSJSONSerialization与第三方JSONKit) 一,使用自带的NSJSONSerialization 苹果从IOS5.0后推出了SDK自带的JSON解决方案NSJSONSerialization,这是一个非常好用的JSON生成和解析工具,效率也比其他第三方开源项目高. NSJSONSerialization能将JSON转换成Foundation对象,也能将Foundation对象转换成JSON,但转换成JSON的对象必须具有如下属性

JSON解析和XML解析

一. XML:用到一个开源解析类,GDataXMLNode(将其加入项目中),添加libxml2.dylib框架 经常用到的方法: 1.- (id)initWithXMLString:(NSString *)str options:(unsigned int)mask error:(NSError *)error 2.- (id)initWithData:(NSData *)data options:(unsigned int)mask error:(NSError *)error 这两个方法可