123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- //
- // NamedNodeMap.m
- // SVGKit
- //
- // Created by adam on 22/05/2012.
- // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
- //
- #import "NamedNodeMap.h"
- #import "NamedNodeMap_Iterable.h"
- @interface NamedNodeMap()
- @property(nonatomic,strong) NSMutableDictionary* internalDictionary;
- @property(nonatomic,strong) NSMutableDictionary* internalDictionaryOfNamespaces;
- @end
- @implementation NamedNodeMap
- @synthesize internalDictionary;
- @synthesize internalDictionaryOfNamespaces;
- - (id)init {
- self = [super init];
- if (self) {
- self.internalDictionary = [NSMutableDictionary dictionary];
- self.internalDictionaryOfNamespaces = [NSMutableDictionary dictionary];
- }
- return self;
- }
- -(Node*) getNamedItem:(NSString*) name
- {
- Node* simpleResult = [self.internalDictionary objectForKey:name];
-
- if( simpleResult == nil )
- {
- /**
- Check the namespaces in turn, to see if we can find this node in one of them
-
- NB: according to spec, this behaviour is:
-
- "The result depends on the implementation"
-
- I've chosen to implement it the most user-friendly way possible. It is NOT the best
- solution IMHO - the spec authors should have defined the outcome!
- */
-
- for( NSString* key in self.internalDictionaryOfNamespaces )
- {
- simpleResult = [self getNamedItemNS:key localName:name];
- if( simpleResult != nil )
- break;
- }
- }
-
- return simpleResult;
- }
- -(Node*) setNamedItem:(Node*) arg
- {
- NSAssert( [[self.internalDictionaryOfNamespaces allKeys] count] < 1, @"WARNING: you are using namespaced attributes in parallel with non-namespaced. According to the DOM Spec, this leads to UNDEFINED behaviour. This is insane - you do NOT want to be doing this! Crashing deliberately...." );
-
- Node* oldNode = [self.internalDictionary objectForKey:arg.localName];
-
- [self.internalDictionary setObject:arg forKey:arg.localName];
-
- return oldNode;
- }
- -(Node*) removeNamedItem:(NSString*) name
- {
- NSAssert( [[self.internalDictionaryOfNamespaces allKeys] count] < 1, @"WARNING: you are using namespaced attributes in parallel with non-namespaced. According to the DOM Spec, this leads to UNDEFINED behaviour. This is insane - you do NOT want to be doing this! Crashing deliberately...." );
-
- Node* oldNode = [self.internalDictionary objectForKey:name];
-
- [self.internalDictionary removeObjectForKey:name];
-
- return oldNode;
- }
- -(unsigned long)length
- {
- NSUInteger count = [self.internalDictionary count];
-
- for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
- {
- count += [namespaceDict count];
- }
-
- return count;
- }
- -(Node*) item:(unsigned long) index
- {
- NSAssert(FALSE, @"This method is broken; Apple does not consistently return ordered values in dictionary.allValues. Apple DOES NOT SUPPORT ordered Maps/Hashes/Tables/Hashtables - we have to re-implement this wheel from scratch");
-
- if( index < [self.internalDictionary count] )
- return [self.internalDictionary.allValues objectAtIndex:index];
- else
- {
- index -= self.internalDictionary.count;
-
- for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
- {
- if( index < [namespaceDict count] )
- return [namespaceDict.allValues objectAtIndex:index];
- else
- index -= [namespaceDict count];
- }
- }
-
- return nil;
- }
- // Introduced in DOM Level 2:
- -(Node*) getNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
- {
- NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
-
- return [namespaceDict objectForKey:localName];
- }
- // Introduced in DOM Level 2:
- -(Node*) setNamedItemNS:(Node*) arg
- {
- return [self setNamedItemNS:arg inNodeNamespace:nil];
- }
- // Introduced in DOM Level 2:
- -(Node*) removeNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
- {
- NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
- Node* oldNode = [namespaceDict objectForKey:localName];
-
- [namespaceDict removeObjectForKey:localName];
-
- return oldNode;
- }
- #pragma mark - MISSING METHOD FROM SVG Spec, without which you cannot parse documents (don't understand how they intended you to fulfil the spec without this method)
- -(Node*) setNamedItemNS:(Node*) arg inNodeNamespace:(NSString*) nodesNamespace
- {
- NSString* effectiveNamespace = arg.namespaceURI != nil ? arg.namespaceURI : nodesNamespace;
- if( effectiveNamespace == nil )
- {
- return [self setNamedItem:arg]; // this should never happen, but there's a lot of malformed SVG files out in the wild
- }
-
- NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:effectiveNamespace];
- if( namespaceDict == nil )
- {
- namespaceDict = [NSMutableDictionary dictionary];
- [self.internalDictionaryOfNamespaces setObject:namespaceDict forKey:effectiveNamespace];
- }
- Node* oldNode = [namespaceDict objectForKey:arg.localName];
-
- [namespaceDict setObject:arg forKey:arg.localName];
-
- return oldNode;
- }
- #pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
- -(NSString *)description
- {
- /** test (and output) both the "DOM 1" and "DOM 2" dictionaries, if they're non-empty */
-
- NSString* dom1 = self.internalDictionary.count > 0 ? [NSString stringWithFormat:@"DOM-v1(%@)", self.internalDictionary] : nil;
- NSString* dom2 = self.internalDictionaryOfNamespaces.count > 0 ? [NSString stringWithFormat:@"DOM-v2(%@)", self.internalDictionaryOfNamespaces] : nil;
-
- return [NSString stringWithFormat:@"NamedNodeMap: %@%@%@", dom1, dom1 != nil && dom2 != nil ? @"\n" : @"", dom2 ];
- }
- #pragma mark - Implementation of category: NamedNodeMap_Iterable
- -(NSArray*) allNodesUnsortedDOM1
- {
- /** Using DOM1 - no namespace support */
-
- return self.internalDictionary.allValues;
- }
- -(NSDictionary*) allNodesUnsortedDOM2
- {
- /** Using DOM2 - every item has a namespace*/
-
- return self.internalDictionaryOfNamespaces;
- }
- #pragma mark - Needed to implement XML DOM effectively: ability to shallow-Clone an instance
- -(id)copyWithZone:(NSZone *)zone
- {
- NamedNodeMap* clone = [[NamedNodeMap allocWithZone:zone] init];
- clone.internalDictionary = [self.internalDictionary copyWithZone:zone];
- clone.internalDictionaryOfNamespaces = [self.internalDictionaryOfNamespaces copyWithZone:zone];
-
- return clone;
- }
- @end
|