您的位置:首页 > 移动开发 > IOS开发

iOS XML转换字典类型(XMLDictionary)

2016-04-06 11:07 489 查看
.h

//

// XMLDictionary.h

//

// Version 1.4

//

// Created by Nick Lockwood on 15/11/2010.

// Copyright 2010 Charcoal Design. All rights reserved.

//

// Get the latest version of XMLDictionary from here:

//

// https://github.com/nicklockwood/XMLDictionary
//

// This software is provided 'as-is', without any express or implied

// warranty. In no event will the authors be held liable for any damages

// arising from the use of this software.

//

// Permission is granted to anyone to use this software for any purpose,

// including commercial applications, and to alter it and redistribute it

// freely, subject to the following restrictions:

//

// 1. The origin of this software must not be misrepresented; you must not

// claim that you wrote the original software. If you use this software

// in a product, an acknowledgment in the product documentation would be

// appreciated but is not required.

//

// 2. Altered source versions must be plainly marked as such, and must not be

// misrepresented as being the original software.

//

// 3. This notice may not be removed or altered from any source distribution.

//

#import <Foundation/Foundation.h>

#pragma GCC diagnostic push

#pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis"

typedef NS_ENUM(NSInteger, XMLDictionaryAttributesMode)

{

XMLDictionaryAttributesModePrefixed = 0, //default

XMLDictionaryAttributesModeDictionary,

XMLDictionaryAttributesModeUnprefixed,

XMLDictionaryAttributesModeDiscard

};

typedef NS_ENUM(NSInteger, XMLDictionaryNodeNameMode)

{

XMLDictionaryNodeNameModeRootOnly = 0, //default

XMLDictionaryNodeNameModeAlways,

XMLDictionaryNodeNameModeNever

};

static NSString *const XMLDictionaryAttributesKey = @"__attributes";

static NSString *const XMLDictionaryCommentsKey = @"__comments";

static NSString *const XMLDictionaryTextKey = @"__text";

static NSString *const XMLDictionaryNodeNameKey = @"__name";

static NSString *const XMLDictionaryAttributePrefix = @"_";

@interface XMLDictionaryParser : NSObject <NSCopying>

+ (XMLDictionaryParser *)sharedInstance;

@property (nonatomic, assign) BOOL collapseTextNodes; // defaults to YES

@property (nonatomic, assign) BOOL stripEmptyNodes; // defaults to YES

@property (nonatomic, assign) BOOL trimWhiteSpace; // defaults to YES

@property (nonatomic, assign) BOOL alwaysUseArrays; // defaults to NO

@property (nonatomic, assign) BOOL preserveComments; // defaults to NO

@property (nonatomic, assign) BOOL wrapRootNode; // defaults to NO

@property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode;

@property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode;

- (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser;

- (NSDictionary *)dictionaryWithData:(NSData *)data;

- (NSDictionary *)dictionaryWithString:(NSString *)string;

- (NSDictionary *)dictionaryWithFile:(NSString *)path;

@end

@interface NSDictionary (XMLDictionary)

+ (NSDictionary *)dictionaryWithXMLParser:(NSXMLParser *)parser;

+ (NSDictionary *)dictionaryWithXMLData:(NSData *)data;

+ (NSDictionary *)dictionaryWithXMLString:(NSString *)string;

+ (NSDictionary *)dictionaryWithXMLFile:(NSString *)path;

- (NSDictionary *)attributes;

- (NSDictionary *)childNodes;

- (NSArray *)comments;

- (NSString *)nodeName;

- (NSString *)innerText;

- (NSString *)innerXML;

- (NSString *)XMLString;

- (NSArray *)arrayValueForKeyPath:(NSString *)keyPath;

- (NSString *)stringValueForKeyPath:(NSString *)keyPath;

- (NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath;

@end

@interface NSString (XMLDictionary)

- (NSString *)XMLEncodedString;

@end

#pragma GCC diagnostic pop

.m

//

// XMLDictionary.m

//

// Version 1.4

//

// Created by Nick Lockwood on 15/11/2010.

// Copyright 2010 Charcoal Design. All rights reserved.

//

// Get the latest version of XMLDictionary from here:

//

// https://github.com/nicklockwood/XMLDictionary
//

// This software is provided 'as-is', without any express or implied

// warranty. In no event will the authors be held liable for any damages

// arising from the use of this software.

//

// Permission is granted to anyone to use this software for any purpose,

// including commercial applications, and to alter it and redistribute it

// freely, subject to the following restrictions:

//

// 1. The origin of this software must not be misrepresented; you must not

// claim that you wrote the original software. If you use this software

// in a product, an acknowledgment in the product documentation would be

// appreciated but is not required.

//

// 2. Altered source versions must be plainly marked as such, and must not be

// misrepresented as being the original software.

//

// 3. This notice may not be removed or altered from any source distribution.

//

#import "XMLDictionary.h"

#pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis"

#pragma GCC diagnostic ignored "-Wdirect-ivar-access"

#pragma GCC diagnostic ignored "-Wformat-non-iso"

#pragma GCC diagnostic ignored "-Wgnu"

#import <Availability.h>

#if !__has_feature(objc_arc)

#error This class requires automatic reference counting

#endif

@interface XMLDictionaryParser () <NSXMLParserDelegate>

@property (nonatomic, strong) NSMutableDictionary *root;

@property (nonatomic, strong) NSMutableArray *stack;

@property (nonatomic, strong) NSMutableString *text;

@end

@implementation XMLDictionaryParser

+ (XMLDictionaryParser *)sharedInstance

{

static dispatch_once_t once;

static XMLDictionaryParser *sharedInstance;

dispatch_once(&once, ^{

sharedInstance = [[XMLDictionaryParser alloc] init];

});

return sharedInstance;

}

- (id)init

{

if ((self = [super init]))

{

_collapseTextNodes = YES;

_stripEmptyNodes = YES;

_trimWhiteSpace = YES;

_alwaysUseArrays = NO;

_preserveComments = NO;

_wrapRootNode = NO;

}

return self;

}

- (id)copyWithZone:(NSZone *)zone

{

XMLDictionaryParser *copy = [[[self class] allocWithZone:zone] init];

copy.collapseTextNodes = _collapseTextNodes;

copy.stripEmptyNodes = _stripEmptyNodes;

copy.trimWhiteSpace = _trimWhiteSpace;

copy.alwaysUseArrays = _alwaysUseArrays;

copy.preserveComments = _preserveComments;

copy.attributesMode = _attributesMode;

copy.nodeNameMode = _nodeNameMode;

copy.wrapRootNode = _wrapRootNode;

return copy;

}

- (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser

{

[parser setDelegate:self];

[parser parse];

id result = _root;

_root = nil;

_stack = nil;

_text = nil;

return result;

}

- (NSDictionary *)dictionaryWithData:(NSData *)data

{

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

return [self dictionaryWithParser:parser];

}

- (NSDictionary *)dictionaryWithString:(NSString *)string

{

NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];

return [self dictionaryWithData:data];

}

- (NSDictionary *)dictionaryWithFile:(NSString *)path

{

NSData *data = [NSData dataWithContentsOfFile:path];

return [self dictionaryWithData:data];

}

+ (NSString *)XMLStringForNode:(id)node withNodeName:(NSString *)nodeName

{

if ([node isKindOfClass:[NSArray class]])

{

NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:[(NSArray *)node count]];

for (id individualNode in node)

{

[nodes addObject:[self XMLStringForNode:individualNode withNodeName:nodeName]];

}

return [nodes componentsJoinedByString:@"\n"];

}

else if ([node isKindOfClass:[NSDictionary class]])

{

NSDictionary *attributes = [(NSDictionary *)node attributes];

NSMutableString *attributeString = [NSMutableString string];

for (NSString *key in [attributes allKeys])

{

[attributeString appendFormat:@" %@=\"%@\"", [[key description] XMLEncodedString], [[attributes[key] description] XMLEncodedString]];

}

NSString *innerXML = [node innerXML];

if ([innerXML length])

{

return [NSString stringWithFormat:@"<%1$@%2$@>%3$@</%1$@>", nodeName, attributeString, innerXML];

}

else

{

return [NSString stringWithFormat:@"<%@%@/>", nodeName, attributeString];

}

}

else

{

return [NSString stringWithFormat:@"<%1$@>%2$@</%1$@>", nodeName, [[node description] XMLEncodedString]];

}

}

- (void)endText

{

if (_trimWhiteSpace)

{

_text = [[_text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];

}

if ([_text length])

{

NSMutableDictionary *top = [_stack lastObject];

id existing = top[XMLDictionaryTextKey];

if ([existing isKindOfClass:[NSArray class]])

{

[existing addObject:_text];

}

else if (existing)

{

top[XMLDictionaryTextKey] = [@[existing, _text] mutableCopy];

}

else

{

top[XMLDictionaryTextKey] = _text;

}

}

_text = nil;

}

- (void)addText:(NSString *)text

{

if (!_text)

{

_text = [NSMutableString stringWithString:text];

}

else

{

[_text appendString:text];

}

}

- (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict

{

[self endText];

NSMutableDictionary *node = [NSMutableDictionary dictionary];

switch (_nodeNameMode)

{

case XMLDictionaryNodeNameModeRootOnly:

{

if (!_root)

{

node[XMLDictionaryNodeNameKey] = elementName;

}

break;

}

case XMLDictionaryNodeNameModeAlways:

{

node[XMLDictionaryNodeNameKey] = elementName;

break;

}

case XMLDictionaryNodeNameModeNever:

{

break;

}

}

if ([attributeDict count])

{

switch (_attributesMode)

{

case XMLDictionaryAttributesModePrefixed:

{

for (NSString *key in [attributeDict allKeys])

{

node[[XMLDictionaryAttributePrefix stringByAppendingString:key]] = attributeDict[key];

}

break;

}

case XMLDictionaryAttributesModeDictionary:

{

node[XMLDictionaryAttributesKey] = attributeDict;

break;

}

case XMLDictionaryAttributesModeUnprefixed:

{

[node addEntriesFromDictionary:attributeDict];

break;

}

case XMLDictionaryAttributesModeDiscard:

{

break;

}

}

}

if (!_root)

{

_root = node;

_stack = [NSMutableArray arrayWithObject:node];

if (_wrapRootNode)

{

_root = [NSMutableDictionary dictionaryWithObject:_root forKey:elementName];

[_stack insertObject:_root atIndex:0];

}

}

else

{

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 if (_alwaysUseArrays)

{

top[elementName] = [NSMutableArray arrayWithObject:node];

}

else

{

top[elementName] = node;

}

[_stack addObject:node];

}

}

- (NSString *)nameForNode:(NSDictionary *)node inDictionary:(NSDictionary *)dict

{

if (node.nodeName)

{

return node.nodeName;

}

else

{

for (NSString *name in dict)

{

id object = dict[name];

if (object == node)

{

return name;

}

else if ([object isKindOfClass:[NSArray class]] && [object containsObject:node])

{

return name;

}

}

}

return nil;

}

- (void)parser:(__unused NSXMLParser *)parser didEndElement:(__unused NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName

{

[self endText];

NSMutableDictionary *top = [_stack lastObject];

[_stack removeLastObject];

if (!top.attributes && !top.childNodes && !top.comments)

{

NSMutableDictionary *newTop = [_stack lastObject];

NSString *nodeName = [self nameForNode:top inDictionary:newTop];

if (nodeName)

{

id parentNode = newTop[nodeName];

if (top.innerText && _collapseTextNodes)

{

if ([parentNode isKindOfClass:[NSArray class]])

{

parentNode[[(NSArray *)parentNode count] - 1] = top.innerText;

}

else

{

newTop[nodeName] = top.innerText;

}

}

else if (!top.innerText && _stripEmptyNodes)

{

if ([parentNode isKindOfClass:[NSArray class]])

{

[parentNode removeLastObject];

}

else

{

[newTop removeObjectForKey:nodeName];

}

}

else if (!top.innerText && !_collapseTextNodes && !_stripEmptyNodes)

{

top[XMLDictionaryTextKey] = @"";

}

}

}

}

- (void)parser:(__unused NSXMLParser *)parser foundCharacters:(NSString *)string

{

[self addText:string];

}

- (void)parser:(__unused NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock

{

[self addText:[[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]];

}

- (void)parser:(__unused NSXMLParser *)parser foundComment:(NSString *)comment

{

if (_preserveComments)

{

NSMutableDictionary *top = [_stack lastObject];

NSMutableArray *comments = top[XMLDictionaryCommentsKey];

if (!comments)

{

comments = [@[comment] mutableCopy];

top[XMLDictionaryCommentsKey] = comments;

}

else

{

[comments addObject:comment];

}

}

}

@end

@implementation NSDictionary(XMLDictionary)

+ (NSDictionary *)dictionaryWithXMLParser:(NSXMLParser *)parser

{

return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithParser:parser];

}

+ (NSDictionary *)dictionaryWithXMLData:(NSData *)data

{

return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithData:data];

}

+ (NSDictionary *)dictionaryWithXMLString:(NSString *)string

{

return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithString:string];

}

+ (NSDictionary *)dictionaryWithXMLFile:(NSString *)path

{

return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithFile:path];

}

- (NSDictionary *)attributes

{

NSDictionary *attributes = self[XMLDictionaryAttributesKey];

if (attributes)

{

return [attributes count]? attributes: nil;

}

else

{

NSMutableDictionary *filteredDict = [NSMutableDictionary dictionaryWithDictionary:self];

[filteredDict removeObjectsForKeys:@[XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]];

for (NSString *key in [filteredDict allKeys])

{

[filteredDict removeObjectForKey:key];

if ([key hasPrefix:XMLDictionaryAttributePrefix])

{

filteredDict[[key substringFromIndex:[XMLDictionaryAttributePrefix length]]] = self[key];

}

}

return [filteredDict count]? filteredDict: nil;

}

return nil;

}

- (NSDictionary *)childNodes

{

NSMutableDictionary *filteredDict = [self mutableCopy];

[filteredDict removeObjectsForKeys:@[XMLDictionaryAttributesKey, XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]];

for (NSString *key in [filteredDict allKeys])

{

if ([key hasPrefix:XMLDictionaryAttributePrefix])

{

[filteredDict removeObjectForKey:key];

}

}

return [filteredDict count]? filteredDict: nil;

}

- (NSArray *)comments

{

return self[XMLDictionaryCommentsKey];

}

- (NSString *)nodeName

{

return self[XMLDictionaryNodeNameKey];

}

- (id)innerText

{

id text = self[XMLDictionaryTextKey];

if ([text isKindOfClass:[NSArray class]])

{

return [text componentsJoinedByString:@"\n"];

}

else

{

return text;

}

}

- (NSString *)innerXML

{

NSMutableArray *nodes = [NSMutableArray array];

for (NSString *comment in [self comments])

{

[nodes addObject:[NSString stringWithFormat:@"<!--%@-->", [comment XMLEncodedString]]];

}

NSDictionary *childNodes = [self childNodes];

for (NSString *key in childNodes)

{

[nodes addObject:[XMLDictionaryParser XMLStringForNode:childNodes[key] withNodeName:key]];

}

NSString *text = [self innerText];

if (text)

{

[nodes addObject:[text XMLEncodedString]];

}

return [nodes componentsJoinedByString:@"\n"];

}

- (NSString *)XMLString

{

if ([self count] == 1 && ![self nodeName])

{

//ignore outermost dictionary

return [self innerXML];

}

else

{

return [XMLDictionaryParser XMLStringForNode:self withNodeName:[self nodeName] ?: @"root"];

}

}

- (NSArray *)arrayValueForKeyPath:(NSString *)keyPath

{

id value = [self valueForKeyPath:keyPath];

if (value && ![value isKindOfClass:[NSArray class]])

{

return @[value];

}

return value;

}

- (NSString *)stringValueForKeyPath:(NSString *)keyPath

{

id value = [self valueForKeyPath:keyPath];

if ([value isKindOfClass:[NSArray class]])

{

value = [(NSArray *)value count]? value[0]: nil;

}

if ([value isKindOfClass:[NSDictionary class]])

{

return [(NSDictionary *)value innerText];

}

return value;

}

- (NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath

{

id value = [self valueForKeyPath:keyPath];

if ([value isKindOfClass:[NSArray class]])

{

value = [(NSArray *)value count]? value[0]: nil;

}

if ([value isKindOfClass:[NSString class]])

{

return @{XMLDictionaryTextKey: value};

}

return value;

}

@end

@implementation NSString (XMLDictionary)

- (NSString *)XMLEncodedString

{

return [[[[[self stringByReplacingOccurrencesOfString:@"&" withString:@"&"]

stringByReplacingOccurrencesOfString:@"<" withString:@"<"]

stringByReplacingOccurrencesOfString:@">" withString:@">"]

stringByReplacingOccurrencesOfString:@"\"" withString:@"""]

stringByReplacingOccurrencesOfString:@"\'" withString:@"'"];

}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: