iOS网络编程笔记——XML文档解析

      今天利用多余时间研究了一下XML文档解析,虽然现在移动端使用的数据格式基本为JSON格式,但是XML格式毕竟多年来一直在各种计算机语言之间使用,是一种老牌的经典的灵活的数据交换格式。所以我认为还是很有必要认真学习一下。

<?xml version="1.0" encoding="UTF-8"?>
<Notes>
  <Note id="1">
    <CDate>2017-2-28</CDate>
    <Content>早上8点钟到公司</Content>
    <UserID>jack</UserID>
  </Note>
  <Note id="2">
    <CDate>2017-3-1</CDate>
    <Content>早上8点到公司</Content>
    <UserID>jack</UserID>
  </Note>
  <Note id="3">
    <CDate>2017-3-2</CDate>
    <Content>早上九点到公司</Content>
    <UserID>jack</UserID>
  </Note>
  <Note id="4">
    <CDate>2017-3-3</CDate>
    <Content>早上十点到公司</Content>
    <UserID>jack</UserID>
  </Note>
  <Note id="5">
    <CDate>2017-3-4</CDate>
    <Content>中午一点到公司</Content>
    <UserID>jack</UserID>
  </Note>
  <Note id="6">
    <CDate>2017-3-5</CDate>
    <Content>中午两点到公司</Content>
    <UserID>jack</UserID>
  </Note>
</Notes>

      这是一个简单的XML文档,结构由声明、根元素<notes> 根元素只有一个,开始和结束标签必须一致、子元素、属性、命名空间、限定名组成,所有元素都要有结束标签,开始和结束标签必须一致。具体就不多做介绍了,我把重点放在XML文档的解析上。

读写XML文档目前最流行的有两种方式:

(1)SAX 一种基于事件驱动的解析模式,解析XML时程序从上到下读取XML文档,如果遇到开始标签结束标签属性等,就会触发相应的事件。弊端只能读取XML文档不能写入,优点是解析速度快。

(2)DOM 将XML文档作为一棵树状结构进行分析,提供获取节点的内容以及相关属性,或者是增、删、改节点的内容。在加载时会一次性读入到内存中,如果文档比较大,解析速度就会很慢,所以苹果推荐使用SAX模式。

介绍两个实例:

(1)使用NSXML

NSXML是iOS SDK 自带的,也是苹果默认解析框架,采用SAX模式。核心是NSXMLParser和它的委托协议NSXMLParserDelegate。

@interface NotesXMLParser : NSObject<NSXMLParserDelegate>

@property (nonatomic, strong) NSMutableArray *notes;
/*
 * 当前标签名字
 */
@property (nonatomic, strong) NSString *currentTagName;

- (void) start;
@end
- (void)start
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Notes" ofType:@"xml"];
    NSURL *url = [NSURL fileURLWithPath:path];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    parser.delegate = self;
    [parser parse];
}

#pragma mark - <NSXMLParserDelegate>
//文档开始时触发
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    _notes = [NSMutableArray array];
}
//文档出错时触发
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"error:%@",parseError.localizedDescription);
}
//遇到一个开始标签时触发
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
    _currentTagName = elementName;
    if ([_currentTagName isEqualToString:@"Note"]){
        NSString *_id = [attributeDict objectForKey:@"id"];
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setObject:_id forKey:@"id"];
        [_notes addObject:dict];
    }
}
//遇到字符串时触发
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];//替换回车符和空格
    if ([string isEqualToString:@""]){
        return;
    }
    NSMutableDictionary *dict = [_notes lastObject];
    if ([_currentTagName isEqualToString:@"CDate"] && dict){
        [dict setObject:string forKey:@"CDate"];
    }
    if ([_currentTagName isEqualToString:@"Content"] && dict){
        [dict setObject:string forKey:@"Content"];
    }
    if ([_currentTagName isEqualToString:@"UserID"] && dict){
        [dict setObject:string forKey:@"UserID"];
    }
}
//遇到结束标签时触发
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    self.currentTagName = nil;
}
//遇到文档结束时触发
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadViewNotification" object:self.notes userInfo:nil];
    self.notes = nil;
}

 

(2)使用TBXML

TBXML解析文档采用DOM模式,通上面比较使用起来比较方便。githup地址:https://githup.com/71squared/TBXML,下载完成后需要在源码工程头文件MyNotes-Prefix.pch中添加宏定义:#define ARC_ENABLED,注意添加.pch文件路径,参考:http://www.ithao123.cn/content-9982088.html 。添加libz.tbd依赖库。

代码实现部分:

@interface NotesTBXMLParser : NSObject

@property (nonatomic, strong) NSMutableArray *notes;

- (void)start;

@end
@implementation NotesTBXMLParser

- (void)start
{
    _notes = [NSMutableArray array];
    TBXML *tbxml = [[TBXML alloc] initWithXMLFile:@"Notes.xml" error:nil];
    TBXMLElement *root = tbxml.rootXMLElement;//获取文档根元素对象
    if (root) {
        TBXMLElement *noteElement = [TBXML childElementNamed:@"Note" parentElement:root];//通过根元素找到下面的note元素
        while (noteElement != nil) {//note元素有很多 遍历循环
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            //通过noteElement找到下面的子元素
            TBXMLElement *CDateElement = [TBXML childElementNamed:@"CDate" parentElement:noteElement];
            if (CDateElement != nil) {
                NSString *CDate = [TBXML textForElement:CDateElement];
                [dict setObject:CDate forKey:@"CDate"];
            }
            
            TBXMLElement *ContentElement = [TBXML childElementNamed:@"Content" parentElement:noteElement];
            if (ContentElement != nil) {
                NSString *Content = [TBXML textForElement:ContentElement];
                [dict setObject:Content forKey:@"Content"];
            }
            
            TBXMLElement *UserIDElement = [TBXML childElementNamed:@"UserID" parentElement:noteElement];
            if (UserIDElement != nil) {
                NSString *UserID = [TBXML textForElement:UserIDElement];
                [dict setObject:UserID forKey:@"UserID"];
            }
            //获得id属性
            NSString *_id = [TBXML valueOfAttributeNamed:@"id" forElement:noteElement error:nil];
            [dict setObject:_id forKey:@"id"];
            
            [_notes addObject:dict];
            
            noteElement = [TBXML nextSiblingNamed:@"Note" searchFromElement:noteElement];//获取同层下个note元素,通过sibling可看出非父子关系的同级元素
        }
    }
    NSLog(@"解析完成");
    [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadViewNotification" object:self.notes];
    self.notes = nil;
}

@end

 

posted on 2017-02-28 15:14  jack.xi  阅读(131)  评论(0编辑  收藏  举报

导航