Parsing JSON With SBJSON

本文介绍如何使用SBJSON库解析从Web服务获取的JSON数据,并将其转换为Objective-C对象模型。包括理解JSON数据结构、构建对象模型及使用SBJsonParser进行解析。

转自: http://jasarien.com/?p=428


So the previous post focussed on retrieving data from a webservice – namely Google’s Local Search.

This post will focus on parsing the JSON returned from the webservice.

My personal choice for parsing JSON is the SBJON library. There are others out there such as TouchJSON and YAJL so check them put and decide for yourself.

Let’s start with a quick recap on what JSON is and how it can be used.

Wikipedia says:

JSON (an acronym for JavaScript Object Notation) is a lightweight text-based open standard designed for human-readable data interchange. It is derived from the JavaScript programming language for representing simple data structures and associative arrays, called objects. Despite its relationship to JavaScript, it is language-independent, with parsers available for virtually every programming language.

JSON presents its data as key-value pairs. Each value is referenced by a key name, which is a string. If you were to represent a person in JSON, their name would be referenced by the key “name” like so: “name” : “James”.

So, JSON represents data in a way that can be passed between applications easily. Perfect.

So when parsing data from a webservice, the first thing you should do is figure out your model. Look at an example of the webservice’s response and figure out which bits represent objects, arrays of objects, fields that belong to an object, etc.

But what kinds of data can JSON represent?

Objects are everything between the braces ( { } ).
Strings are enclosed in quotes.
Numbers aren’t enclosed by anything and just appear as numbers, e.g. 12345.
Arrays are enclosed in square brackets ( [ ] ).
Booleans take the form of the words ‘true’ or ‘false’ (without quotes).
Null values are represented as ‘null’ (without quotes).

So an example of JSON using all these data types:

{
     "firstName": "John",
     "lastName": "Smith",
     "age": 25,
     "address": 
     {
         "streetAddress": "21 2nd Street",
         "city": "New York",
         "state": "NY",
         "postalCode": "10021"
     },
     "phoneNumber": 
     [
         {
           "type": "home",
           "number": "212 555-1234"
         },
         {
           "type": "fax",
           "number": "646 555-4567"
         }
     ]
 }

And it’s representation in Objective-C:

#import <Foundation/Foundation.h>
 
@interface Person : NSObject
{
    NSString *firstName;
    NSString *lastName;
 
    NSInteger age;
 
    NSDictionary *address;
 
    NSArray *phoneNumbers;
}
 
@end

You may think we’ve missed out some information, such as the details of the address, and phone numbers. It’s you decision how you model your objects. I’ve chosen to store the address details in a dictionary, each value being referenced by a key name, just as it is in JSON. The phone numbers also stored in dictionaries, but then those dictionaries put into an array.

If you wanted to, you could create another Class named Address and use it to store the address details. This may be a more object-oriented approach and useful if addresses are used in other places throughout your application without needing to be tied to a Person.

So now that you have your object model, you need to get the data out of the JSON and create instances of your model.

SBJSON has a useful SBJsonParser class that can parse an entire JSON object in one line:

SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSError *error = nil;
NSArray *jsonObjects = [jsonParser objectWithString:jsonString error:&error];
[jsonParser release], jsonParser = nil;

SBJSON treats JSON objects as dictionaries in Objective-C. Depending on the webservice you may get a JSON object as the top level object or you may get an array. For this reason, objectWithString:error: has id as it’s return type. You can use Objective-C’s dynamism to determine which type of data store the parser as returned, like this:

id jsonObject = [jsonParser objectWithString:jsonString error:&error];
 
if ([jsonObject isKindOfClass:[NSDictionary class]])
    // treat as a dictionary, or reassign to a dictionary ivar
else if ([jsonObject isKindOfClass:[NSArray class]])
    // treat as an array or reassign to an array ivar.

If the webservice only ever returns one of the two representations as it’s top level then you can go ahead and assume it will be either an Array or Dictionary, and not have to worry about checking.

Now you have your JSON data in a format that you can manage via Objective-C. All you need to do now is iterate over the contents of the dictionary/array and create instances of Person to represent them.

One thing that’s important to remember is that literal numbers such as the age value in our Person example will be wrapped in NSNumber objects, so we’ll need to call ‘intValue’ on them to get the number.

NSMutableArrary *people = [NSMutableArray array];
 
for (NSDictionary *dict in jsonObjects)
{
    Person *newPerson = [[[Person alloc] init] autorelease];
    [newPerson setFirstName:[dict objectForKey:@"firstName"]];
    [newPerson setLastName:[dict objectForKey:@"lastName"]];
    [newPerson setAge:[[dict objectForKey:@"age"] intValue]];
    [newPerson setAddress:[dict objectForKey:@"address"]];
    [newPerson setPhoneNumbers:[dict objectForKey:@"phoneNumber"]];
 
    [people addObject:newPerson];
}

And there we have it.

One final thing to take note of. You’ll notice that I used literal strings as key names while creating the Person objects. It might be better for you to determine each key name that you’ll be using and create a string constant for them. That way, when you’re parsing your data, if you misspell firstName, the compiler can throw an error (because it won’t match the name of the constant you created) and save you a lot of time debugging when, for some damn reason, you’re not getting any value for @”firtName”!


### JSON解析错误的可能原因与解决方案 在处理JSON数据时,解析错误通常由以下几个常见原因引起:格式不正确、编码问题或网络传输中的数据损坏。以下是针对`https://start.aliyun.com`返回的JSON响应解析错误的分析和解决方法。 #### 1. 检查JSON格式是否正确 JSON格式必须严格遵守键值对结构,且所有字符串需要用双引号括起来。如果JSON中存在语法错误(如缺少引号、逗号位置不当等),解析器将无法正确解析数据[^1]。 ```python import json # 示例代码:验证JSON字符串是否合法 json_str = '{"key": "value"}' # 正确的JSON格式 try: parsed_json = json.loads(json_str) print("JSON解析成功:", parsed_json) except json.JSONDecodeError as e: print("JSON解析失败:", e) ``` #### 2. 确保服务器返回的内容是JSON类型 在请求`https://start.aliyun.com`时,需确认服务器返回的内容类型为`application/json`。如果返回的是HTML或其他非JSON格式的数据,则会导致解析失败[^2]。 ```python import requests response = requests.get("https://start.aliyun.com") if response.headers['Content-Type'] == 'application/json': try: data = response.json() print("解析成功:", data) except json.JSONDecodeError as e: print("解析失败:", e) else: print("服务器未返回JSON数据") ``` #### 3. 处理编码问题 某些情况下,JSON数据可能包含非UTF-8编码的字符,导致解析器无法正确读取。可以通过显式设置编码方式来解决此问题[^3]。 ```python response = requests.get("https://start.aliyun.com") response.encoding = 'utf-8' # 强制指定编码 try: data = response.json() print("解析成功:", data) except json.JSONDecodeError as e: print("解析失败:", e) ``` #### 4. 捕获并记录异常信息 在实际开发中,建议捕获JSON解析异常,并记录详细的错误信息以便后续排查。 ```python try: data = response.json() print("解析成功:", data) except json.JSONDecodeError as e: print(f"JSON解析失败: {e}") print("原始响应内容:", response.text) ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值