下面是一段XML文本:
大家可以看看,有什么特点。
好了,我就不卖关子了,第一行介绍XML的版本和编码格式。
下面就是一个个形如<></>而且都是成对出现的,这个叫做标签。<>这是开标签,</>这是关标签。要获取某个标签的数据,需要一步步遍历下去,直到找到你所需要的那个标签下的内容,比如我要获取老师晁辉的年龄<teacher></teacher>里,那我先找到开标签为teacher的,然后找第一个面的名字是不是晁辉,不是那我就直接到第二个teacher,直到第三个teacher是叫晁辉,那我再找第三个teacher下的子标签的开标签为<age>的,那这个age的内容就是我们所需的晁辉的年龄。是不是觉得真特么麻烦??对的。这是没办法的事,XML就是这么不爽,所以如果你们公司的后台给你的数据就是一堆XML,那恭喜你了。
那JSon长什么样呢??机智的少年,直接就会回到前两篇,找到咱们获取数据的那个URL,将这个可爱的URL,拷贝到你的浏览器的地址栏,前往,你就看到长长的可爱的JSon数据(因为咱们之前做的一直是JSon解析啊!!!)。
我截取了部分数据:
是不是觉得里面的数据很眼熟??对的,一个大括号里面对应一个dictionary,一个中括号对应一个array。就这么点。那我问你,要找dictionary和array里面的对应数据容易不容易??遍历起来方不方便(大声告诉我!),所以啊,拿到JSon数据,你应该放声大笑。下面XML会用代码教你们做人~~~
XML解析又有sax和DOM解析之分,前一个是逐行解析,文件损坏对解析没影响,但是就和我上面和大家介绍的一样,需要一个一个标签去读,读到你崩溃为止。后一个一个是完全读入整个文件,简单粗暴。但是文件一旦有某个位置错误,就GG了,而且灰常消耗内存。所以啊,都不好用,但非得用。
先遵守NSXMLParserDelegate协议。
- // 读入文件
- NSString *path = [[NSBundle mainBundle] pathForResource:@"teacher" ofType:@"xml"];
- // NSXMLParser对象
- NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[NSData dataWithContentsOfFile:path]];
- // 设置delegate对象(解析过程放在代理中执行)
- parser.delegate = self;
- // 执行解析
- [parser parse];
代理方法里面进行逐行解析:
- // 开始标签
- - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
- {
- NSLog(@"%@", elementName);
- }
- // 结束标签
- - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
- {
- NSLog(@"%@", elementName);
- }
- // 取值
- - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
- {
- NSLog(@"%@", string);
- }
注意:sax解析是系统提供的一套解析方案,sax解析的优点:逐行解析,不会一次性读入整个文件,减小内存消耗。因为是逐行解析,xml文件损坏对解析没影响;sax解析的缺点:因为是逐行解析,所以没办法获取文件的层级关系,对于程序员获取数据而言比较麻烦。
DOM解析需要引入两个文件。有兴趣自己动手的同学,需要注意。
就是上图的两个文件,拖进工程后,需要做三件事。
前两个是处理文件链接路径,下面一个是将MRC文件编译到ARC工程中所需的操作。
接下来上DOM解析代码:
- /********************************DOM*******************************/
- // 获取文件路径
- NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
- NSError *error;
- GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithXMLString:str options:0 error:&error];
- // 获取根节点
- // 不断的找子节点来获取数据
- GDataXMLElement *rootElement = document.rootElement;
- NSLog(@"%@", rootElement);
- // 获取子节点
- NSArray *array = rootElement.children;
- NSLog(@"%@", array[1]);
- // 获取子节点的子节点
- GDataXMLElement *childElement = array[1];
- GDataXMLElement *element = childElement.children[1];
- NSLog(@"%@", element);
- NSString *sex = element.stringValue;
- NSLog(@"%@", sex);
上面就是拿到一个节点,然后找子节点,逐行找。。。
第二种,已知节点名字,找到节点内容:
- /********************************DOM*******************************/
- // 获取文件路径
- NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
- NSError *error;
- GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithXMLString:str options:0 error:&error];
- // 第二种方式:使用elementForName:方法,给出一个节点的名字然后获取节点对应的数据
- GDataXMLElement *rootelement = document.rootElement;
- NSArray *arr = [rootelement elementsForName:@"teacher"];
- NSLog(@"%@", arr[1]);
- GDataXMLElement *element = arr[1];
- GDataXMLElement *sex = [element elementsForName:@"sex"][0];
- NSLog(@"%@", sex.stringValue);
第三种,绝对路径。
- /********************************DOM*******************************/
- // 获取文件路径
- NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
- NSError *error;
- GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithXMLString:str options:0 error:&error];
- NSArray *array = [document nodesForXPath:@"teachers/teacher/sex" error:nil];
- NSLog(@"%@", [array[1] stringValue]);
第四种,相对路径。
- /********************************DOM*******************************/
- // 获取文件路径
- NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
- NSError *error;
- GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithXMLString:str options:0 error:&error];
- NSArray *array = [document nodesForXPath:@"//age" error:nil];
- NSLog(@"%@", [array[2] stringValue]);
看到这里,是不是被恶心到了。。。
这个就非常简单了。一行代码搞定,拿到咱们的NSData,然后
- NSError *newError = nil;
- // 获取数据
- NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&newError];
第一个参数就是我们从服务器获取的data数据。第二个参数指的是你的容器类型,这是个枚举值。
- typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
- NSJSONReadingMutableContainers = (1UL << 0), // 用NSDictionary或者NSArray接收,可变的mutable也是可以的。
- NSJSONReadingMutableLeaves = (1UL << 1), // 用NSMutableString接收
- NSJSONReadingAllowFragments = (1UL << 2) // 既不是NSDictionary也不是NSArray的实例
- }
如果获取的数据的最外层是中括号(上面的截图里面最外层是大括号),那么这里用来接收数据的变量类型就不是NSDictionary而是NSArray了。
从本节的篇幅就可以看到,JSon用起来不是一般的方便,而XML怎么用都不爽。这个也是没办法的,只有央求你们的后台不会丢给你XML的数据了。