NamedNodeMap.m 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. //
  2. // NamedNodeMap.m
  3. // SVGKit
  4. //
  5. // Created by adam on 22/05/2012.
  6. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
  7. //
  8. #import "NamedNodeMap.h"
  9. #import "NamedNodeMap_Iterable.h"
  10. @interface NamedNodeMap()
  11. @property(nonatomic,strong) NSMutableDictionary* internalDictionary;
  12. @property(nonatomic,strong) NSMutableDictionary* internalDictionaryOfNamespaces;
  13. @end
  14. @implementation NamedNodeMap
  15. @synthesize internalDictionary;
  16. @synthesize internalDictionaryOfNamespaces;
  17. - (id)init {
  18. self = [super init];
  19. if (self) {
  20. self.internalDictionary = [NSMutableDictionary dictionary];
  21. self.internalDictionaryOfNamespaces = [NSMutableDictionary dictionary];
  22. }
  23. return self;
  24. }
  25. -(Node*) getNamedItem:(NSString*) name
  26. {
  27. Node* simpleResult = [self.internalDictionary objectForKey:name];
  28. if( simpleResult == nil )
  29. {
  30. /**
  31. Check the namespaces in turn, to see if we can find this node in one of them
  32. NB: according to spec, this behaviour is:
  33. "The result depends on the implementation"
  34. I've chosen to implement it the most user-friendly way possible. It is NOT the best
  35. solution IMHO - the spec authors should have defined the outcome!
  36. */
  37. for( NSString* key in self.internalDictionaryOfNamespaces )
  38. {
  39. simpleResult = [self getNamedItemNS:key localName:name];
  40. if( simpleResult != nil )
  41. break;
  42. }
  43. }
  44. return simpleResult;
  45. }
  46. -(Node*) setNamedItem:(Node*) arg
  47. {
  48. 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...." );
  49. Node* oldNode = [self.internalDictionary objectForKey:arg.localName];
  50. [self.internalDictionary setObject:arg forKey:arg.localName];
  51. return oldNode;
  52. }
  53. -(Node*) removeNamedItem:(NSString*) name
  54. {
  55. 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...." );
  56. Node* oldNode = [self.internalDictionary objectForKey:name];
  57. [self.internalDictionary removeObjectForKey:name];
  58. return oldNode;
  59. }
  60. -(unsigned long)length
  61. {
  62. NSUInteger count = [self.internalDictionary count];
  63. for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
  64. {
  65. count += [namespaceDict count];
  66. }
  67. return count;
  68. }
  69. -(Node*) item:(unsigned long) index
  70. {
  71. 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");
  72. if( index < [self.internalDictionary count] )
  73. return [self.internalDictionary.allValues objectAtIndex:index];
  74. else
  75. {
  76. index -= self.internalDictionary.count;
  77. for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
  78. {
  79. if( index < [namespaceDict count] )
  80. return [namespaceDict.allValues objectAtIndex:index];
  81. else
  82. index -= [namespaceDict count];
  83. }
  84. }
  85. return nil;
  86. }
  87. // Introduced in DOM Level 2:
  88. -(Node*) getNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
  89. {
  90. NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
  91. return [namespaceDict objectForKey:localName];
  92. }
  93. // Introduced in DOM Level 2:
  94. -(Node*) setNamedItemNS:(Node*) arg
  95. {
  96. return [self setNamedItemNS:arg inNodeNamespace:nil];
  97. }
  98. // Introduced in DOM Level 2:
  99. -(Node*) removeNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
  100. {
  101. NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
  102. Node* oldNode = [namespaceDict objectForKey:localName];
  103. [namespaceDict removeObjectForKey:localName];
  104. return oldNode;
  105. }
  106. #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)
  107. -(Node*) setNamedItemNS:(Node*) arg inNodeNamespace:(NSString*) nodesNamespace
  108. {
  109. NSString* effectiveNamespace = arg.namespaceURI != nil ? arg.namespaceURI : nodesNamespace;
  110. if( effectiveNamespace == nil )
  111. {
  112. return [self setNamedItem:arg]; // this should never happen, but there's a lot of malformed SVG files out in the wild
  113. }
  114. NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:effectiveNamespace];
  115. if( namespaceDict == nil )
  116. {
  117. namespaceDict = [NSMutableDictionary dictionary];
  118. [self.internalDictionaryOfNamespaces setObject:namespaceDict forKey:effectiveNamespace];
  119. }
  120. Node* oldNode = [namespaceDict objectForKey:arg.localName];
  121. [namespaceDict setObject:arg forKey:arg.localName];
  122. return oldNode;
  123. }
  124. #pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
  125. -(NSString *)description
  126. {
  127. /** test (and output) both the "DOM 1" and "DOM 2" dictionaries, if they're non-empty */
  128. NSString* dom1 = self.internalDictionary.count > 0 ? [NSString stringWithFormat:@"DOM-v1(%@)", self.internalDictionary] : nil;
  129. NSString* dom2 = self.internalDictionaryOfNamespaces.count > 0 ? [NSString stringWithFormat:@"DOM-v2(%@)", self.internalDictionaryOfNamespaces] : nil;
  130. return [NSString stringWithFormat:@"NamedNodeMap: %@%@%@", dom1, dom1 != nil && dom2 != nil ? @"\n" : @"", dom2 ];
  131. }
  132. #pragma mark - Implementation of category: NamedNodeMap_Iterable
  133. -(NSArray*) allNodesUnsortedDOM1
  134. {
  135. /** Using DOM1 - no namespace support */
  136. return self.internalDictionary.allValues;
  137. }
  138. -(NSDictionary*) allNodesUnsortedDOM2
  139. {
  140. /** Using DOM2 - every item has a namespace*/
  141. return self.internalDictionaryOfNamespaces;
  142. }
  143. #pragma mark - Needed to implement XML DOM effectively: ability to shallow-Clone an instance
  144. -(id)copyWithZone:(NSZone *)zone
  145. {
  146. NamedNodeMap* clone = [[NamedNodeMap allocWithZone:zone] init];
  147. clone.internalDictionary = [self.internalDictionary copyWithZone:zone];
  148. clone.internalDictionaryOfNamespaces = [self.internalDictionaryOfNamespaces copyWithZone:zone];
  149. return clone;
  150. }
  151. @end