123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- //
- // NSDictionary+YYAdd.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 13/4/4.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "NSDictionary+YYAdd.h"
- #import "NSString+YYAdd.h"
- #import "NSData+YYAdd.h"
- #import "YYKitMacro.h"
- YYSYNTH_DUMMY_CLASS(NSDictionary_YYAdd)
- @interface _YYXMLDictionaryParser : NSObject <NSXMLParserDelegate>
- @end
- @implementation _YYXMLDictionaryParser {
- NSMutableDictionary *_root;
- NSMutableArray *_stack;
- NSMutableString *_text;
- }
- - (instancetype)initWithData:(NSData *)data {
- self = super.init;
- NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
- [parser setDelegate:self];
- [parser parse];
- return self;
- }
- - (instancetype)initWithString:(NSString *)xml {
- NSData *data = [xml dataUsingEncoding:NSUTF8StringEncoding];
- return [self initWithData:data];
- }
- - (NSDictionary *)result {
- return _root;
- }
- #pragma mark - NSXMLParserDelegate
- #define XMLText @"_text"
- #define XMLName @"_name"
- #define XMLPref @"_"
- - (void)textEnd {
- _text = _text.stringByTrim.mutableCopy;
- if (_text.length) {
- NSMutableDictionary *top = _stack.lastObject;
- id existing = top[XMLText];
- if ([existing isKindOfClass:[NSArray class]]) {
- [existing addObject:_text];
- } else if (existing) {
- top[XMLText] = [@[existing, _text] mutableCopy];
- } else {
- top[XMLText] = _text;
- }
- }
- _text = nil;
- }
- - (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict {
- [self textEnd];
-
- NSMutableDictionary *node = [NSMutableDictionary new];
- if (!_root) node[XMLName] = elementName;
- if (attributeDict.count) [node addEntriesFromDictionary:attributeDict];
-
- if (_root) {
- NSMutableDictionary *top = _stack.lastObject;
- id existing = top[elementName];
- if ([existing isKindOfClass:[NSArray class]]) {
- [existing addObject:node];
- } else if (existing) {
- top[elementName] = [@[existing, node] mutableCopy];
- } else {
- top[elementName] = node;
- }
- [_stack addObject:node];
- } else {
- _root = node;
- _stack = [NSMutableArray arrayWithObject:node];
- }
- }
- - (void)parser:(__unused NSXMLParser *)parser didEndElement:(__unused NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName {
- [self textEnd];
-
- NSMutableDictionary *top = _stack.lastObject;
- [_stack removeLastObject];
-
- NSMutableDictionary *left = top.mutableCopy;
- [left removeObjectsForKeys:@[XMLText, XMLName]];
- for (NSString *key in left.allKeys) {
- [left removeObjectForKey:key];
- if ([key hasPrefix:XMLPref]) {
- left[[key substringFromIndex:XMLPref.length]] = top[key];
- }
- }
- if (left.count) return;
-
- NSMutableDictionary *children = top.mutableCopy;
- [children removeObjectsForKeys:@[XMLText, XMLName]];
- for (NSString *key in children.allKeys) {
- if ([key hasPrefix:XMLPref]) {
- [children removeObjectForKey:key];
- }
- }
- if (children.count) return;
-
- NSMutableDictionary *topNew = _stack.lastObject;
- NSString *nodeName = top[XMLName];
- if (!nodeName) {
- for (NSString *name in topNew) {
- id object = topNew[name];
- if (object == top) {
- nodeName = name; break;
- } else if ([object isKindOfClass:[NSArray class]] && [object containsObject:top]) {
- nodeName = name; break;
- }
- }
- }
- if (!nodeName) return;
-
- id inner = top[XMLText];
- if ([inner isKindOfClass:[NSArray class]]) {
- inner = [inner componentsJoinedByString:@"\n"];
- }
- if (!inner) return;
-
- id parent = topNew[nodeName];
- if ([parent isKindOfClass:[NSArray class]]) {
- NSArray *parentAsArray = parent;
- parent[parentAsArray.count - 1] = inner;
- } else {
- topNew[nodeName] = inner;
- }
- }
- - (void)parser:(__unused NSXMLParser *)parser foundCharacters:(NSString *)string {
- if (_text) [_text appendString:string];
- else _text = [NSMutableString stringWithString:string];
- }
- - (void)parser:(__unused NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock {
- NSString *string = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
- if (_text) [_text appendString:string];
- else _text = [NSMutableString stringWithString:string];
- }
- #undef XMLText
- #undef XMLName
- #undef XMLPref
- @end
- @implementation NSDictionary (YYAdd)
- + (NSDictionary *)dictionaryWithPlistData:(NSData *)plist {
- if (!plist) return nil;
- NSDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListImmutable format:NULL error:NULL];
- if ([dictionary isKindOfClass:[NSDictionary class]]) return dictionary;
- return nil;
- }
- + (NSDictionary *)dictionaryWithPlistString:(NSString *)plist {
- if (!plist) return nil;
- NSData *data = [plist dataUsingEncoding:NSUTF8StringEncoding];
- return [self dictionaryWithPlistData:data];
- }
- - (NSData *)plistData {
- return [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListBinaryFormat_v1_0 options:kNilOptions error:NULL];
- }
- - (NSString *)plistString {
- NSData *xmlData = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:kNilOptions error:NULL];
- if (xmlData) return xmlData.utf8String;
- return nil;
- }
- - (NSArray *)allKeysSorted {
- return [[self allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
- }
- - (NSArray *)allValuesSortedByKeys {
- NSArray *sortedKeys = [self allKeysSorted];
- NSMutableArray *arr = [[NSMutableArray alloc] init];
- for (id key in sortedKeys) {
- [arr addObject:self[key]];
- }
- return [arr copy];
- }
- - (BOOL)containsObjectForKey:(id)key {
- if (!key) return NO;
- return self[key] != nil;
- }
- - (NSDictionary *)entriesForKeys:(NSArray *)keys {
- NSMutableDictionary *dic = [NSMutableDictionary new];
- for (id key in keys) {
- id value = self[key];
- if (value) dic[key] = value;
- }
- return [dic copy];
- }
- - (NSString *)jsonStringEncoded {
- if ([NSJSONSerialization isValidJSONObject:self]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
- NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- if (!error) return json;
- }
- return nil;
- }
- - (NSString *)jsonPrettyStringEncoded {
- if ([NSJSONSerialization isValidJSONObject:self]) {
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error];
- NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- if (!error) return json;
- }
- return nil;
- }
- + (NSDictionary *)dictionaryWithXML:(id)xml {
- _YYXMLDictionaryParser *parser = nil;
- if ([xml isKindOfClass:[NSString class]]) {
- parser = [[_YYXMLDictionaryParser alloc] initWithString:xml];
- } else if ([xml isKindOfClass:[NSData class]]) {
- parser = [[_YYXMLDictionaryParser alloc] initWithData:xml];
- }
- return [parser result];
- }
- /// Get a number value from 'id'.
- static NSNumber *NSNumberFromID(id value) {
- static NSCharacterSet *dot;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)];
- });
- if (!value || value == [NSNull null]) return nil;
- if ([value isKindOfClass:[NSNumber class]]) return value;
- if ([value isKindOfClass:[NSString class]]) {
- NSString *lower = ((NSString *)value).lowercaseString;
- if ([lower isEqualToString:@"true"] || [lower isEqualToString:@"yes"]) return @(YES);
- if ([lower isEqualToString:@"false"] || [lower isEqualToString:@"no"]) return @(NO);
- if ([lower isEqualToString:@"nil"] || [lower isEqualToString:@"null"]) return nil;
- if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
- return @(((NSString *)value).doubleValue);
- } else {
- return @(((NSString *)value).longLongValue);
- }
- }
- return nil;
- }
- #define RETURN_VALUE(_type_) \
- if (!key) return def; \
- id value = self[key]; \
- if (!value || value == [NSNull null]) return def; \
- if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value)._type_; \
- if ([value isKindOfClass:[NSString class]]) return NSNumberFromID(value)._type_; \
- return def;
- - (BOOL)boolValueForKey:(NSString *)key default:(BOOL)def {
- RETURN_VALUE(boolValue);
- }
- - (char)charValueForKey:(NSString *)key default:(char)def {
- RETURN_VALUE(charValue);
- }
- - (unsigned char)unsignedCharValueForKey:(NSString *)key default:(unsigned char)def {
- RETURN_VALUE(unsignedCharValue);
- }
- - (short)shortValueForKey:(NSString *)key default:(short)def {
- RETURN_VALUE(shortValue);
- }
- - (unsigned short)unsignedShortValueForKey:(NSString *)key default:(unsigned short)def {
- RETURN_VALUE(unsignedShortValue);
- }
- - (int)intValueForKey:(NSString *)key default:(int)def {
- RETURN_VALUE(intValue);
- }
- - (unsigned int)unsignedIntValueForKey:(NSString *)key default:(unsigned int)def {
- RETURN_VALUE(unsignedIntValue);
- }
- - (long)longValueForKey:(NSString *)key default:(long)def {
- RETURN_VALUE(longValue);
- }
- - (unsigned long)unsignedLongValueForKey:(NSString *)key default:(unsigned long)def {
- RETURN_VALUE(unsignedLongValue);
- }
- - (long long)longLongValueForKey:(NSString *)key default:(long long)def {
- RETURN_VALUE(longLongValue);
- }
- - (unsigned long long)unsignedLongLongValueForKey:(NSString *)key default:(unsigned long long)def {
- RETURN_VALUE(unsignedLongLongValue);
- }
- - (float)floatValueForKey:(NSString *)key default:(float)def {
- RETURN_VALUE(floatValue);
- }
- - (double)doubleValueForKey:(NSString *)key default:(double)def {
- RETURN_VALUE(doubleValue);
- }
- - (NSInteger)integerValueForKey:(NSString *)key default:(NSInteger)def {
- RETURN_VALUE(integerValue);
- }
- - (NSUInteger)unsignedIntegerValueForKey:(NSString *)key default:(NSUInteger)def {
- RETURN_VALUE(unsignedIntegerValue);
- }
- - (NSNumber *)numberValueForKey:(NSString *)key default:(NSNumber *)def {
- if (!key) return def;
- id value = self[key];
- if (!value || value == [NSNull null]) return def;
- if ([value isKindOfClass:[NSNumber class]]) return value;
- if ([value isKindOfClass:[NSString class]]) return NSNumberFromID(value);
- return def;
- }
- - (NSString *)stringValueForKey:(NSString *)key default:(NSString *)def {
- if (!key) return def;
- id value = self[key];
- if (!value || value == [NSNull null]) return def;
- if ([value isKindOfClass:[NSString class]]) return value;
- if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value).description;
- return def;
- }
- @end
- @implementation NSMutableDictionary (YYAdd)
- + (NSMutableDictionary *)dictionaryWithPlistData:(NSData *)plist {
- if (!plist) return nil;
- NSMutableDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:plist options:NSPropertyListMutableContainersAndLeaves format:NULL error:NULL];
- if ([dictionary isKindOfClass:[NSMutableDictionary class]]) return dictionary;
- return nil;
- }
- + (NSMutableDictionary *)dictionaryWithPlistString:(NSString *)plist {
- if (!plist) return nil;
- NSData *data = [plist dataUsingEncoding:NSUTF8StringEncoding];
- return [self dictionaryWithPlistData:data];
- }
- - (id)popObjectForKey:(id)aKey {
- if (!aKey) return nil;
- id value = self[aKey];
- [self removeObjectForKey:aKey];
- return value;
- }
- - (NSDictionary *)popEntriesForKeys:(NSArray *)keys {
- NSMutableDictionary *dic = [NSMutableDictionary new];
- for (id key in keys) {
- id value = self[key];
- if (value) {
- [self removeObjectForKey:key];
- dic[key] = value;
- }
- }
- return [dic copy];
- }
- @end
|