数据解析之XML解析详解(苹果自带XML解析)——并将数据转成Model(需要重点掌握)

2024-08-28 16:18

本文主要是介绍数据解析之XML解析详解(苹果自带XML解析)——并将数据转成Model(需要重点掌握),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是XML

全称是Extensible Markup Language,可译为可扩展性标记语言。

JSON一样,也是一种用于交互的数据格式。

一般也叫做XML文档。

XML举例

<videos>

    <video name="小黄人01" length="30" />

    <video name="小黄人02" length="19" />

    <video name="小黄人03" length="33" />

</videos>

XML语法

一个常见的XML文档一般由以下部分组成

文档声明

元素(Element

属性(Attribute


XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型。

最简单的声明

<?xml version=“1.0”>

encoding属性说明文档的编码

<?xml version=“1.0” encoding = “UTF-8”>

XML语法元素(ELement

一个元素包括了开始标签和结束标签

拥有元素的内容:<video>小黄人</video>

没有元素的内容:<video></video>

没有内容的简写:<video/>

一个元素可以嵌套若干个子元素(不能出现交叉嵌套)

<videos>

        <video>

                 <name>小黄人</name>

                 <length>30</length>

        </video>

</videos>

交叉嵌套举例如下:

<videos>

        <video>

                 <name>小黄人</name>

                 <length>30</length>

        </videos>

</video>

规范的XML文档最多只有一个根元素,其他元素都是根元素的子孙元素。

XML语法——元素注意:

XML中所有空格和换行,(空格和换行都会当做字符处理)都会当做具体内容处理。

下面两个元素的内容是不一样的。

第一个

<video>小黄人</video>

第二个

<video>

     小黄人

</video>

XML语法——属性(Attribute

一个元素可以拥有很多属性。

<video name=“小黄人第01”length=“30”>

video元素拥有namelength两个属性。

属性值必须用双引号或单引号括住。

实际上,属性表示的信息也可以用子元素来表示,比如:

<video>

     <name>小黄人第01</name>

     <length>30</length>

</video>

注意:一个元素相当于一个Model,一个元素属性相当于Model中的变量。每一个子元素相当于一个Model成员对象。


XML解析:

要想从XML中提取有用的信息,必须学会解析XML

提取name元素里面的内容

<name>小黄人第01</name>

提取video元素中namelength属性的值

<video name=“小黄人第01”length=“30”>


XML解析主要有两种

DOM:一次性将整个XML文档加载进内存,比较适合解析小文件。

SAX:从根元素开始,按顺序一个一个元素往下解析(类似于递归),比较适合解析大文件。

苹果自带的XML解析方法以及步骤如下:

第一步:创建解析器。

 首先在获得网络数据后,实例化一个XML的解析器进行实现XML的解析。如下所示:

NSXMLParser *parse = [[NSXMLParser alloc] initWithData: data];

第二步:设置代理。并将当前控制器遵守NSXMLParserDelegate协议

parse.delegate = self;

第三步:开始解析。[parse parse];

第四步:实现NSXMLParserDelegate里的五个必不可少的代理方法,如下所示:

1)打开文档开始准备解析。代理方法如下所示:

- (void)parserDidStartDocument:(NSXMLParser *)parser

2)开始结点。代理方法如下所示:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

3)发现结点内容。代理方法如下所示:

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

4)结束结点。代理方法如下所示:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

5)结束文档。代理方法如下所示:

- (void)parserDidEndDocument:(NSXMLParser *)parser

注意:因为是递归执行,所以除了第一个打开文档和最后一个结束文档外,其他的都是循环执行的。

解析步骤如下:

步骤一、新建一个全局的可变容器,用来存放XML文档转化后的Model。

步骤二、新建一个全局的可变字符串变量,用来存放拼接后的字符串。

步骤三、根据解析内容新建对应的Model模型,并在当前控制器中新建对应的全局Model属性。

步骤四、在代理方法中对数据进行处理。处理大概包括以下几个过程:

4.1、在打开文档开始解析的代理方法(1)中初始化全局容器,即清空全局容器的内容。(为了防止多次解析时重复添加数据)。

4.2、在开始结点的代理方法中对各个结点元素的名称进行判断,并创建对应的Model对象以及设置Model对应的attributeDict字典内的属性。另外还需要把全局的可变字符串置为空(因为开始解析新的结点)。

4.3、在发现节点内容的代理方法(3)中, 需要进行全局可变字符串的拼接操作。

4.4、在结束结点的代理方法(4)中需要对节点名称进行判断分别执行不同的操作(添加对应Model到全局可变容器或者利用KVC对Model的子元素进行赋值)。

4.5、 在结束文档的代理方法中可以在主线程更新UI

思路如下图:


新建工程,步骤如下:

3


4


5


6


7


8



新建模型类如下:

Video.h

#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

Video.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
viewController.m

//
//  ViewController.m
//  07-xml解析
//
//  Created by apple on 15/1/19.
//  Copyright (c) 2015年 apple. All rights reserved.
//#import "ViewController.h"
#import "Video.h"@interface ViewController ()<NSXMLParserDelegate>
/**整个xml的数据容器*/
@property(nonatomic,strong)NSMutableArray *videos;/**第3步拼接字符串*/
@property(nonatomic,strong)NSMutableString *elementString;/**当前的模型*/
@property(nonatomic,strong) Video *currentVideo;/**表格的所有数据*/
@property (nonatomic, strong) NSMutableArray *dataList;@end@implementation ViewController- (void)setDataList:(NSMutableArray *)dataList
{_dataList = dataList;// 只要重新给表格的数据容器赋值,就刷新[self.tableView reloadData];// 隐藏刷新控件[self.refreshControl endRefreshing];
}- (NSMutableArray *)videos
{if (_videos == nil) {_videos = [NSMutableArray array];}return _videos;
}- (NSMutableString *)elementString
{if (_elementString == nil) {_elementString = [NSMutableString string];}return _elementString;
}- (void)viewDidLoad {[super viewDidLoad];[self loadData];
}#pragma mark - 加载数据
- (IBAction)loadData
{// 1. urlNSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];// 2. 请求NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:2.0f];// 3. 连接[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {// xml的解析// 1. 实例化一个xml的解析器--通过代理来实现xml的解析NSXMLParser *parse = [[NSXMLParser alloc] initWithData:data];// 2. 设置代理parse.delegate = self;// 3. 解析器开始解析[parse parse];}];
}#pragma mark - 代理方法
//1.打开文档, 准备开始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser
{NSLog(@"1. 打开文档, 准备开始解析");// 初始化数组容器, 清空容器,便于多次加载数据[self.videos removeAllObjects];
}//2.开始节点
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{NSLog(@"2.开始节点%@---%@", elementName, attributeDict);// 如果开始节点的名称 是video,就创建一个对象if ([elementName isEqualToString:@"video"]) {self.currentVideo = [[Video alloc] init];// 设置videoIDself.currentVideo.videoId = attributeDict[@"videoId"];}// 清空字符串的内容,因为马上要进入第3 个方法,要开始拼接当前的节点的内容[self.elementString setString:@""];
}//3. 发现节点里面内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{NSLog(@"3. 发现节点里面内容--->%@", string);// 开始拼接[self.elementString appendString:string];
}//4. 结束节点
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{NSLog(@"4. 结束节点 %@", elementName);if ([elementName isEqualToString:@"video"]) {// 如果结束的节点是video, 需要把这个对象添加到数组[self.videos addObject:self.currentVideo];}else if (![elementName isEqualToString:@"videos"]){[self.currentVideo setValue:self.elementString forKeyPath:elementName];}//    else if ([elementName isEqualToString:@"name"]) {// 如果结束节点,就可以把第二步创建的对象,设置name/length属性
//        // 设置name属性
//        // 1. 直接赋值self.currentVideo.name = self.elementString;
//        // 2. KVC赋值[self.currentVideo setValue:self.elementString forKeyPath:@"name"];
//        // 3. 改造
//        [self.currentVideo setValue:self.elementString forKeyPath:elementName];
//    }else if ([elementName isEqualToString:@"length"]){
//        // 设置length属性self.currentVideo.length = @([self.elementString integerValue]);
//        
//        [self.currentVideo setValue:self.elementString forKeyPath:elementName];
//    }else if ([elementName isEqualToString:@"videoURL"]){
//        // 设置videoURL属性self.currentVideo.videoURL = self.elementString;
//         [self.currentVideo setValue:self.elementString forKeyPath:elementName];
//    }else if ([elementName isEqualToString:@"desc"]){
//        // 设置desc属性self.currentVideo.desc = self.elementString;
//         [self.currentVideo setValue:self.elementString forKeyPath:elementName];
//    }else if ([elementName isEqualToString:@"teacher"]){
//        // 设置teacher属性self.currentVideo.teacher = self.elementString;
//         [self.currentVideo setValue:self.elementString forKeyPath:elementName];
//    }// cocoa 的大招 KVC
}//5 结束文档
- (void)parserDidEndDocument:(NSXMLParser *)parser
{NSLog(@"5 结束文档");// xml真正解析结束, 可以更新UI, 在主线程dispatch_async(dispatch_get_main_queue(), ^{self.dataList = self.videos;});}#pragma tabel数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{return self.videos.count;
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];Video *video = self.dataList[indexPath.row];cell.textLabel.text = video.name;return cell;
}@end
本地服务器显示如下:


后台运行结果如下:


手机显示如下:


这篇关于数据解析之XML解析详解(苹果自带XML解析)——并将数据转成Model(需要重点掌握)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115263

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象