2013-06-05 31 views
11

Tôi có một ứng dụng iOS cần xử lý phản hồi từ dịch vụ web. Câu trả lời là một chuỗi JSON serialized chứa một đối tượng JSON serialized, tìm một cái gì đó như thế này:Làm thế nào bạn có thể deserialize một chuỗi JSON thoát với NSJSONSerialization?

"{ \"name\" : \"Bob\", \"age\" : 21 }" 

Lưu ý rằng phản ứng này là một JSON chuỗi, không phải là một đối tượng JSON. Những gì tôi cần làm là deserialize chuỗi, vì vậy mà tôi có được điều này:

{ "name" : "Bob", "age" : 21 } 

Và sau đó tôi có thể sử dụng +[NSJSONSerialization JSONObjectWithData:options:error:] để deserialize đó vào một NSDictionary.

Nhưng, làm cách nào để thực hiện bước đầu tiên đó? Đó là, làm thế nào để tôi "unescape" chuỗi để tôi có một đối tượng JSON serialized? +[NSJSONSerialization JSONObjectWithData:options:error:] chỉ hoạt động nếu đối tượng cấp cao nhất là mảng hoặc từ điển; nó không hoạt động trên dây.

Tôi đã kết thúc bằng văn bản my own JSON string parser, mà tôi hy vọng phù hợp với section 2.5 of RFC 4627. Nhưng tôi nghi ngờ tôi đã bỏ qua một số cách dễ dàng để làm điều này bằng cách sử dụng NSJSONSerialization hoặc một số phương pháp có sẵn khác.

+0

Chỉ cần cắt đứt hàng đầu và đuôi quoteß và sau đó thay thế tất cả '\" 's với '" '. –

+0

Sau đó, bạn lặp lại quá trình unescaping cho mỗi trình tự thoát có thể có (có rất nhiều finitely). –

+0

Chuỗi thoát '\ uXXXX' làm cho việc tìm kiếm và thay thế trở nên khó khăn. –

Trả lời

24

Nếu bạn đã lồng JSON, sau đó chỉ cần gọi số JSONObjectWithData hai lần:

NSString *string = @"\"{ \\\"name\\\" : \\\"Bob\\\", \\\"age\\\" : 21 }\""; 
// --> the string 
// "{ \"name\" : \"Bob\", \"age\" : 21 }" 

NSError *error; 
NSString *outerJson = [NSJSONSerialization JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding] 
           options:NSJSONReadingAllowFragments error:&error]; 
// --> the string 
// { "name" : "Bob", "age" : 21 } 
NSDictionary *innerJson = [NSJSONSerialization JSONObjectWithData:[outerJson dataUsingEncoding:NSUTF8StringEncoding] 
           options:0 error:&error]; 
// --> the dictionary 
// { age = 21; name = Bob; } 
+0

Khi tôi đã thử điều đó, tôi nhận được một thông báo lỗi. Dường như nó chỉ hoạt động nếu đối tượng cấp cao nhất là một mảng hoặc từ điển. –

+0

@KristopherJohnson: Tôi đã thử chính xác mã này và nó đã làm việc cho tôi. Bạn cần tùy chọn NSJSONReadingAllowFragments trong bước đầu tiên. –

+0

Tôi thề tôi đã thử 'NSJSONReadingAllowFragments' trước đây, và nó không hoạt động, nhưng bây giờ nó đã làm. Cảm ơn đã khiến tôi thử lại lần nữa. –

0

Chuyển đổi chuỗi số liệu:

NSString *string = @"{ \"name\" : \"Bob\", \"age\" : 21 }"; 
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; 
NSError *error; 
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 
+0

Tôi có đối tượng 'NSData' khi tôi gọi' NSJSONSerialization'. Vì vậy, nó giống như mã của bạn là 'string = @" \ "{\\" tên \\ ": \\" Bob \\ ", \\" tuổi \ ": 21} \" ";' –

+0

bạn nhận được chuỗi đó? Nghe có vẻ giống như một nơi nào đó dọc theo đường ống, nó bị thoát kép, và đó là những gì bạn cần để gỡ lỗi. –

+1

Dịch vụ web sẽ thoát kép. Bạn và tôi có thể đồng ý rằng nó không nên, nhưng nó có, và tôi phải đối phó với nó. –

0

Chỉ cần cắt đứt các dấu ngoặc kép ở đầu và đuôi và sau đó thay thế tất cả \ "s với":

NSString *sub = [original substringWithRange:(NSRange){ 1, original.length - 2 }]; 
NSString *unescaped = [sub stringByReplacingOccurrencesOfString:@"\\\" withString:@"\"]; 
+0

Đó là giải pháp hacky ban đầu của tôi, nhưng nó chỉ hoạt động nếu không có các ký tự đặc biệt khác trong chuỗi ('\ n',' \ t', '\ u1234', v.v.). Nhưng tôi không thể giả định điều đó. –

+0

Chuỗi JSON sẽ yêu cầu thoát khỏi các ký tự này. Vì vậy, khi một bộ mã hóa được áp dụng, nó sẽ chỉ thoát khỏi sự trốn thoát: "(\\ n)" – CouchDeveloper

0

Trước hết, hãy hỏi, tại sao máy chủ không bao gồm JSON, như một cấu trúc phụ.

Nhưng dù sao đi nữa. Chuỗi bạn đã xem có vẻ là một mã vạch đã thoát được JSON. Điều đó thực sự là , hoàn toàn phụ thuộc vào nhà phát triển dịch vụ web. Tôi nghi ngờ rằng chỉ có các dấu ngoặc kép và một lối thoát tự nó đã được thoát với một lối thoát \. Chuỗi kết quả không được "nối tiếp" - JSON đã được tuần tự hóa - nhưng được mã hóa. Để hoàn nguyên trở lại - bạn cần phải "unescape" hoặc decode nó một lần nữa:

Một chút C++ đoạn cho thấy cách (Tôi biết bạn yêu cầu Objective-C - nhưng điều này chỉ là quá dễ dàng):

Chỉnh sửa: mã cũng sẽ hoạt động cho UTF-16 và UTF-32 - với bất kỳ độ cuối nào - và nếu bộ mã hóa chỉ làm đúng những gì tôi nghi ngờ, nó cũng sẽ hoạt động cho các ký tự unicode thoát, ví dụ \ u1234, v.v.

Chỉnh sửa - không, nó sẽ không hoạt động đối với UTF-16 và UTF-32. Các mẫu sẽ phải được cố định cho điều đó (mà sẽ được dễ dàng). Nhưng hãy đảm bảo bạn có UTF-8 - hầu như luôn luôn như vậy.

#include <iostream> 

char input[] = u8R"___({ \"name\" : \"Bob\", \"age\" : 21 })___"; 

// Unescapes the character sequence "in-situ". 
// Returns a pointer to "past-the-end" of the unescaped string. 
static char* unescape(char* first, char* last) { 
    char* dest = first; 
    while (first != last) { 
     if (*first == '\\') { 
      ++first; 
     } 
     *dest++ = *first++; 
    } 
    return dest; 
} 

int main(int argc, const char * argv[]) 
{ 
    char* first = input; 
    char* last = first + strlen(input); 
    std::string s(input, unescape(first, last)); 

    std::cout << s << std::endl; 

    return 0; 
} 

Prints:

{ "tên": "Bob", "tuổi": 21}

+1

Ví dụ của bạn hoạt động trên đầu vào '{\" tên \ ": \" Bob \ ", \" tuổi \ ": 21}'. Nhưng phản hồi của máy chủ thực tế là (như tôi hiểu) '" {\ "tên \": \ "Bob \", \ "tuổi \": 21} "' (lưu ý dấu ngoặc kép đầu và cuối). Đó là lý do tại sao NSJSONReadingAllowFragments hoạt động. –

+0

OK, điều đó có nghĩa, NSJSONSerialization diễn giải điều này dưới dạng một chuỗi JSON và sau đó trả về đối tượng cấp cao nhất này - đó là một NSString. Vì vậy, hiệu quả nó áp dụng một "JSON String decoder" vào chuỗi đã cho. Điều đó có thể làm việc - nhưng tôi sẽ làm rõ cách thức chuỗi đã cho đã được giải mã bởi dịch vụ web. – CouchDeveloper

Các vấn đề liên quan