一、iOS 4种JSON数据解析方法详解
2013年09月10日⁄ 综合⁄ 共 9124字⁄ 字号小中大⁄评论关闭
在网络中数据的传输很多格式都是JSON或是XML,之前的博文已经介绍过XML,这篇介绍JSON数据。
在对JSON数据进行解析过程中大致有四种方法可供选择,包括原生的NSJSONSerialization,TouchJson,JSONKit,SBJon;其中后三种方法都要导入第三方类库。(在使用第三方类库过程中,如果项目是支持ARC的话,而这些类库文件不支持ARC特性的话,就会遇到ARC问题保错,所以就要添加arc特性,即添加-fno-objc-arc就解决)
附:
TouchJson包下载: http://download.csdn.net/detail/enuola/4523169
SBJson 包下载: http://download.csdn.net/detail/enuola/4523177
JSONKit包下载:https://github.com/TouchCode/TouchJSON
一、原生的NSJSONSerialization用法详解。
You use the NSJSONSerialization class to convert JSON to Foundation objects and convert Foundation objects to JSON.An object that may be converted to JSON must have the following properties://但是转换成JSON的对象必须具有如下属性:The top level object is an NSArray or NSDictionary.//顶层对象必须是NSArray或者NSDictionary
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.//所有的对象必须是NSString、NSNumber、NSArray、NSDictionary、NSNull的实例
All dictionary keys are instances of NSString.//所有NSDictionary的key必须是NSString类型
Numbers are not NaN or infinity.//数字对象不能是非数值或无穷
Other rules may apply. CallingisValidJSONObject:or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
这是NSJSONSerialization官方文档的开头一段话,介绍的是NSJSONSerialization可以将JSON对象转换成Foundation对象,也可以将Foundation对象转换成JSON对象。但是将Foundation对象转换成JSON对象时就有了上面的要求了。要注意的是The
top level object is an NSArray or NSDictionary。
这个类对应的方法有:
Creating a JSON Object
+ JSONObjectWithData:options:error:
+ JSONObjectWithStream:options:error:
Creating JSON Data
+ dataWithJSONObject:options:error:
+ writeJSONObject:toStream:options:error:
+ isValidJSONObject:
其中红色标记的方法是常用的方法,下面分别贴出其用法,注意每个方法使用过程中的参数类型。
Returns a Foundation object from given JSON data.
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error
其中的NSJSONReadingOptions包括:
NSJSONReadingMutableContainers
Specifies that arrays and dictionaries are created as mutable objects.
NSJSONReadingMutableLeaves
Specifies that leaf strings in the JSON object graph are created as instances of NSMutableString.
NSJSONReadingAllowFragments
Specifies that the parser should allow top-level objects that are not an instance of NSArray or NSDictionary.
Returns a Boolean value that indicates whether a given object can be converted to JSON data.
+ (BOOL)isValidJSONObject:(id)obj
Returns JSON data from a Foundation object.
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error
其中NSJSONWritingOptions包括
NSJSONWritingPrettyPrinted
Specifies that the JSON data should be generated with whitespace designed to make the output more readable. If this option is not set, the most compact possible JSON representation is generated.
下面通过一个简单的程序例子展示一下这个过程。
NSDictionary *jsonDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"value1",@"key1",@"value2",@"key2", nil];
NSError *error;
NSData *jsonData;
if ([NSJSONSerialization isValidJSONObject:jsonDictionary]) {
NSLog(@"yes");
jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:NSJSONWritingPrettyPrinted error:&error];
}
else {
NSLog(@"error :%@",error.localizedDescription);
}
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
NSLog(@"key1: %@",[dictionary objectForKey:@"key1"]);
二、JSONKit用法详解
(个人目前用到较多的是使用JSONKit来对json格式的字符串进行解析)
使用JSONKit需要在项目中导入JSONKit类库文件,可以从上面的链接中下载。
使用JSONKit对数据解析过程中常用的方法(都是实例方法)就是:
- (id)objectFromJSONString;
- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
- (id)mutableObjectFromJSONString;
- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
- (id)objectFromJSONData;
- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
- (id)mutableObjectFromJSONData;
- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
常用的分别是前三个。
其中的JKParseOptionFlags包括:
JKSerializeOptionNone = 0,
JKSerializeOptionPretty = (1 << 0),
JKSerializeOptionEscapeUnicode = (1 << 1),
JKSerializeOptionEscapeForwardSlashes = (1 << 4),
JKSerializeOptionValidFlags = (JKSerializeOptionPretty | JKSerializeOptionEscapeUnicode | JKSerializeOptionEscapeForwardSlashes),
下面代码实例演示解析字符串JSON格式:
NSString *jsonString =@"[{\"precision\": \"zip\",\"Latitude\": 37.7668,\"Longitude\": -122.3959,\"Address\": \"\",\"City\": \"SAN FRANCISCO\",\"State\": \"CA\",\"Zip\": \"94107\",\"Country\": \"US\"},{\"precision\": \"zip\",\"Latitude\": 37.371991,\"Longitude\": -122.026020,\"Address\": \"\",\"City\": \"SUNNYVALE\",\"State\": \"CA\",\"Zip\": \"94085\",\"Country\": \"US\"}]";
NSArray *jsonArray = [jsonString objectFromJSONString];
for(NSDictionary *dictionary in jsonArray) {
NSLog(@"City :%@",[dictionary objectForKey:@"City"]);
}
其中的jsonString是如下内容(有两个dictionary,所以我们可以用一个数组来装载,然后再用字典来分别装载里面内容):
[
{
\"precision\": \"zip\",
\"Latitude\": 37.7668,
\"Longitude\": -122.3959,
\"Address\": \"\",
\"City\": \"SANFRANCISCO\",
\"State\": \"CA\",
\"Zip\": \"94107\",
\"Country\": \"US\"
},
{
\"precision\": \"zip\",
\"Latitude\": 37.371991,
\"Longitude\": -122.026020,
\"Address\": \"\",
\"City\": \"SUNNYVALE\",
\"State\": \"CA\",
\"Zip\": \"94085\",
\"Country\": \"US\"
}
]
三、TouchJson用法详解
首先根据上面给出的下载链接下载这个库,解压后在项目导入Source文件夹。使用时要如下import相关文件。
#import "Source/JSON/CJSONDeserializer.h"
#import "Source/JSON/CJSONSerializer.h"
提示:如果是ARC项目,在target中关于TouchJson的所有文件请添加arc:-fno-objc-arc。
由上面的import的语句可知,使用这个库,既可以反序列化操作,即将JSON数据转换成其他对象,也可以序列化操作,即将某个对象转换成JSON数据。
1、下面看看序列化操作对应的方法吧!在CJSONSerializer.h文件中可以找到。
+ (CJSONSerializer *)serializer;
- (BOOL)isValidJSONObject:(id)inObject;
/// Take any JSON compatible object (generally NSNull, NSNumber, NSString, NSArray and NSDictionary) and produce an NSData containing the serialized JSON.
- (NSData *)serializeObject:(id)inObject error:(NSError **)outError;
- (NSData *)serializeNull:(NSNull *)inNull error:(NSError **)outError;
- (NSData *)serializeNumber:(NSNumber *)inNumber error:(NSError **)outError;
- (NSData *)serializeString:(NSString *)inString error:(NSError **)outError;
- (NSData *)serializeArray:(NSArray *)inArray error:(NSError **)outError;
- (NSData *)serializeDictionary:(NSDictionary *)inDictionary error:(NSError **)outError;
上面的方法中常用的是前三个,而且注意:Take any JSON compatible object (generally NSNull, NSNumber, NSString, NSArray and NSDictionary) and produce an NSData containing the serialized JSON.下面看看实例代码吧!
NSError *error;
NSString *jsonString =@"{\"key1\":{\"precision\": \"zip\",\"Latitude\": 37.7668,\"Longitude\": -122.3959,\"Address\": \"\",\"City\": \"SAN FRANCISCO\",\"State\": \"CA\",\"Zip\": \"94107\",\"Country\": \"US\"},\"key2\":{\"precision\": \"zip\",\"Latitude\": 37.371991,\"Longitude\": -122.026020,\"Address\": \"\",\"City\": \"SUNNYVALE\",\"State\": \"CA\",\"Zip\": \"94085\",\"Country\": \"US\"}}";
CJSONSerializer *serial = [CJSONSerializer serializer]; //creat an object of CJSONSerializer
if ([serial isValidJSONObject:jsonString]) {
NSLog(@"yes");
NSData *jsonData = [serial serializeString:jsonString error:&error];
}
}
2、接着就是反序列化操作(通常说的数据解析),在CJSONDeserializer.h文件中我们可看到相应的方法。
+ (CJSONDeserializer *)deserializer;
- (id)deserialize:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError;
都比较容易理解,常用的还是前两个。看看实例代码吧!
NSString *jsonString =@"{\"key1\":{\"precision\": \"zip\",\"Latitude\": 37.7668,\"Longitude\": -122.3959,\"Address\": \"\",\"City\": \"SAN FRANCISCO\",\"State\": \"CA\",\"Zip\": \"94107\",\"Country\": \"US\"},\"key2\":{\"precision\": \"zip\",\"Latitude\": 37.371991,\"Longitude\": -122.026020,\"Address\": \"\",\"City\": \"SUNNYVALE\",\"State\": \"CA\",\"Zip\": \"94085\",\"Country\": \"US\"}}";
NSError *error;
NSArray *array = [[CJSONDeserializer deserializer] deserialize:[jsonString dataUsingEncoding:NSUTF8StringEncoding] error:&error];
for(NSDictionary *dic in array) {
NSLog(@"City :%@",[dic objectForKey:@"City"]);
}
上面是将一个json字符串编码成jsona格式,然后对其进行解析也即反序列化。
四、SBJson用法详解
在使用SBJson对数据进行解析时,要导入相应的文件,并#import "SBJson/SBJsonParser.h",主要使用的方法有:
- (id)objectWithData:(NSData*)data;
- (id)objectWithString:(NSString *)repr;
- (id)objectWithString:(NSString*)jsonText
error:(NSError**)error;
下面实例演示如何使用SBJson对数据进行解析。
NSString *jsonString =@"{\"key1\":{\"precision\": \"zip\",\"Latitude\": 37.7668,\"Longitude\": -122.3959,\"Address\": \"\",\"City\": \"SAN FRANCISCO\",\"State\": \"CA\",\"Zip\": \"94107\",\"Country\": \"US\"},\"key2\":{\"precision\": \"zip\",\"Latitude\": 37.371991,\"Longitude\": -122.026020,\"Address\": \"\",\"City\": \"SUNNYVALE\",\"State\": \"CA\",\"Zip\": \"94085\",\"Country\": \"US\"}}";
NSError *error;
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *dictionary= [parser objectWithString:jsonString error:&error];
NSLog(@"%@",dictionary);
NSLog(@"%@",[[dictionary objectForKey:@"key1"] objectForKey:@"City"]);
解释一下,这里的jsonString和前面使用的有一点区别,待会看输出就知道了(为两个dictionary添加了key1和key2)。
首先要创建一个SBJsonParser对象,然后调用方法进行解析。
{
key1 = {
Address = "";
City = "SAN FRANCISCO";
Country = US;
Latitude = "37.7668";
Longitude = "-122.3959";
State = CA;
Zip = 94107;
precision = zip;
};
key2 = {
Address = "";
City = SUNNYVALE;
Country = US;
Latitude = "37.371991";
Longitude = "-122.02602";
State = CA;
Zip = 94085;
precision = zip;
};
}
二、xml解析
这里首先明白什么是SAX是一个用于处理XML事件驱动的“推”模型,优点是一种解析速度快并且占用内存少的xml解析器,它需要哪些数据再加载和解析哪些内容。缺点是它不会记录标签的关系,而要让你的应用程序自己处理,这样就增加了你程序的负担。DOM是一种文档对象模型,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。Dom技术使得用户页面可以动态地变化,如可以动态地显示或隐藏一个元素,改变它们的属性,增加一个元素等,Dom技术使得页面的交互性大大地增强。缺点是DOM解析XML文件时,会将XML文件的所有内容以文档树方式存放在内存中。
Pull解析和Sax解析很相似,Pull解析和Sax解析不一样的地方是pull读取xml文件后触发相应的事件调用方法返回的是数字还有pull可以在程序中控制想解析到哪里就可以停止解析。
以penson.xml文件为例:
name
男
30
第一种SAX 解析代码如下
public class SaxParseService extends DefaultHandler{
private List mPensons = null;
private Penson mPenson = null;
private String m_preTag = null;
public List getPensons(InputStream xmlStream) throws Exception{ SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
SaxParseService handler = new SaxParseService(); parser.parse(xmlStream, handler);
return handler.getPensons();
}
public List getPensons(){
return mPensons;
}
@Override
public void startDocument() throws SAXException {
mPensons = new ArrayList();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if("Penson".equals(qName)){
mPenson = new Penson(); mPenson.penId=Integer.parseInt(attributes.getValue(0));
}
m_preTag = qName;//将正在解析的节点名称赋给preTag
}
@Override
public void endElement(String uri, String localName, String qName)throws SAXException {
if("Penson".equals(qName)){
mPensons.add(mPenson);
mPenson = null;
}
m_preTag = null;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException { if(m_preTag!=null){
try {
String content = new String(ch,start,length); if("name".equals(m_preTag)){
mPenson.name=content;
}else if("sex".equals(m_preTag)){
mPenson.sex=content;
}else if("age".equals(m_preTag)){ mPenson.age=Integer.parseInt(content);
} }catch(Exception e){} } }}
第二种PULL 解析代码如下:
public class PullParseService {
public static List getPensons(InputStream inputStream) throws Exception{ List mPensons = null;
Penson mPenson = null;
XmlPullParser parser = Xml.newPullParser(); parser.setInput(inputStream, "UTF-8");
int event = parser.getEventType(); while(event!=XmlPullParser.END_DOCUMENT){
switch(event){
case XmlPullParser.START_DOCUMENT:
mPensons = new ArrayList();
break;
case XmlPullParser.START_TAG: if("Penson".equals(parser.getName())){
mPenson = new Penson(); mPenson.penId=Integer.parseInt(parser.getAttributeValue(0)); } if(mPenson!=null){ if("name".equals(parser.getName())){ mPenson.name=parser.nextText();
}else if("sex".equals(parser.getName())){ mPenson.sex=parser.nextText();
}else if("age".equals(parser.getName())){ mPenson.age=Integer.parseInt(parser.nextText()); } } break;
case XmlPullParser.END_TAG: if("Penson".equals(parser.getName())){
mPensons.add(mPenson);
mPenson = null; } break; }
event = parser.next();
}
return mPensons; } }
第三种DOM 解析代码如下:
public class DomParseService {
public List getPensons(InputStream inputStream) throws Exception{ List list = new ArrayList();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inputStream);
Element element = document.getDocumentElement();
NodeList PensonNodes = element.getElementsByTagName("Penson");
for(int i=0;i
Element PensonElement = (Element) PensonNodes.item(i);
Penson mPenson = new Penson(); mPenson.penId=Integer.parseInt(PensonElement.getAttribute("id")); NodeList childNodes = PensonElement.getChildNodes();
for(int j=0;j
if("name".equals(childNodes.item(j).getNodeName())){
mPenson.name=childNodes.item(j).getFirstChild().getNodeValue(); }else if("sex".equals(childNodes.item(j).getNodeName())){ mPenson.sex=childNodes.item(j).getFirstChild().getNodeValue(); }else if("age".equals(childNodes.item(j).getNodeName())){ mPenson.age=Integer.parseInt(childNodes.item(j).getFirstChild().getNodeValue()); } } }
list.add(mPenson);
}
return list; }}
测试代码
public class MainActivity extends Activity implements OnClickListener{
private TextView mText;
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText=(TextView) findViewById(R.id.text); findViewById(R.id.btn_sax).setOnClickListener(this); findViewById(R.id.btn_pull).setOnClickListener(this); findViewById(R.id.btn_dom).setOnClickListener(this);
testSaxXml();
}
public void testSaxXml() {
try {
InputStream input=this.getResources().getAssets().open("peson.xml"); SaxParseService sax = new SaxParseService();
List mPensons=sax.getPensons(input);
for(Penson mPenson : mPensons){
String text= "sax analyze:"+mPenson.toString(); mText.setText(text);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
public void testPullXml() {
try {
InputStream input=this.getResources().getAssets().open("peson.xml"); PullParseService pull = new PullParseService();
List mPensons=pull.getPensons(input);
for(Penson mPenson : mPensons) {
String text= "pull analyze:"+mPenson.toString();
mText.setText(text);
} } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
public void testDomXml() { try {
InputStream input=this.getResources().getAssets().open("peson.xml"); DomParseService dom = new DomParseService();
List mPensons=dom.getPensons(input);
for(Penson mPenson : mPensons) {
String text= "dom analyze:"+mPenson.toString(); mText.setText(text);
} } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btn_sax:
testSaxXml();
break;
case R.id.btn_pull:
testPullXml();
break;
case R.id.btn_dom:
testDomXml();
break; } }}