zoukankan      html  css  js  c++  java
  • ios-XML文档解析之SAX解析

    • 首先SAX解析xml
      *xml文档的格式特点是节点,大体思路是把每个最小的子节点作为对象的属性,每个最小子节点的'父'节点作为对象,将节点转化为对象,输出.

    • 每个节点都是成对存在的,有开始有结束.有始有终

    • 搭建本地服务器,并创建异步请求访问本地服务器中的数据video.xml

    #import "ViewController.h"
    #import "Video.h"
    @interface ViewController () <NSXMLParserDelegate>
    //vidios用来保存video对象的数组
    @property (nonatomic, strong) NSMutableArray *videos;
    //当前创建的video对象
    @property (nonatomic, strong) Video *currentVideo;
    //存储当前节点的内容
    @property (nonatomic, copy) NSMutableString *mString;
    @end
    
    
    • currentVideo每次寻找到节点名字为video的时候创建一个video对象,并添加到数组videos中.
    • mString是开始与结束节点之间的内容用mString来存储.在找到结束节点之后把mString通过setvalue...forkey...的方式(kvc)赋值给video对应的属性.
    • 通过SAX(NSXMLParser)方式解析xml文件要遵守协议NSXMLParserDelegate,设置代理.=self
    
    @implementation ViewController
    //懒加载--->初始化videos
    - (NSMutableArray *)videos {
        if (_videos == nil) {
            _videos = [NSMutableArray arrayWithCapacity:10];
        }
        return _videos;
    }
    //初始化mString
    - (NSMutableString *)mString {
        if (_mString == nil) {
            _mString = [NSMutableString string];
        }
        return _mString;
    }
    
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
            
        [self loadXML];
    
    }
    
    //异步请求xml
    - (void)loadXML {
        //异步请求服务器的xml文件
        NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            if (connectionError) {
                NSLog(@"连接错误 %@",connectionError);
                return;
            }
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) {
                //解析数据
                NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
                //设置代理
                parser.delegate = self;
                //开始执行代理的方法,代理的方法中开始解析的
                [parser parse];
            }else{
                NSLog(@"服务器内部错误");
            }
        }];
    }
    
    
    • 创建video分类
    #import <Foundation/Foundation.h>
    
    @interface Video : NSObject
    
    @property (nonatomic, copy) NSNumber *videoId;
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSNumber *length;
    @property (nonatomic, copy) NSString *videoURL;
    @property (nonatomic, copy) NSString *imageURL;
    @property (nonatomic, copy) NSString *desc;
    @property (nonatomic, copy) NSString *teacher;
    
    @property (nonatomic, readonly) NSString *time;
    
    - (instancetype)initWithDict:(NSDictionary *)dict;
    + (instancetype)videoWithDict:(NSDictionary *)dict;
    
    @end
    
    
    
    • .m文件
    #import "Video.h"
    
    @implementation Video
    
    - (instancetype)initWithDict:(NSDictionary *)dict {
        self = [super init];
        if (self) {
            [self setValuesForKeysWithDictionary:dict];
        }
        return self;
    }
    
    + (instancetype)videoWithDict:(NSDictionary *)dict {
        return [[self alloc] initWithDict:dict];
    }
    
    - (NSString *)time {
        int len = self.length.intValue;
        
        return [NSString stringWithFormat:@"%02d:%02d:%02d", len / 3600, (len % 3600) / 60, (len % 60)];
    }
    
    - (NSString *)description {
        return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher];
    }
    
    @end
    
    
    
    • 重写- (NSString *)description 为了在解析结束后打印出来看结果是否正确

    • 开始写代理方法

    
    //1 开始解析文档
    - (void)parserDidStartDocument:(NSXMLParser *)parser {
        NSLog(@"1 开始解析文档  %@",[NSThread currentThread]);
    }
    //2 找开始节点
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
        //elementName 节点的名称
        //attributeDict  标签的属性
        NSLog(@"2 找开始节点  %@--%@",elementName,attributeDict);
        
        //如果是video标签,创建video对象
        if ([elementName isEqualToString:@"video"]) {
            self.currentVideo = [[Video alloc] init];
            self.currentVideo.videoId = @([attributeDict[@"videoId"] intValue]);
            
            //添加到数组中
            [self.videos addObject:self.currentVideo];
            
        }
        
        
    }
    
    
    • 开始查找节点,如果节点名称==video则创建对象self.currentVideo = [[Video alloc] init];并且加入可变数组videos中.
    
    //3 找节点之间的内容
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
        //
        NSLog(@"3 找节点之间的内容 %@",string);
        //拼接字符串
        [self.mString appendString:string];
        
    }
    
    
    • 将开始于结束节点之间的内容用可变字符串mString保存起来.当找到结束节点名字后,利用结束节点名通过setvalue...forkey...方式把mString的内容赋值给对应的video(或者说self.currentVideo)的属性.
    
    //4 找结束节点
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
        //elementName 节点名称
        NSLog(@"4 找结束节点 %@",elementName);
        
        //判断标签是否是对应的属性
        if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) {
           
            //kvc 赋值的过程就是地址指向的过程,不会做类型转换
            [self.currentVideo setValue:self.mString forKey:elementName];
    
        }
        
        //清空可变字符串
        [self.mString setString:@""];
    }
    
    
    • 每次用完mString都要清空,不然前面的节点内容都会拼接到正在解析的节点的内容上.
    
    //5 结束解析文档
    - (void)parserDidEndDocument:(NSXMLParser *)parser {
        NSLog(@"5 结束解析文档");
        NSLog(@"%@",self.videos);
    }
    //6 解析出错
    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
        NSLog(@"出错");
    }
    
    
    
    • 文档解析完成.思路--->找最小子节点--->把最小子节点的父节点作为一个对象,最小子节点作为属性.通过读取到节点的名称,用kvc方式对对象的属性进行赋值.

    • 文档输出由于汉字编码是Unicode方式需要对其转换.

    • 下面演示不管是数组还是字典只要整体输出都会有编码问题

    • 解决方法:重写数组与字典的- (NSString *)descriptionWithLocale:(id)locale,写完不用导入头文件.

    • 创建NSObject 分类Log

    • 用block循环逐个输出解决汉字问题

    小结:XML和json解析的区别
    XML:
    * 优点:1>所有的语言中格式统一,数据共享比较方便
    * 缺点: 1>XML格式文件庞大,格式复杂,解析起来比较麻烦!压缩比例小。
    JOSN:
    * 优点:
    * 1>数据结构简单,易于读写,易于解析,压缩比例大。
    * 2>支持多种语言,java,ios,javascript,php等语言。
    * 3>前端和后台维护简单方便。
    * 缺点:1>JSON出现的时间比XML晚。移动端开发推荐使用json!!!

  • 相关阅读:
    服务器性能测试实时监控Linux命令
    软件性能测试中的关键指标
    递归静态路由和直连静态路由
    FIB表与RIB表的区别与联系
    FIB表中 Next Hop 的几种状态码(drop/receive/attached/no route)的含义
    Leetcode 与树(TreeNode )相关的题解测试工具函数总结
    centos 7.6 docker 安装 nextcloud -使用sqlite数据库
    看守所收押流程
    qt编译oracle驱动,qt 5.12 连接 oracle 数据库示例代码
    centos 7.6 安装配置nginx (显示中文目录,带密码验证)
  • 原文地址:https://www.cnblogs.com/adampei-bobo/p/5301911.html
Copyright © 2011-2022 走看看