1

次の JSON を使用しています: http://www.kb.dk/tekst/mobil/aabningstider_en.json キー「場所」で解析しようとすると、次のようになります。

//    get response in the form of a utf-8 encoded json string
NSString *jsonString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];

//    get most parent node from json string
NSDictionary *json = [jsonString JSONValue];

//    get key-path from jason up to the point of json object
NSDictionary *locations = [json objectForKey:@"location"];

NSLog( @"%@", locations );

//    iterate through all of the location objects in the json
for (NSDictionary *loc in locations )
{

    //        pull library name from the json object
    NSString *name = [loc valueForKey:@"name"];
    //        add library data table arrays respectively
    [ libraryNames addObject: ( ( name == nil | name.length > 0 ) ? name : @"UnNamed" ) ];

}

NSLog を介してオブジェクトの場所を出力すると、次のようになります。

{
address = "Universitetsparken 4, 3. etage, 2100 K\U00f8benhavn \U00d8";
desc = "";
lastUpdated = "";
latlng = "55.703124,12.559596";
link = "http://www.farma.ku.dk/index.php?id=3742";
name = "Faculty of Pharmaceutical Sciences Library";
parts =     {
    part =         {
        hour =             {
            day = "5.June Constitution Day (Denmark)";
            open = Closed;
        };
        hours =             {
            hour =                 {
                day = Friday;
                open = "10-16";
            };
        };
        name = main;
    };
};
}

「場所」キーの最後の値のみです。私は何か間違ったことをしていますか?http://jsonlint.com/経由で JSON を検証しようとしましたが、上記のように JSON URL を入力すると、「有効」と表示されました - それでも最後の「場所」キーのみが表示されました」 -貼り付けると、JSON が検証されず、文字列から改行を削除して修正する必要があります。

また、JSON を解析して「名前」フィールドを取得しようとすると、次の例外が発生します。

2012-05-08 15:37:04.941 iPhone App Tabbed[563:f803] *** Terminating app due to uncaught         exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x68bfe70> valueForUndefinedKey:]:     this class is not key value coding-compliant for the key name.'
*** First throw call stack:
(0x13dc052 0x156dd0a 0x13dbf11 0x9d2f0e 0x941841 0x940ca9 0x4593 0xf964e 0x114b89 0x1149bd     0x112f8a 0x112e2f 0x1148f4 0x13ddec9 0x365c2 0x3655a 0x25b569 0x13ddec9 0x365c2 0x3655a     0xdbb76 0xdc03f 0xdbbab 0x25dd1f 0x13ddec9 0x365c2 0x3655a 0xdbb76 0xdc03f 0xdb2fe 0x5ba30     0x5bc56 0x42384 0x35aa9 0x12c6fa9 0x13b01c5 0x1315022 0x131390a 0x1312db4 0x1312ccb 0x12c5879     0x12c593e 0x33a9b 0x281d 0x2785)
terminate called throwing an exception(lldb) 

「locations」タグが角かっこ ([]) で囲まれた配列オブジェクトであれば、より理にかなっていますが、現在は通常のキーと値のペアのシーケンスにすぎません...悲しいことに、それは私が使用しなければならない JSON です。 .

助けてください、そしてどうもありがとう!:)

敬具、ピョートル。

4

3 に答える 3

2

処理しなければならない JSON は有効かもしれませんが、あまり意味がありません。locationキーが何度も繰り返される1 つの大きな辞書があります。ほとんどの JSON パーサーは、繰り返されたキーの最後の値を返すだけです。代わりに配列を使用するように構造を変更できれば最善ですが、それができない場合でもまだ望みはあります。ストリームを読み取り、locationキーからの値を配列に詰め込むことができます。これはあなたがそれを行う方法です:

@interface BadJsonHelper : NSObject
@property(strong) NSMutableArray *accumulator;
@end    
@implementation BadJsonHelper
- (void)parser:(SBJsonStreamParser *)parser foundArray:(NSArray *)array {
    // void
}
- (void)parser:(SBJsonStreamParser *)parser foundObject:(NSDictionary *)dict {
    [accumulator addObject:dict];
}
@end

その小さなヘルパー クラスをファイルの先頭、作業を行っているクラスの @implementation セクションの外にドロップできます。(@interface と @implementation が異なるファイルにある必要はありません。)

コードでは、次のように使用します。

BadJsonHelper *helper = [[BadJsonHelper alloc] init];
helper.accumulator = [NSMutableArray array];

SBJsonStreamParserAdapter *adapter = [[SBJsonStreamParserAdapter new] init];
adapter.delegate = helper;
adapter.levelsToSkip = 1;

SBJsonStreamParser *parser = [[SBJsonStreamParser alloc] init];
parser.delegate = adapter;

switch ([parser parse: responseData]) {
    case SBJsonStreamParserComplete: 
        NSLog(@"%@", helper.accumulator);
        break;
    case SBJsonStreamParserWaitingForData:
        NSLog(@"Didn't get all the JSON yet...");
        break;
    case SBJsonStreamParserError:
        NSLog(@"Error: %@", parser.error);
        break;
}

この例は、もともと次のテストから改作されました: https://github.com/stig/json-framework/blob/master/Tests/StreamParserIntegrationTest.m

更新: JSON を非同期的に読み込んで解析する、完全に機能するサンプル プロジェクトを作成しました。これはgithubから入手できます。

于 2012-05-10T22:36:23.070 に答える
1
NSDictionary *locations = [json objectForKey:@"location"];

ご覧のとおり、SBJson による JSON 解析の結果はNSDictionary. ディクショナリにはキーと値のペアが含まれており、キーはペアの一意の識別子です。

処理する必要がある JSON データは有効ですが、適切なものではありません。RFC 4627 - 2.2に従って:

オブジェクト構造は、0 個以上の名前と値のペア (またはメンバー) を囲む中かっこのペアとして表されます。名前は文字列です。各名前の後にコロンを 1 つ付けて、名前と値を区切ります。単一のコンマは、値とそれに続く名前を区切ります。 オブジェクト内の名前は一意である必要があります。

jQuery のようなものも JSON を解析できますが、結果は SBJson と同じです (最後のものは 1 つです)。JSON キーは一意である必要がありますか? を参照してください。.

これは必須ではありませんが、それでも良い習慣ではありません。JSON データをそのまま解析するよりも、サーバー側 (または受信後にクライアント側でも) で JSON データの構造を変更できれば、はるかに簡単になります。

于 2012-05-08T14:09:06.483 に答える
1

JSON は有効ですが、項目の配列の定義に関して基本的な問題があります。

括弧を使用して配列を定義する代わりにlocations、JSON は同じlocationキーと値のペアを何度も再定義します。つまり、JSON は最初に location の値が "The Black Diamond" という名前のコレクションであると言いますが、直後に "Faculty Library of Humanities" という名前のコレクションでそれを再定義し、最後の場所まで薬学科学図書館まで続きます。 "。

partsとについても同様ですhours

JSON の結果を修正できず、実際に機能させる必要がある場合は、JSON を変更して「場所」キーを削除し、ブラケットを適切に追加することをお勧めします。

編集

または、 を使用してNSScanner、JSON の結果を手動で処理することもできます。ちょっとハックですが、JSON 形式が大幅に変更されない限り機能します。

編集

この抜粋されたコードは機能するはずです...

NSString *jsonString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];

int indx = 1;
for (;;)
{
    NSRange locationRange = [jsonString rangeOfString:@"\"location\":"];

    if (locationRange.location == NSNotFound) break;

    jsonString = [jsonString stringByReplacingCharactersInRange:locationRange
                                                     withString:[NSString stringWithFormat:@"\"location%d\":", indx++]];
} 
于 2012-05-08T14:03:27.843 に答える