#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
//
// 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:[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[[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 = [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 = [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
转载于:https://www.cnblogs.com/ningmengcao-ios/p/5728001.html