NSXMLElement+XMPP.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #import "NSXMLElement+XMPP.h"
  2. #import "NSNumber+XMPP.h"
  3. #if ! __has_feature(objc_arc)
  4. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  5. #endif
  6. @implementation NSXMLElement (XMPP)
  7. /**
  8. * Convenience methods for Creating elements.
  9. **/
  10. + (NSXMLElement *)elementWithName:(NSString *)name numberValue:(NSNumber *)number
  11. {
  12. return [self elementWithName:name stringValue:[number stringValue]];
  13. }
  14. - (id)initWithName:(NSString *)name numberValue:(NSNumber *)number
  15. {
  16. return [self initWithName:name stringValue:[number stringValue]];
  17. }
  18. + (NSXMLElement *)elementWithName:(NSString *)name objectValue:(id)objectValue
  19. {
  20. if([objectValue isKindOfClass:[NSString class]])
  21. {
  22. return [self elementWithName:name stringValue:objectValue];
  23. }
  24. else if([objectValue isKindOfClass:[NSNumber class]])
  25. {
  26. return [self elementWithName:name numberValue:objectValue];
  27. }
  28. else if([objectValue respondsToSelector:@selector(stringValue)])
  29. {
  30. return [self elementWithName:name stringValue:[objectValue stringValue]];
  31. }
  32. else
  33. {
  34. return [self elementWithName:name];
  35. }
  36. }
  37. - (id)initWithName:(NSString *)name objectValue:(id)objectValue
  38. {
  39. if([objectValue isKindOfClass:[NSString class]])
  40. {
  41. return [self initWithName:name stringValue:objectValue];
  42. }
  43. else if([objectValue isKindOfClass:[NSNumber class]])
  44. {
  45. return [self initWithName:name numberValue:objectValue];
  46. }
  47. else if([objectValue respondsToSelector:@selector(stringValue)])
  48. {
  49. return [self initWithName:name stringValue:[objectValue stringValue]];
  50. }
  51. else
  52. {
  53. return [self initWithName:name];
  54. }
  55. }
  56. /**
  57. * Quick method to create an element
  58. **/
  59. + (NSXMLElement *)elementWithName:(NSString *)name xmlns:(NSString *)ns
  60. {
  61. NSXMLElement *element = [NSXMLElement elementWithName:name];
  62. [element setXmlns:ns];
  63. return element;
  64. }
  65. - (id)initWithName:(NSString *)name xmlns:(NSString *)ns
  66. {
  67. if ((self = [self initWithName:name]))
  68. {
  69. [self setXmlns:ns];
  70. }
  71. return self;
  72. }
  73. - (NSArray *)elementsForXmlns:(NSString *)ns
  74. {
  75. NSMutableArray *elements = [NSMutableArray array];
  76. for (NSXMLNode *node in [self children])
  77. {
  78. if ([node isKindOfClass:[NSXMLElement class]])
  79. {
  80. NSXMLElement *element = (NSXMLElement *)node;
  81. if ([[element xmlns] isEqual:ns])
  82. {
  83. [elements addObject:element];
  84. }
  85. }
  86. }
  87. return elements;
  88. }
  89. - (NSArray *)elementsForXmlnsPrefix:(NSString *)nsPrefix
  90. {
  91. NSMutableArray *elements = [NSMutableArray array];
  92. for (NSXMLNode *node in [self children])
  93. {
  94. if ([node isKindOfClass:[NSXMLElement class]])
  95. {
  96. NSXMLElement *element = (NSXMLElement *)node;
  97. if ([[element xmlns] hasPrefix:nsPrefix])
  98. {
  99. [elements addObject:element];
  100. }
  101. }
  102. }
  103. return elements;
  104. }
  105. /**
  106. * This method returns the first child element for the given name (as an NSXMLElement).
  107. * If no child elements exist for the given name, nil is returned.
  108. **/
  109. - (NSXMLElement *)elementForName:(NSString *)name
  110. {
  111. NSArray *elements = [self elementsForName:name];
  112. if ([elements count] > 0)
  113. {
  114. return elements[0];
  115. }
  116. else
  117. {
  118. // There is a bug in the NSXMLElement elementsForName: method.
  119. // Consider the following XML fragment:
  120. //
  121. // <query xmlns="jabber:iq:private">
  122. // <x xmlns="some:other:namespace"></x>
  123. // </query>
  124. //
  125. // Calling [query elementsForName:@"x"] results in an empty array!
  126. //
  127. // However, it will work properly if you use the following:
  128. // [query elementsForLocalName:@"x" URI:@"some:other:namespace"]
  129. //
  130. // The trouble with this is that we may not always know the xmlns in advance,
  131. // so in this particular case there is no way to access the element without looping through the children.
  132. //
  133. // This bug was submitted to apple on June 1st, 2007 and was classified as "serious".
  134. //
  135. // --!!-- This bug does NOT exist in DDXML --!!--
  136. return nil;
  137. }
  138. }
  139. /**
  140. * This method returns the first child element for the given name and given xmlns (as an NSXMLElement).
  141. * If no child elements exist for the given name and given xmlns, nil is returned.
  142. **/
  143. - (NSXMLElement *)elementForName:(NSString *)name xmlns:(NSString *)xmlns
  144. {
  145. NSArray *elements = [self elementsForLocalName:name URI:xmlns];
  146. if ([elements count] > 0)
  147. {
  148. return elements[0];
  149. }
  150. else
  151. {
  152. return nil;
  153. }
  154. }
  155. - (NSXMLElement *)elementForName:(NSString *)name xmlnsPrefix:(NSString *)xmlnsPrefix{
  156. NSXMLElement *result = nil;
  157. for (NSXMLNode *node in [self children])
  158. {
  159. if ([node isKindOfClass:[NSXMLElement class]])
  160. {
  161. NSXMLElement *element = (NSXMLElement *)node;
  162. if ([[element name] isEqualToString:name] && [[element xmlns] hasPrefix:xmlnsPrefix])
  163. {
  164. result = element;
  165. break;
  166. }
  167. }
  168. }
  169. return result;
  170. }
  171. /**
  172. * This method removes the first child element for the given name.
  173. * If no child elements exist for the given name, this method does nothing.
  174. **/
  175. - (void)removeElementForName:(NSString *)name
  176. {
  177. NSXMLElement *element = [self elementForName:name];
  178. if(element)
  179. {
  180. [self removeChildAtIndex:[[self children] indexOfObject:element]];
  181. }
  182. }
  183. /**
  184. * This method removes the all child elements for the given name.
  185. * If no child elements exist for the given name, this method does nothing.
  186. **/
  187. - (void)removeElementsForName:(NSString *)name
  188. {
  189. NSArray *elements = [self elementsForName:name];
  190. for(NSXMLElement *element in elements)
  191. {
  192. [self removeChildAtIndex:[[self children] indexOfObject:element]];
  193. }
  194. }
  195. /**
  196. * This method removes the first child element for the given name and given xmlns.
  197. * If no child elements exist for the given name and given xmlns, this method does nothing.
  198. **/
  199. - (void)removeElementForName:(NSString *)name xmlns:(NSString *)xmlns
  200. {
  201. NSXMLElement *element = [self elementForName:name xmlns:xmlns];
  202. if(element)
  203. {
  204. [self removeChildAtIndex:[[self children] indexOfObject:element]];
  205. }
  206. }
  207. /**
  208. * This method removes the first child element for the given name and given xmlns prefix.
  209. * If no child elements exist for the given name and given xmlns prefix, this method does nothing.
  210. **/
  211. - (void)removeElementForName:(NSString *)name xmlnsPrefix:(NSString *)xmlnsPrefix
  212. {
  213. NSXMLElement *element = [self elementForName:name xmlnsPrefix:xmlnsPrefix];
  214. if(element)
  215. {
  216. [self removeChildAtIndex:[[self children] indexOfObject:element]];
  217. }
  218. }
  219. /**
  220. * Returns the common xmlns "attribute", which is only accessible via the namespace methods.
  221. * The xmlns value is often used in jabber elements.
  222. **/
  223. - (NSString *)xmlns
  224. {
  225. return [[self namespaceForPrefix:@""] stringValue];
  226. }
  227. - (void)setXmlns:(NSString *)ns
  228. {
  229. // If we use setURI: then the xmlns won't be displayed in the XMLString.
  230. // Adding the namespace this way works properly.
  231. [self addNamespace:[NSXMLNode namespaceWithName:@"" stringValue:ns]];
  232. }
  233. /**
  234. * Shortcut to get a pretty (formatted) string representation of the element.
  235. **/
  236. - (NSString *)prettyXMLString
  237. {
  238. return [self XMLStringWithOptions:(NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement)];
  239. }
  240. /**
  241. * Shortcut to get a compact string representation of the element.
  242. **/
  243. - (NSString *)compactXMLString
  244. {
  245. return [self XMLStringWithOptions:NSXMLNodeCompactEmptyElement];
  246. }
  247. /**
  248. * Shortcut to avoid having to use NSXMLNode everytime
  249. **/
  250. - (void)addAttributeWithName:(NSString *)name intValue:(int)intValue
  251. {
  252. [self addAttributeWithName:name numberValue:@(intValue)];
  253. }
  254. - (void)addAttributeWithName:(NSString *)name boolValue:(BOOL)boolValue
  255. {
  256. [self addAttributeWithName:name numberValue:@(boolValue)];
  257. }
  258. - (void)addAttributeWithName:(NSString *)name floatValue:(float)floatValue
  259. {
  260. [self addAttributeWithName:name numberValue:@(floatValue)];
  261. }
  262. - (void)addAttributeWithName:(NSString *)name doubleValue:(double)doubleValue
  263. {
  264. [self addAttributeWithName:name numberValue:@(doubleValue)];
  265. }
  266. - (void)addAttributeWithName:(NSString *)name integerValue:(NSInteger)integerValue
  267. {
  268. [self addAttributeWithName:name numberValue:@(integerValue)];
  269. }
  270. - (void)addAttributeWithName:(NSString *)name unsignedIntegerValue:(NSUInteger)unsignedIntegerValue
  271. {
  272. [self addAttributeWithName:name numberValue:@(unsignedIntegerValue)];
  273. }
  274. - (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string
  275. {
  276. [self addAttribute:[NSXMLNode attributeWithName:name stringValue:string]];
  277. }
  278. - (void)addAttributeWithName:(NSString *)name numberValue:(NSNumber *)number
  279. {
  280. [self addAttributeWithName:name stringValue:[number stringValue]];
  281. }
  282. - (void)addAttributeWithName:(NSString *)name objectValue:(id)objectValue
  283. {
  284. if([objectValue isKindOfClass:[NSString class]])
  285. {
  286. [self addAttributeWithName:name stringValue:objectValue];
  287. }
  288. else if([objectValue isKindOfClass:[NSNumber class]])
  289. {
  290. [self addAttributeWithName:name numberValue:objectValue];
  291. }
  292. else if([objectValue respondsToSelector:@selector(stringValue)])
  293. {
  294. [self addAttributeWithName:name stringValue:[objectValue stringValue]];
  295. }
  296. }
  297. /**
  298. * The following methods return the corresponding value of the attribute with the given name.
  299. **/
  300. - (int)attributeIntValueForName:(NSString *)name
  301. {
  302. return [[self attributeStringValueForName:name] intValue];
  303. }
  304. - (BOOL)attributeBoolValueForName:(NSString *)name
  305. {
  306. NSString *attributeStringValueForName = [self attributeStringValueForName:name];
  307. BOOL result = NO;
  308. // An XML boolean datatype can have the following legal literals: true, false, 1, 0
  309. if ([attributeStringValueForName isEqualToString:@"true"] || [attributeStringValueForName isEqualToString:@"1"])
  310. {
  311. result = YES;
  312. }
  313. else if([attributeStringValueForName isEqualToString:@"false"] || [attributeStringValueForName isEqualToString:@"0"])
  314. {
  315. result = NO;
  316. }
  317. else
  318. {
  319. result = [attributeStringValueForName boolValue];
  320. }
  321. return result;
  322. }
  323. - (float)attributeFloatValueForName:(NSString *)name
  324. {
  325. return [[self attributeStringValueForName:name] floatValue];
  326. }
  327. - (double)attributeDoubleValueForName:(NSString *)name
  328. {
  329. return [[self attributeStringValueForName:name] doubleValue];
  330. }
  331. - (int32_t)attributeInt32ValueForName:(NSString *)name
  332. {
  333. int32_t result = 0;
  334. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoInt32:&result];
  335. return result;
  336. }
  337. - (uint32_t)attributeUInt32ValueForName:(NSString *)name
  338. {
  339. uint32_t result = 0;
  340. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoUInt32:&result];
  341. return result;
  342. }
  343. - (int64_t)attributeInt64ValueForName:(NSString *)name
  344. {
  345. int64_t result;
  346. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoInt64:&result];
  347. return result;
  348. }
  349. - (uint64_t)attributeUInt64ValueForName:(NSString *)name
  350. {
  351. uint64_t result;
  352. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoUInt64:&result];
  353. return result;
  354. }
  355. - (NSInteger)attributeIntegerValueForName:(NSString *)name
  356. {
  357. NSInteger result;
  358. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoNSInteger:&result];
  359. return result;
  360. }
  361. - (NSUInteger)attributeUnsignedIntegerValueForName:(NSString *)name
  362. {
  363. NSUInteger result = 0;
  364. [NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoNSUInteger:&result];
  365. return result;
  366. }
  367. - (NSString *)attributeStringValueForName:(NSString *)name
  368. {
  369. return [[self attributeForName:name] stringValue];
  370. }
  371. - (NSNumber *)attributeNumberIntValueForName:(NSString *)name
  372. {
  373. return @([self attributeIntValueForName:name]);
  374. }
  375. - (NSNumber *)attributeNumberBoolValueForName:(NSString *)name
  376. {
  377. return @([self attributeBoolValueForName:name]);
  378. }
  379. - (NSNumber *)attributeNumberFloatValueForName:(NSString *)name
  380. {
  381. return @([self attributeFloatValueForName:name]);
  382. }
  383. - (NSNumber *)attributeNumberDoubleValueForName:(NSString *)name
  384. {
  385. return @([self attributeDoubleValueForName:name]);
  386. }
  387. - (NSNumber *)attributeNumberInt32ValueForName:(NSString *)name
  388. {
  389. return @([self attributeInt32ValueForName:name]);
  390. }
  391. - (NSNumber *)attributeNumberUInt32ValueForName:(NSString *)name
  392. {
  393. return @([self attributeUInt32ValueForName:name]);
  394. }
  395. - (NSNumber *)attributeNumberInt64ValueForName:(NSString *)name
  396. {
  397. return @([self attributeInt64ValueForName:name]);
  398. }
  399. - (NSNumber *)attributeNumberUInt64ValueForName:(NSString *)name
  400. {
  401. return @([self attributeUInt64ValueForName:name]);
  402. }
  403. - (NSNumber *)attributeNumberIntegerValueForName:(NSString *)name
  404. {
  405. return @([self attributeIntegerValueForName:name]);
  406. }
  407. - (NSNumber *)attributeNumberUnsignedIntegerValueForName:(NSString *)name
  408. {
  409. return @([self attributeUnsignedIntegerValueForName:name]);
  410. }
  411. /**
  412. * The following methods return the corresponding value of the attribute with the given name.
  413. * If the attribute does not exist, the given defaultValue is returned.
  414. **/
  415. - (int)attributeIntValueForName:(NSString *)name withDefaultValue:(int)defaultValue
  416. {
  417. NSXMLNode *attr = [self attributeForName:name];
  418. return (attr) ? [[attr stringValue] intValue] : defaultValue;
  419. }
  420. - (BOOL)attributeBoolValueForName:(NSString *)name withDefaultValue:(BOOL)defaultValue
  421. {
  422. NSXMLNode *attr = [self attributeForName:name];
  423. return (attr) ? [[attr stringValue] boolValue] : defaultValue;
  424. }
  425. - (float)attributeFloatValueForName:(NSString *)name withDefaultValue:(float)defaultValue
  426. {
  427. NSXMLNode *attr = [self attributeForName:name];
  428. return (attr) ? [[attr stringValue] floatValue] : defaultValue;
  429. }
  430. - (double)attributeDoubleValueForName:(NSString *)name withDefaultValue:(double)defaultValue
  431. {
  432. NSXMLNode *attr = [self attributeForName:name];
  433. return (attr) ? [[attr stringValue] doubleValue] : defaultValue;
  434. }
  435. - (int32_t)attributeInt32ValueForName:(NSString *)name withDefaultValue:(int32_t)defaultValue
  436. {
  437. int32_t result = 0;
  438. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoInt32:&result])
  439. return result;
  440. else
  441. return defaultValue;
  442. }
  443. - (uint32_t)attributeUInt32ValueForName:(NSString *)name withDefaultValue:(uint32_t)defaultValue
  444. {
  445. uint32_t result = 0;
  446. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoUInt32:&result])
  447. return result;
  448. else
  449. return defaultValue;
  450. }
  451. - (int64_t)attributeInt64ValueForName:(NSString *)name withDefaultValue:(int64_t)defaultValue
  452. {
  453. int64_t result = 0;
  454. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoInt64:&result])
  455. return result;
  456. else
  457. return defaultValue;
  458. }
  459. - (uint64_t)attributeUInt64ValueForName:(NSString *)name withDefaultValue:(uint64_t)defaultValue
  460. {
  461. uint64_t result = 0;
  462. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoUInt64:&result])
  463. return result;
  464. else
  465. return defaultValue;
  466. }
  467. - (NSInteger)attributeIntegerValueForName:(NSString *)name withDefaultValue:(NSInteger)defaultValue
  468. {
  469. NSInteger result = 0;
  470. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoNSInteger:&result])
  471. return result;
  472. else
  473. return defaultValue;
  474. }
  475. - (NSUInteger)attributeUnsignedIntegerValueForName:(NSString *)name withDefaultValue:(NSUInteger)defaultValue
  476. {
  477. NSUInteger result = 0;
  478. if ([NSNumber xmpp_parseString:[self attributeStringValueForName:name] intoNSUInteger:&result])
  479. return result;
  480. else
  481. return defaultValue;
  482. }
  483. - (NSString *)attributeStringValueForName:(NSString *)name withDefaultValue:(NSString *)defaultValue
  484. {
  485. NSXMLNode *attr = [self attributeForName:name];
  486. return (attr) ? [attr stringValue] : defaultValue;
  487. }
  488. - (NSNumber *)attributeNumberIntValueForName:(NSString *)name withDefaultValue:(int)defaultValue
  489. {
  490. return @([self attributeIntValueForName:name withDefaultValue:defaultValue]);
  491. }
  492. - (NSNumber *)attributeNumberBoolValueForName:(NSString *)name withDefaultValue:(BOOL)defaultValue
  493. {
  494. return @([self attributeBoolValueForName:name withDefaultValue:defaultValue]);
  495. }
  496. /**
  497. * Returns all the attributes in a dictionary.
  498. **/
  499. - (NSMutableDictionary *)attributesAsDictionary
  500. {
  501. NSArray *attributes = [self attributes];
  502. NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:[attributes count]];
  503. NSUInteger i;
  504. for(i = 0; i < [attributes count]; i++)
  505. {
  506. NSXMLNode *node = attributes[i];
  507. result[[node name]] = [node stringValue];
  508. }
  509. return result;
  510. }
  511. /**
  512. * The following methods return the corresponding value of the node.
  513. **/
  514. - (int)stringValueAsInt
  515. {
  516. return [[self stringValue] intValue];
  517. }
  518. - (BOOL)stringValueAsBool
  519. {
  520. return [[self stringValue] boolValue];
  521. }
  522. - (float)stringValueAsFloat
  523. {
  524. return [[self stringValue] floatValue];
  525. }
  526. - (double)stringValueAsDouble
  527. {
  528. return [[self stringValue] doubleValue];
  529. }
  530. - (int32_t)stringValueAsInt32
  531. {
  532. int32_t result;
  533. if ([NSNumber xmpp_parseString:[self stringValue] intoInt32:&result])
  534. return result;
  535. else
  536. return 0;
  537. }
  538. - (uint32_t)stringValueAsUInt32
  539. {
  540. uint32_t result;
  541. if ([NSNumber xmpp_parseString:[self stringValue] intoUInt32:&result])
  542. return result;
  543. else
  544. return 0;
  545. }
  546. - (int64_t)stringValueAsInt64
  547. {
  548. int64_t result = 0;
  549. if ([NSNumber xmpp_parseString:[self stringValue] intoInt64:&result])
  550. return result;
  551. else
  552. return 0;
  553. }
  554. - (uint64_t)stringValueAsUInt64
  555. {
  556. uint64_t result = 0;
  557. if ([NSNumber xmpp_parseString:[self stringValue] intoUInt64:&result])
  558. return result;
  559. else
  560. return 0;
  561. }
  562. - (NSInteger)stringValueAsNSInteger
  563. {
  564. NSInteger result = 0;
  565. if ([NSNumber xmpp_parseString:[self stringValue] intoNSInteger:&result])
  566. return result;
  567. else
  568. return 0;
  569. }
  570. - (NSUInteger)stringValueAsNSUInteger
  571. {
  572. NSUInteger result = 0;
  573. if ([NSNumber xmpp_parseString:[self stringValue] intoNSUInteger:&result])
  574. return result;
  575. else
  576. return 0;
  577. }
  578. /**
  579. * Shortcut to avoid having to use NSXMLNode everytime
  580. **/
  581. - (void)addNamespaceWithPrefix:(NSString *)prefix stringValue:(NSString *)string
  582. {
  583. [self addNamespace:[NSXMLNode namespaceWithName:prefix stringValue:string]];
  584. }
  585. /**
  586. * Just to make your code look a little bit cleaner.
  587. **/
  588. - (NSString *)namespaceStringValueForPrefix:(NSString *)prefix
  589. {
  590. return [[self namespaceForPrefix:prefix] stringValue];
  591. }
  592. - (NSString *)namespaceStringValueForPrefix:(NSString *)prefix withDefaultValue:(NSString *)defaultValue
  593. {
  594. NSXMLNode *namespace = [self namespaceForPrefix:prefix];
  595. return (namespace) ? [namespace stringValue] : defaultValue;
  596. }
  597. @end