美文网首页
ios - NSXMLParser XML解析

ios - NSXMLParser XML解析

作者: lizhi_boy | 来源:发表于2019-03-28 19:37 被阅读0次

目前大部分的的app的请求数据的类型都为json数据,对于json数据我们借助MJExtension或者其它优秀的第三方解析类库进行解析,即可得到显示的数据内容。但有时候也会遇到用xml数据的情况,对于xml数据的解析,应该怎样操作呢?下面我写一个简单的demo来实现一下。

1、看一下要解析的数据

<paper>
    <info>
        <paperId>t123456</paperId>
        <paperName paperpath = '试卷路径'>模拟试卷一</paperName>
        <partNumber>1</partNumber>
        <sectionNumber>1</sectionNumber>
        <questionNumber>3</questionNumber>
        <totalScore>3</totalScore>
    </info>
    <sectionList>
        <sectionItem>
            <sectionFolder>听对话回答问题1/听对话回答问题1</sectionFolder>
            <sectionTotalScore>6</sectionTotalScore>
        </sectionItem>
        <sectionItem>
            <sectionFolder>听对话回答问题2/听对话回答问题2</sectionFolder>
            <sectionTotalScore>6</sectionTotalScore>
        </sectionItem>
        </sectionList>
</paper>

分析一下:info标签内容数据,可以看作是一个字典(或类) 。sectionList标签的内容,可以看作一个数组里包含着两个元素(字典或类)。分析清楚后就可以为解析xml数据时的提供一个方向了。

2、构建解析类

NSXMLParser 实现的是sax方法解析xml文件。下面科普一下saxdom的解析方法有什么优缺点?
dom实现的原理是把整个xml文档一次性读出,放在一个树型结构里。在需要的时候,查找特定节点,然后对节点进行读或写。
优点:实现简单,读写平衡;
缺点:比较占内存,因为他要把整个xml文档都读入内存,文件越大,缺点就越明显。
sax的实现方法和dom不同。它只在xml文档中查找特定条件的内容,并且只提取需要的内容。
优点:占用内存小,灵活。
缺点:编写实现上比较复杂。

(1)、构建一个解析工具类

ParserManager.h

@interface ParserManager : NSObject

/**
 初始化方法

 @param data 解析的xml数据
 @return ParserManager
 */
-(instancetype)initWithData:(NSData *)data;


/**
 解析完成时调用

 @param completion 完成时回调(demo中是把解析出来的数据返回了)
 */
-(void)finishedParser:(void(^)(NSArray *modeArray,NSDictionary *modeDic,NSError *error))completion;


@end

ParserManager.m
定义一个NSXMLParser类,以及一些必要的属性,属性的定义可以根据xml的数据结构来定义

@interface ParserManager ()<NSXMLParserDelegate>
/** 定义一个解析类 */
@property(nonatomic,strong) NSXMLParser *parser;
/** 记录当前解析的节点 */
@property(nonatomic,strong) NSString *currentElementName;
/** 记录当前解析的类的属性 */
@property(nonatomic,strong) NSMutableDictionary *currentParserDic;
/** 记录当前解析的类的数组 */
@property(nonatomic,strong) NSMutableArray *currentParserArray;
/** 接收解析出来的dic数据 */
@property(nonatomic,strong) NSMutableDictionary *modeDic;
/** 接收解析出来的array数据 */
@property(nonatomic,strong) NSMutableArray *modeArray;
/** 解析完成的回调 */
@property(nonatomic,copy) void(^parserFinished)(NSArray *demoArray,NSDictionary *demoDic,NSError *error);
@end

初始化以及懒加载

-(instancetype)initWithData:(NSData *)data{
    
    if (self = [super init]) {
        self.parser = [[NSXMLParser alloc] initWithData:data];
        self.parser.delegate = self;
        //开始解析
        [self.parser parse];
    }
    return self;
}

-(NSMutableDictionary *)currentParserDic{
    if (!_currentParserDic) {
        _currentParserDic = [NSMutableDictionary dictionary];
    }
    return _currentParserDic;
}

-(NSMutableArray *)currentParserArray{
    if (!_currentParserArray) {
        _currentParserArray = [NSMutableArray array];
    }
    return _currentParserArray;
}
(2)、执行NSXMLParserDelegate代理方法

接下来的事情就简单了,只需在NSXMLParserDelegate代理方法中进行操作即可。
执行解析方法会调用时会调用:

-(void)parserDidStartDocument:(NSXMLParser *)parser{
//    NSLog(@"开始解析");
}

读取到节点时会执行,按照demo的xml数据解析会首先读取到的节点是<paper>[从上往下逐行逐字进行解析]。此外获取节点中的属性值也在此方法中操作,比如要获取<paperName>节点的的属性paperpath的值。(demo中在此方法中对<info>节点中清除了currentParserArraycurrentParserArray内的数据,目的是保证解析数据的准确性)。

//开始解析到某个节点是调用
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
    self.currentElementName = elementName;
    
    //当节点解析到info时开始准备一个字典接收解析出来的数据
    if ([elementName isEqualToString:@"info"]) {
        [self.currentParserArray removeAllObjects];
        [self.currentParserDic removeAllObjects];
    }
    //同理,当节点解析到sectionList时开始准备一个数组接收解析出来的数据
    if ([elementName isEqualToString:@"sectionList"]) {
        [self.currentParserArray removeAllObjects];
        [self.currentParserDic removeAllObjects];
    }
    //获取节点中的属性值
    if ([elementName isEqualToString:@"paperName"]) {
        NSLog(@"%@",attributeDict[@"paperpath"]);
    }
}

获取节点数据

//取值
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    //didEndElement方法执行后,即节点解析结束后还会调用此方法,解析出来的string的值为"\n    ",并不是想要显示数据所以要做过滤操作
    if (self.currentElementName && [self isValidationString:string]) {
        [self.currentParserDic setValue:string forKey:self.currentElementName];
        [self.currentParserArray addObject:self.currentParserDic];
    }
}

节点解析结束。注意:self.currentElementName = nil;(按照demo的xml数据解析会首先读取到的节点是</paperId>,[从上往下逐行逐字进行解析])

//结束解析某个节点时调用

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    //把数据取出
    if ([elementName isEqualToString:@"info"]) {
        self.modeDic = self.currentParserDic.copy;
    }
    if ([elementName isEqualToString:@"sectionList"]) {
        self.modeArray = self.currentParserArray.copy;
    } 
    self.currentElementName = nil;
}

结束整个xml文件解析时调用

//结束整个xml文件解析时调用
-(void)parserDidEndDocument:(NSXMLParser *)parser{
    //放在主线程中处理是为了解决self.parserFinished未被初始化的问题
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.parserFinished) {
            self.parserFinished(self.modeArray,self.modeDic,nil);
        }
    });
}

解析出错时调用的代理方法


-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
       dispatch_async(dispatch_get_main_queue(), ^{
        if (self.parserFinished) {
            self.parserFinished(nil,nil,parseError);
        }
    });
}
-(void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError{
       dispatch_async(dispatch_get_main_queue(), ^{
        if (self.parserFinished) {
            self.parserFinished(nil,nil,validationError);
        }
    });
}
(3)、外调方法以及私有方法的实现
-(void)finishedParser:(void (^)(NSArray *, NSDictionary *,NSError*))completion{
    self.parserFinished = completion;
}

//过滤不必要的数据
-(BOOL)isValidationString:(NSString *)string{
    if ([string hasPrefix:@"\n"]){
        return NO;
    }else{
        return YES;
    }
}
(4)、控制器调用并查看效果
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"xml"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    ParserManager *parser = [[ParserManager alloc] initWithData:data];
    __weak typeof(self) weakSelf = self;
    [parser finishedParser:^(NSArray *modeArray, NSDictionary *modeDic, NSError *error) {
        if (!error) {
            weakSelf.contentText.text = [NSString stringWithFormat:@"%@\n%@",modeArray,modeDic];
        }else{
            NSLog(@"error:%@",error.localizedDescription);
        }
    }];
}
demo打印信息.png

接下来就是字典转模型的步骤了,这应该都玩的挺6的了,就不多说了。

总结:1、要清楚xml数据的结构 2、要清楚NSXMLParser解析类代理方法的调用顺序。明白这两点就可以很快的把xml数据解析出来了。


都看到这里了,点个喜欢❤️不过分吧

相关文章

  • XML

    NSXMLParser解析XML GDataXML解析XML

  • 解析xml文件-NSXMLParser

    简介 iOS SDK的NSXMLParser解析XML文档是事件驱动模式的,即采用SAX方式来解析XML格式文档。...

  • ios15的NSXMLParser类使用解析XML

    ios15的NSXMLParser类使用解析XML 必须遵守NSXMLParserDelegate协议。重写里面的...

  • ios - NSXMLParser XML解析

    目前大部分的的app的请求数据的类型都为json数据,对于json数据我们借助MJExtension或者其它优秀的...

  • NSXMLParser does not support ree

    今日遇到此问题的前提: 使用iOS系统自带的Xml解析类 NSXMLParser类来进行解析两个xml文件,一个在...

  • 2018-01-02 xml格式数据的请求处理

    用NSXMLParser解析XML文件过程: 1 创建NSXMLParser实例,并传入从服务器接收XML数据。 ...

  • NSXMLParser

    NSXMLParser是iOS自带SAX方式解析,使用方法为:1.// 传入XML数据,初始化解析器[[NSXML...

  • IOS中的XML解析

    在iOS中,解析XML的手段有很多 苹果原生NSXMLParser:SAX方式解析,使用简单 第三方框架libxm...

  • XML解析NSXMLParser

    NSXMLParser NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理当扫描到...

  • Swift - 解析XML格式数据(分别使用GDataXML和D

    XML解析方式的选择建议 大文件用:NSXMLParser 小文件用:GDataXML 假设需要被解析的XML数据...

网友评论

      本文标题:ios - NSXMLParser XML解析

      本文链接:https://www.haomeiwen.com/subject/bmqcbqtx.html