XML和JSON數(shù)據(jù)解析

XML和JSON是兩種數(shù)據(jù)交換格式运翼。

  • XML是老牌双谆、經(jīng)典壳咕、靈活的數(shù)據(jù)交換格式
  • JSON是比XML輕便的數(shù)據(jù)交換格式席揽,廣泛用于Web和移動(dòng)平臺(tái)開(kāi)發(fā)

一、XML數(shù)據(jù)解析

1谓厘、解析XML文檔的兩種模式

(1) SAX:事件驅(qū)動(dòng)模式幌羞。從根元素開(kāi)始,按順序一個(gè)個(gè)元素往下解析竟稳,遇到開(kāi)始標(biāo)簽属桦、結(jié)束標(biāo)簽和屬性等就會(huì)觸發(fā)相應(yīng)事件。它只在XML文檔中查找特定條件的內(nèi)容他爸,并且只提取需要的東西聂宾,占用內(nèi)存少,比較靈活诊笤。

優(yōu)點(diǎn):占用內(nèi)存少系谐,解析速度快,適合解析大文件
缺點(diǎn):只能讀取XML文檔讨跟,不能寫(xiě)入或修改XML文檔

(2)DOM:文檔對(duì)象模型纪他。一次性將整個(gè)XML文檔加載進(jìn)內(nèi)存,將XML文檔作為一棵樹(shù)狀結(jié)構(gòu)進(jìn)行分析晾匠,需要的時(shí)候查找特定的結(jié)點(diǎn)茶袒。

優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,讀寫(xiě)平衡(可讀可寫(xiě))凉馆,適合解析小文件
缺點(diǎn):占用內(nèi)存較多薪寓,解析速度較慢,不適合解析大文件

2澜共、常用XML解析

(1)NSXML(iOS SDK自帶预愤,蘋(píng)果默認(rèn)解析框架,采用SAX模式)
(2)TBXML(第三方開(kāi)源庫(kù)咳胃,采用DOM模式)

以下例子將使用下面的Books.xml文件來(lái)讀取數(shù)據(jù)

<?xml version="1.0" encoding="UTF-8"?>
<Books>
    <Book id="1">
        <title>title1</title>
        <author>author1</author>
        <summary>summary1</summary>
    </Book>
    
    <Book id="2">
        <title>title2</title>
        <author>author2</author>
        <summary>summary2</summary>
    </Book>
    
    <Book id="3">
        <title>title3</title>
        <author>author3</author>
        <summary>summary3</summary>
    </Book>
</Books>

</br>

3植康、NSXML解析

NSXML框架的核心是NSXMLParser及其委托協(xié)議NSXMLParserDelegate,主要的解析工作在NSXMLParserDelegate實(shí)現(xiàn)類中完成展懈。

其中NSXMLParserDelegate有5個(gè)常用的方法:

(1)在文檔開(kāi)始的時(shí)候觸發(fā)

parserDidStartDocument:

(2)遇到一個(gè)開(kāi)始標(biāo)簽時(shí)觸發(fā)销睁,其中namespaceURI部分是命名空間,qualifiedName是限定名存崖,attributes是字典類型的屬性集合

parser:didStartElement:namespaceURI:qualifiedName:attributes:

(3)遇到字符串時(shí)觸發(fā)

parser:foundCharacters:

(4)遇到結(jié)束標(biāo)簽時(shí)觸發(fā)

parser:didEndElement:namespaceURI:qualifiedName:

(5)在文檔結(jié)束時(shí)觸發(fā)

parserDidEndDocument:

4冻记、NSXML解析的分析:結(jié)合Books.xml文件來(lái)說(shuō)明每個(gè)方法的調(diào)用時(shí)機(jī)

(此處調(diào)用方法1)

<?xml version="1.0" encoding="UTF-8"?>
(此處調(diào)用方法2)<Books>  

   (此處調(diào)用方法2)<Book id="1"> 
     (此處調(diào)用方法2)<title>(此處調(diào)用方法3)title1(此處調(diào)用方法4)</title>
       (此處調(diào)用方法2)<author>(此處調(diào)用方法3)author1(此處調(diào)用方法4)</author>
       (此處調(diào)用方法2)<summary>(此處調(diào)用方法3)summary1(此處調(diào)用方法4)</summary>
  (此處調(diào)用方法4) </Book>
    
  (下同)
    <Book id="2">
        <title>title2</title>
        <author>author2</author>
        <summary>summary2</summary>
    </Book>
    
  (下同)
    <Book id="3">
        <title>title3</title>
        <author>author3</author>
        <summary>summary3</summary>
    </Book>
</Books>

(此處調(diào)用方法5)

</br>

所以我們可以自定義一個(gè)類,如KSXMLParser来惧,并讓其實(shí)現(xiàn)NSXMLParserDelegate協(xié)議

//KSXMLParser.h
@interface KSXMLParser : NSObject <NSXMLParserDelegate>

@property (strong, nonatomic) NSMutableArray *list; //把讀取的每一個(gè)Book數(shù)據(jù)作為一個(gè)數(shù)組元素保存

@property (strong, nonatomic) NSString *currentElementName; //記錄當(dāng)前讀取的Element冗栗,如"Book","title","author"等

- (void)startParser;

@end
#import "KSXMLParser.h"

@implementation KSXMLParser

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

//方法1
- (void)parserDidStartDocument:(NSXMLParser *)parser {
    self.list = [[NSMutableArray alloc] init];
}

//方法2
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
    
    self.currentElementName = elementName;
    
    if ([self.currentElementName isEqualToString:@"Book"]) {
        
        NSString *identifier = [attributeDict objectForKey:@"id"];
        NSMutableString *book = [[NSMutableString alloc] initWithString:identifier];
        
        [self.list addObject: book];
    }
}

//方法3
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    
    string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if ([string isEqualToString:@""]) {
        return;
    }
    
    if ([self.currentElementName isEqualToString:@"title"] && [self.list count]) {
        
        NSMutableString * book = (NSMutableString *)[self.list lastObject];
        
        [book appendFormat:@" %@", string];
        
    }
    
    if ([self.currentElementName isEqualToString:@"author"] && [self.list count]) {

        NSMutableString * book = (NSMutableString *)[self.list lastObject];
        
        [book appendFormat:@" %@", string];
    }
    
    if ([self.currentElementName isEqualToString:@"summary"] && [self.list count]) {
        
        NSMutableString *book = (NSMutableString *)[self.list lastObject];
        
        [book appendFormat:@" %@", string];
    }
}

//方法4
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI {
    
}

//方法5
- (void)parserDidEndDocument:(NSXMLParser *)parser {
    
}

@end
//ViewController.m

#import "ViewController.h"
#import "KSXMLParser.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    KSXMLParser *parser = [[KSXMLParser alloc] init];
    [parser startParser];
    
    for (NSString *str in parser.list) {
        NSLog(@"%@", str);
    }
}

@end

輸出

NSXMLParser[1326:111640] 1 title1 author1 summary1
NSXMLParser[1326:111640] 2 title2 author2 summary2
NSXMLParser[1326:111640] 3 title3 author3 summary3

補(bǔ)充說(shuō)明:
方法2中的下面這2條語(yǔ)句是用來(lái)消除XML文本中遇到的回車符和空格的隅居。僅僅方法2需要這2條語(yǔ)句钠至,是因?yàn)榉椒?在遇到換行符和回車符等特殊字符也會(huì)觸發(fā),所以需要做處理胎源。

string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

if ([string isEqualToString:@""]) {
        return;
}

</br>

5棉钧、TBXML解析

因?yàn)門BXML是第三方開(kāi)源庫(kù),所以不像iOS自帶的那么方便涕蚤,使用時(shí)需要下載宪卿,然后配置環(huán)境。

我們可以選擇手動(dòng)配置或使用CocoaPods幫我們配置万栅,這里我將詳細(xì)演示前者的配置方法佑钾。

(1)下載完成并解壓后,將TBXML-Headers和TBXML-Code文件夾添加到工程中烦粒,如下圖


(2)在工程中添加TBXML所依賴的Framework和庫(kù)休溶,有2個(gè):libz.tbd和CoreGraphics.framework,步驟:TARGETS-->Build Phases-->Link Binary With Libraries撒遣,點(diǎn)擊“+”按鈕搜索并添加

(3)此外邮偎,還需要有預(yù)編譯文件管跺,包括兩個(gè)步驟义黎,創(chuàng)建和配置

通過(guò)在Xcode菜單點(diǎn)擊File-->New-->File或快捷鍵Command+N選擇PCH File文件模板創(chuàng)建預(yù)編譯頭文件

在預(yù)編譯頭文件中添加選中的那2行代碼,因?yàn)門BXML默認(rèn)支持MRC豁跑,是ARC_ENABLED宏可以打開(kāi)ARC開(kāi)關(guān)廉涕,使TBXML能夠支持ARC工程。


配置預(yù)編譯頭文件到工程中的步驟是TARGETS-->Build Settings-->Apple LLVM 8.0 - Language --> Prefix Header中輸入預(yù)編譯頭文件的文件名


(4)完成以上工作之后執(zhí)行一次編譯艇拍,如果出現(xiàn)以下錯(cuò)誤:


說(shuō)明在創(chuàng)建預(yù)編譯頭文件時(shí)狐蜕,沒(méi)有把它放到與.xcodeproj同一個(gè)目錄里,把它放到那里問(wèn)題就可以解決了卸夕,如下圖:


6层释、TBXML解析的分析:

如前文第1點(diǎn)和第2點(diǎn)所述,TBXML是采用DOM模式解析的快集,它會(huì)將XML文件轉(zhuǎn)換為一棵樹(shù)進(jìn)行分析贡羔,當(dāng)讀取Books.xml文件時(shí),會(huì)按如下生成的樹(shù)結(jié)構(gòu)進(jìn)行解析


解析順序:title1个初,author1乖寒,summary1 --> title2,author2院溺,summary2 --> title3楣嘁,author3,summary3

7、TBXML解析

//KSXMLParser.h
#import <Foundation/Foundation.h>
#import "TBXML.h"

@interface KSXMLParser : NSObject

@property (strong, nonatomic) NSMutableArray *list;

- (void)startParse;

@end
//KSXMLParser.m
#import "KSXMLParser.h"

@implementation KSXMLParser

- (void)startParse {
    
    self.list = [[NSMutableArray alloc] init];
    
    TBXML *tbxml = [[TBXML alloc] initWithXMLFile:@"Books.xml" error: nil];
    
    TBXMLElement *root = tbxml.rootXMLElement;
    
    //如果root元素有效
    if (root) {
        TBXMLElement *bookElement = [TBXML childElementNamed:@"Book" parentElement:root];
        
        while (bookElement != nil) {
            NSMutableString *str = [[NSMutableString alloc] init];
            
            //獲取Book id
            NSString *s = [TBXML valueOfAttributeNamed:@"id" forElement:bookElement error:nil];
            [str appendFormat:@" %@", s];
            
            //獲取title
            TBXMLElement *titleElement = [TBXML childElementNamed:@"title" parentElement:bookElement];
            if (titleElement != nil) {
                NSString *s = [TBXML textForElement: titleElement];
                [str appendFormat:@" %@", s];
            }
            
            //獲取author
            TBXMLElement *authorElement = [TBXML childElementNamed:@"author" parentElement:bookElement];
            if (authorElement != nil) {
                NSString *s = [TBXML textForElement:titleElement];
                [str appendFormat:@" %@", s];
            }
            
            //獲取summary
            TBXMLElement *summaryElement = [TBXML childElementNamed:@"summary" parentElement:bookElement];
            if (summaryElement != nil) {
                NSString *s = [TBXML textForElement:summaryElement];
                [str appendFormat:@" %@", s];
            }
            
            [self.list addObject:str];
            
            bookElement = [TBXML nextSiblingNamed:@"Book" searchFromElement:bookElement];
            
        }
    }
}

@end
//ViewController.m
#import "ViewController.h"
#import "KSXMLParser.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    KSXMLParser *parser = [[KSXMLParser alloc] init];
    [parser startParse];
    
    for (NSString *str in parser.list) {
        NSLog(@"%@", str);
    }
}

@end

輸出

TBXML[933:67915] 1 title1 title1 summary1
TBXML[933:67915] 2 title2 title2 summary2
TBXML[933:67915] 3 title3 title3 summary3

</br>

二逐虚、JSON數(shù)據(jù)解析

1聋溜、構(gòu)成JSON文檔的兩種結(jié)構(gòu)

  • 對(duì)象,里面的每個(gè)基本單位為“名稱-值”痊班,類似于Objective-C字典勤婚,是無(wú)序集合
  • 數(shù)組,里面的每個(gè)基本單位為“值”涤伐,“值”可以是雙引號(hào)括起來(lái)的字符串馒胆、數(shù)值、true凝果、false祝迂、null、對(duì)象或數(shù)組器净,類似于Objective-C數(shù)組型雳,是有序集合

對(duì)象結(jié)構(gòu)的語(yǔ)法

{
    " " : " ",
    " " : " ",
    " " : " ",
    ......
}

{
    "name" : "a.htm",
    "size" : 345,
    "saved" : true
}

數(shù)組結(jié)構(gòu)的語(yǔ)法

[ " ", " ", " ", ...... ]

["text", "html", "css"]

對(duì)象結(jié)構(gòu)和數(shù)組結(jié)構(gòu)可以嵌套,如我們將在下面JSON解析時(shí)用到的data.json文件

{"ResultCode" : 0 ,
"Record" : [{"ID":"1", "title":"title1", "author":"author1", "summary":"summary1"},
            {"ID":"2", "title":"title2", "author":"author2", "summary":"summary2"},
            {"ID":"3", "title":"title3", "author":"author3", "summary":"summary3"}] }

</br>

2山害、常用JSON解析

(1)NSJSONSerialization

3纠俭、NSJSONSerialization解析

因?yàn)槭窃趇OS5后添加進(jìn)SDK的框架,所以可以很方便使用浪慌,同時(shí)也有非常優(yōu)秀的性能

//ViewController.m
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
    
    NSData *jsonData = [[NSData alloc] initWithContentsOfFile:path];
    
    NSError *error;
    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
    if (!jsonObj || error) {
        NSLog(@"JSON解碼失敗");
    }
    
    NSArray *listData = jsonObj[@"Record"];
    for (NSString *str in listData) {
        NSLog(@"%@", str);
    }
}

@end

輸出

NSJSONSerialization[955:73984] {
    ID = 1;
    author = author1;
    summary = summary1;
    title = title1;
}
NSJSONSerialization[955:73984] {
    ID = 2;
    author = author2;
    summary = summary2;
    title = title2;
}
NSJSONSerialization[955:73984] {
    ID = 3;
    author = author3;
    summary = summary3;
    title = title3;
}

補(bǔ)充說(shuō)明:
NSJSONSerialization的靜態(tài)方法JSONObjectWithData: options: error:冤荆,返回的是字典類型。

(以下出自《iOS開(kāi)發(fā)指南》(第4版) p462)
其中options參數(shù)指定了解析JSON的模式权纤。該參數(shù)是枚舉類型NSJSONReadingOptions定義的钓简,有如下3個(gè)常量。

  • MutableContainers汹想。指定解析返回的是可變的數(shù)組或字典外邓。如果以后需要修改結(jié)果,這個(gè)常量是合適的選擇
  • MutableLeaves古掏。指定葉節(jié)點(diǎn)是可變字符串
  • AllowFragments损话。指定頂級(jí)節(jié)點(diǎn)可以不是數(shù)組或字典

此外,NSJSONSerialization還提供了JSON編碼的方法槽唾, dataWithJSONObject: options: error:writeJSONObject: toStream: options: error:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末丧枪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夏漱,更是在濱河造成了極大的恐慌豪诲,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,496評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挂绰,死亡現(xiàn)場(chǎng)離奇詭異屎篱,居然都是意外死亡服赎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門交播,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)重虑,“玉大人,你說(shuō)我怎么就攤上這事秦士∪崩鳎” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,091評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵隧土,是天一觀的道長(zhǎng)提针。 經(jīng)常有香客問(wèn)我,道長(zhǎng)曹傀,這世上最難降的妖魔是什么辐脖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,458評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮皆愉,結(jié)果婚禮上嗜价,老公的妹妹穿的比我還像新娘。我一直安慰自己幕庐,他們只是感情好久锥,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,542評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著异剥,像睡著了一般瑟由。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上届吁,一...
    開(kāi)封第一講書(shū)人閱讀 49,802評(píng)論 1 290
  • 那天错妖,我揣著相機(jī)與錄音绿鸣,去河邊找鬼疚沐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛潮模,可吹牛的內(nèi)容都是我干的亮蛔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,945評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼擎厢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼究流!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起动遭,我...
    開(kāi)封第一講書(shū)人閱讀 37,709評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芬探,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后厘惦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體偷仿,經(jīng)...
    沈念sama閱讀 44,158評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,502評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酝静。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片节榜。...
    茶點(diǎn)故事閱讀 38,637評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖别智,靈堂內(nèi)的尸體忽然破棺而出宗苍,到底是詐尸還是另有隱情,我是刑警寧澤薄榛,帶...
    沈念sama閱讀 34,300評(píng)論 4 329
  • 正文 年R本政府宣布讳窟,位于F島的核電站,受9級(jí)特大地震影響敞恋,放射性物質(zhì)發(fā)生泄漏挪钓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,911評(píng)論 3 313
  • 文/蒙蒙 一耳舅、第九天 我趴在偏房一處隱蔽的房頂上張望碌上。 院中可真熱鬧,春花似錦浦徊、人聲如沸馏予。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,744評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)霞丧。三九已至,卻和暖如春冕香,著一層夾襖步出監(jiān)牢的瞬間蛹尝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,982評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工悉尾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留突那,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,344評(píng)論 2 360
  • 正文 我出身青樓构眯,卻偏偏與公主長(zhǎng)得像愕难,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惫霸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,500評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1 數(shù)據(jù)解析 在iOS開(kāi)發(fā)中猫缭,常見(jiàn)的數(shù)據(jù)傳輸格式有兩種:JSON和XML。目前JSON由于其體積小壹店、傳輸速度快等優(yōu)...
    歲與禾閱讀 1,039評(píng)論 2 11
  • 網(wǎng)絡(luò)傳輸數(shù)據(jù)時(shí)最常用的格式有兩種:XML和JSON XML解析: 對(duì)于XML的解析猜丹,常用的方法有:Pull解析方式...
    飛行員suke閱讀 1,607評(píng)論 0 1
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)硅卢,斷路器射窒,智...
    卡卡羅2017閱讀 134,632評(píng)論 18 139
  • 解析的基本概念 解析: 從事先規(guī)定好的格式中提取數(shù)據(jù) 解析的前提: 提前約定好格式,數(shù)據(jù)提供方按照格式提供數(shù)據(jù),數(shù)...
    云之君兮鵬閱讀 1,842評(píng)論 4 28
  • JSON JSON和XML都是需要解析的 JSON是一種輕量級(jí)的數(shù)據(jù)格式妖混,一般用于數(shù)據(jù)交互服務(wù)器返回給客戶端的數(shù)據(jù)...
    JonesCxy閱讀 1,847評(píng)論 2 10