PageRenderTime 77ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/XMPP_Demo/Vendor/KissXML/DDXMLElement.m

https://gitlab.com/praveenvelanati/ios-demo
Objective C | 801 lines | 524 code | 162 blank | 115 comment | 89 complexity | bcb1cba16f89d5c23543d8cb2e839d67 MD5 | raw file
  1. #import "DDXMLPrivate.h"
  2. #import "NSString+DDXML.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. /**
  7. * Welcome to KissXML.
  8. *
  9. * The project page has documentation if you have questions.
  10. * https://github.com/robbiehanson/KissXML
  11. *
  12. * If you're new to the project you may wish to read the "Getting Started" wiki.
  13. * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
  14. *
  15. * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
  16. * The goal is to get the exact same behavior as the NSXML classes.
  17. *
  18. * For API Reference, see Apple's excellent documentation,
  19. * either via Xcode's Mac OS X documentation, or via the web:
  20. *
  21. * https://github.com/robbiehanson/KissXML/wiki/Reference
  22. **/
  23. @implementation DDXMLElement
  24. /**
  25. * Returns a DDXML wrapper object for the given primitive node.
  26. * The given node MUST be non-NULL and of the proper type.
  27. **/
  28. + (id)nodeWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)owner
  29. {
  30. return [[DDXMLElement alloc] initWithElementPrimitive:node owner:owner];
  31. }
  32. - (id)initWithElementPrimitive:(xmlNodePtr)node owner:(DDXMLNode *)inOwner
  33. {
  34. self = [super initWithPrimitive:(xmlKindPtr)node owner:inOwner];
  35. return self;
  36. }
  37. + (id)nodeWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)owner
  38. {
  39. // Promote initializers which use proper parameter types to enable compiler to catch more mistakes
  40. NSAssert(NO, @"Use nodeWithElementPrimitive:owner:");
  41. return nil;
  42. }
  43. - (id)initWithPrimitive:(xmlKindPtr)kindPtr owner:(DDXMLNode *)inOwner
  44. {
  45. // Promote initializers which use proper parameter types to enable compiler to catch more mistakes.
  46. NSAssert(NO, @"Use initWithElementPrimitive:owner:");
  47. return nil;
  48. }
  49. - (id)initWithName:(NSString *)name
  50. {
  51. // Note: Make every guarantee that genericPtr is not null
  52. xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
  53. if (node == NULL)
  54. {
  55. return nil;
  56. }
  57. return [self initWithElementPrimitive:node owner:nil];
  58. }
  59. - (id)initWithName:(NSString *)name URI:(NSString *)URI
  60. {
  61. // Note: Make every guarantee that genericPtr is not null
  62. xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
  63. if (node == NULL)
  64. {
  65. return nil;
  66. }
  67. DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
  68. [result setURI:URI];
  69. return result;
  70. }
  71. - (id)initWithName:(NSString *)name stringValue:(NSString *)string
  72. {
  73. // Note: Make every guarantee that genericPtr is not null
  74. xmlNodePtr node = xmlNewNode(NULL, [name xmlChar]);
  75. if (node == NULL)
  76. {
  77. return nil;
  78. }
  79. DDXMLElement *result = [self initWithElementPrimitive:node owner:nil];
  80. [result setStringValue:string];
  81. return result;
  82. }
  83. - (id)initWithXMLString:(NSString *)string error:(NSError **)error
  84. {
  85. DDXMLDocument *doc = [[DDXMLDocument alloc] initWithXMLString:string options:0 error:error];
  86. if (doc == nil)
  87. {
  88. return nil;
  89. }
  90. DDXMLElement *result = [doc rootElement];
  91. [result detach];
  92. return result;
  93. }
  94. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  95. #pragma mark Elements by name
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. /**
  98. * Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
  99. * The name parameter is required, all others are optional.
  100. **/
  101. - (NSArray *)_elementsForName:(NSString *)name
  102. localName:(NSString *)localName
  103. prefix:(NSString *)prefix
  104. uri:(NSString *)uri
  105. {
  106. // This is a private/internal method
  107. // Rule : !uri => match: name
  108. // Rule : uri && hasPrefix => match: name || (localName && uri)
  109. // Rule : uri && !hasPefix => match: name && uri
  110. xmlNodePtr node = (xmlNodePtr)genericPtr;
  111. NSMutableArray *result = [NSMutableArray array];
  112. BOOL hasPrefix = [prefix length] > 0;
  113. const xmlChar *xmlName = [name xmlChar];
  114. const xmlChar *xmlLocalName = [localName xmlChar];
  115. const xmlChar *xmlUri = [uri xmlChar];
  116. xmlNodePtr child = node->children;
  117. while (child)
  118. {
  119. if (IsXmlNodePtr(child))
  120. {
  121. BOOL match = NO;
  122. if (uri == nil)
  123. {
  124. match = xmlStrEqual(child->name, xmlName);
  125. }
  126. else
  127. {
  128. BOOL nameMatch = xmlStrEqual(child->name, xmlName);
  129. BOOL localNameMatch = xmlStrEqual(child->name, xmlLocalName);
  130. BOOL uriMatch = NO;
  131. if (child->ns)
  132. {
  133. uriMatch = xmlStrEqual(child->ns->href, xmlUri);
  134. }
  135. if (hasPrefix)
  136. match = nameMatch || (localNameMatch && uriMatch);
  137. else
  138. match = nameMatch && uriMatch;
  139. }
  140. if (match)
  141. {
  142. [result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]];
  143. }
  144. }
  145. child = child->next;
  146. }
  147. return result;
  148. }
  149. /**
  150. * Returns the child element nodes (as DDXMLElement objects) of the receiver that have a specified name.
  151. *
  152. * If name is a qualified name, then this method invokes elementsForLocalName:URI: with the URI parameter set to
  153. * the URI associated with the prefix. Otherwise comparison is based on string equality of the qualified or
  154. * non-qualified name.
  155. **/
  156. - (NSArray *)elementsForName:(NSString *)name
  157. {
  158. #if DDXML_DEBUG_MEMORY_ISSUES
  159. DDXMLNotZombieAssert();
  160. #endif
  161. if (name == nil) return [NSArray array];
  162. // We need to check to see if name has a prefix.
  163. // If it does have a prefix, we need to figure out what the corresponding URI is for that prefix,
  164. // and then search for any elements that have the same name (including prefix) OR have the same URI.
  165. // Otherwise we loop through the children as usual and do a string compare on the name
  166. NSString *prefix;
  167. NSString *localName;
  168. [DDXMLNode getPrefix:&prefix localName:&localName forName:name];
  169. if ([prefix length] > 0)
  170. {
  171. xmlNodePtr node = (xmlNodePtr)genericPtr;
  172. // Note: We use xmlSearchNs instead of resolveNamespaceForName: because
  173. // we want to avoid creating wrapper objects when possible.
  174. xmlNsPtr ns = xmlSearchNs(node->doc, node, [prefix xmlChar]);
  175. if (ns)
  176. {
  177. NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)];
  178. return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
  179. }
  180. }
  181. return [self _elementsForName:name localName:localName prefix:prefix uri:nil];
  182. }
  183. - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri
  184. {
  185. #if DDXML_DEBUG_MEMORY_ISSUES
  186. DDXMLNotZombieAssert();
  187. #endif
  188. if (localName == nil) return [NSArray array];
  189. // We need to figure out what the prefix is for this URI.
  190. // Then we search for elements that are named prefix:localName OR (named localName AND have the given URI).
  191. NSString *prefix = [self _recursiveResolvePrefixForURI:uri atNode:(xmlNodePtr)genericPtr];
  192. if (prefix)
  193. {
  194. NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName];
  195. return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
  196. }
  197. else
  198. {
  199. NSString *prefix;
  200. NSString *realLocalName;
  201. [DDXMLNode getPrefix:&prefix localName:&realLocalName forName:localName];
  202. return [self _elementsForName:localName localName:realLocalName prefix:prefix uri:uri];
  203. }
  204. }
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. #pragma mark Attributes
  207. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  208. - (BOOL)_hasAttributeWithName:(NSString *)name
  209. {
  210. // This is a private/internal method
  211. xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
  212. if (attr)
  213. {
  214. const xmlChar *xmlName = [name xmlChar];
  215. do
  216. {
  217. if (xmlStrEqual(attr->name, xmlName))
  218. {
  219. return YES;
  220. }
  221. attr = attr->next;
  222. } while (attr);
  223. }
  224. return NO;
  225. }
  226. - (void)_removeAttributeForName:(NSString *)name
  227. {
  228. // This is a private/internal method
  229. xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
  230. if (attr)
  231. {
  232. const xmlChar *xmlName = [name xmlChar];
  233. do
  234. {
  235. if (xmlStrEqual(attr->name, xmlName))
  236. {
  237. [DDXMLNode removeAttribute:attr];
  238. return;
  239. }
  240. attr = attr->next;
  241. } while(attr);
  242. }
  243. }
  244. - (void)addAttribute:(DDXMLNode *)attribute
  245. {
  246. #if DDXML_DEBUG_MEMORY_ISSUES
  247. DDXMLNotZombieAssert();
  248. #endif
  249. // NSXML version uses this same assertion
  250. DDXMLAssert([attribute _hasParent] == NO, @"Cannot add an attribute with a parent; detach or copy first");
  251. DDXMLAssert(IsXmlAttrPtr(attribute->genericPtr), @"Not an attribute");
  252. [self _removeAttributeForName:[attribute name]];
  253. // xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur)
  254. // Add a new node to @parent, at the end of the child (or property) list merging
  255. // adjacent TEXT nodes (in which case @cur is freed). If the new node is ATTRIBUTE, it is added
  256. // into properties instead of children. If there is an attribute with equal name, it is first destroyed.
  257. xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)attribute->genericPtr);
  258. // The attribute is now part of the xml tree heirarchy
  259. attribute->owner = self;
  260. }
  261. - (void)removeAttributeForName:(NSString *)name
  262. {
  263. #if DDXML_DEBUG_MEMORY_ISSUES
  264. DDXMLNotZombieAssert();
  265. #endif
  266. [self _removeAttributeForName:name];
  267. }
  268. - (NSArray *)attributes
  269. {
  270. #if DDXML_DEBUG_MEMORY_ISSUES
  271. DDXMLNotZombieAssert();
  272. #endif
  273. NSMutableArray *result = [NSMutableArray array];
  274. xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
  275. while (attr != NULL)
  276. {
  277. [result addObject:[DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self]];
  278. attr = attr->next;
  279. }
  280. return result;
  281. }
  282. - (DDXMLNode *)attributeForName:(NSString *)name
  283. {
  284. #if DDXML_DEBUG_MEMORY_ISSUES
  285. DDXMLNotZombieAssert();
  286. #endif
  287. xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
  288. if (attr)
  289. {
  290. const xmlChar *xmlName = [name xmlChar];
  291. do
  292. {
  293. if (attr->ns && attr->ns->prefix)
  294. {
  295. // If the attribute name was originally something like "xml:quack",
  296. // then attr->name is "quack" and attr->ns->prefix is "xml".
  297. //
  298. // So if the user is searching for "xml:quack" we need to take the prefix into account.
  299. // Note that "xml:quack" is what would be printed if we output the attribute.
  300. if (xmlStrQEqual(attr->ns->prefix, attr->name, xmlName))
  301. {
  302. return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
  303. }
  304. }
  305. else
  306. {
  307. if (xmlStrEqual(attr->name, xmlName))
  308. {
  309. return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
  310. }
  311. }
  312. attr = attr->next;
  313. } while (attr);
  314. }
  315. return nil;
  316. }
  317. /**
  318. * Sets the list of attributes for the element.
  319. * Any previously set attributes are removed.
  320. **/
  321. - (void)setAttributes:(NSArray *)attributes
  322. {
  323. #if DDXML_DEBUG_MEMORY_ISSUES
  324. DDXMLNotZombieAssert();
  325. #endif
  326. [DDXMLNode removeAllAttributesFromNode:(xmlNodePtr)genericPtr];
  327. NSUInteger i;
  328. for (i = 0; i < [attributes count]; i++)
  329. {
  330. DDXMLNode *attribute = [attributes objectAtIndex:i];
  331. [self addAttribute:attribute];
  332. // Note: The addAttributes method properly sets the freeOnDealloc ivar.
  333. }
  334. }
  335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  336. #pragma mark Namespaces
  337. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  338. - (void)_removeNamespaceForPrefix:(NSString *)name
  339. {
  340. xmlNodePtr node = (xmlNodePtr)genericPtr;
  341. // If name is nil or the empty string, the user is wishing to remove the default namespace
  342. const xmlChar *xmlName = [name length] > 0 ? [name xmlChar] : NULL;
  343. xmlNsPtr ns = node->nsDef;
  344. while (ns != NULL)
  345. {
  346. if (xmlStrEqual(ns->prefix, xmlName))
  347. {
  348. [DDXMLNode removeNamespace:ns fromNode:node];
  349. break;
  350. }
  351. ns = ns->next;
  352. }
  353. // Note: The removeNamespace method properly handles the situation where the namespace is the default namespace
  354. }
  355. - (void)_addNamespace:(DDXMLNode *)namespace
  356. {
  357. // NSXML version uses this same assertion
  358. DDXMLAssert([namespace _hasParent] == NO, @"Cannot add a namespace with a parent; detach or copy first");
  359. DDXMLAssert(IsXmlNsPtr(namespace->genericPtr), @"Not a namespace");
  360. xmlNodePtr node = (xmlNodePtr)genericPtr;
  361. xmlNsPtr ns = (xmlNsPtr)namespace->genericPtr;
  362. // Beware: [namespace prefix] does NOT return what you might expect. Use [namespace name] instead.
  363. NSString *namespaceName = [namespace name];
  364. [self _removeNamespaceForPrefix:namespaceName];
  365. xmlNsPtr currentNs = node->nsDef;
  366. if (currentNs == NULL)
  367. {
  368. node->nsDef = ns;
  369. }
  370. else
  371. {
  372. while (currentNs->next != NULL)
  373. {
  374. currentNs = currentNs->next;
  375. }
  376. currentNs->next = ns;
  377. }
  378. // The namespace is now part of the xml tree heirarchy
  379. namespace->owner = self;
  380. if ([namespace isKindOfClass:[DDXMLNamespaceNode class]])
  381. {
  382. DDXMLNamespaceNode *ddNamespace = (DDXMLNamespaceNode *)namespace;
  383. // The xmlNs structure doesn't contain a reference to the parent, so we manage our own reference
  384. [ddNamespace _setNsParentPtr:node];
  385. }
  386. // Did we just add a default namespace
  387. if ([namespaceName isEqualToString:@""])
  388. {
  389. node->ns = ns;
  390. // Note: The removeNamespaceForPrefix method above properly handled removing any previous default namespace
  391. }
  392. }
  393. - (void)addNamespace:(DDXMLNode *)namespace
  394. {
  395. #if DDXML_DEBUG_MEMORY_ISSUES
  396. DDXMLNotZombieAssert();
  397. #endif
  398. [self _addNamespace:namespace];
  399. }
  400. - (void)removeNamespaceForPrefix:(NSString *)name
  401. {
  402. #if DDXML_DEBUG_MEMORY_ISSUES
  403. DDXMLNotZombieAssert();
  404. #endif
  405. [self _removeNamespaceForPrefix:name];
  406. }
  407. - (NSArray *)namespaces
  408. {
  409. #if DDXML_DEBUG_MEMORY_ISSUES
  410. DDXMLNotZombieAssert();
  411. #endif
  412. NSMutableArray *result = [NSMutableArray array];
  413. xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
  414. while (ns != NULL)
  415. {
  416. [result addObject:[DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self]];
  417. ns = ns->next;
  418. }
  419. return result;
  420. }
  421. - (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
  422. {
  423. #if DDXML_DEBUG_MEMORY_ISSUES
  424. DDXMLNotZombieAssert();
  425. #endif
  426. // If the prefix is nil or the empty string, the user is requesting the default namespace
  427. if ([prefix length] == 0)
  428. {
  429. // Requesting the default namespace
  430. xmlNsPtr ns = ((xmlNodePtr)genericPtr)->ns;
  431. if (ns != NULL)
  432. {
  433. return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
  434. }
  435. }
  436. else
  437. {
  438. xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
  439. if (ns)
  440. {
  441. const xmlChar *xmlPrefix = [prefix xmlChar];
  442. do
  443. {
  444. if (xmlStrEqual(ns->prefix, xmlPrefix))
  445. {
  446. return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
  447. }
  448. ns = ns->next;
  449. } while (ns);
  450. }
  451. }
  452. return nil;
  453. }
  454. - (void)setNamespaces:(NSArray *)namespaces
  455. {
  456. #if DDXML_DEBUG_MEMORY_ISSUES
  457. DDXMLNotZombieAssert();
  458. #endif
  459. [DDXMLNode removeAllNamespacesFromNode:(xmlNodePtr)genericPtr];
  460. NSUInteger i;
  461. for (i = 0; i < [namespaces count]; i++)
  462. {
  463. DDXMLNode *namespace = [namespaces objectAtIndex:i];
  464. [self _addNamespace:namespace];
  465. // Note: The addNamespace method properly sets the freeOnDealloc ivar.
  466. }
  467. }
  468. /**
  469. * Recursively searches the given node for the given namespace
  470. **/
  471. - (DDXMLNode *)_recursiveResolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)nodePtr
  472. {
  473. // This is a private/internal method
  474. if (nodePtr == NULL) return nil;
  475. xmlNsPtr ns = nodePtr->nsDef;
  476. if (ns)
  477. {
  478. const xmlChar *xmlPrefix = [prefix xmlChar];
  479. do
  480. {
  481. if (xmlStrEqual(ns->prefix, xmlPrefix))
  482. {
  483. return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:nodePtr owner:self];
  484. }
  485. ns = ns->next;
  486. } while(ns);
  487. }
  488. return [self _recursiveResolveNamespaceForPrefix:prefix atNode:nodePtr->parent];
  489. }
  490. /**
  491. * Returns the namespace node with the prefix matching the given qualified name.
  492. * Eg: You pass it "a:dog", it returns the namespace (defined in this node or parent nodes) that has the "a" prefix.
  493. **/
  494. - (DDXMLNode *)resolveNamespaceForName:(NSString *)name
  495. {
  496. #if DDXML_DEBUG_MEMORY_ISSUES
  497. DDXMLNotZombieAssert();
  498. #endif
  499. // If the user passes nil or an empty string for name, they're looking for the default namespace.
  500. if ([name length] == 0)
  501. {
  502. return [self _recursiveResolveNamespaceForPrefix:nil atNode:(xmlNodePtr)genericPtr];
  503. }
  504. NSString *prefix = [[self class] prefixForName:name];
  505. if ([prefix length] > 0)
  506. {
  507. // Unfortunately we can't use xmlSearchNs because it returns an xmlNsPtr.
  508. // This gives us mostly what we want, except we also need to know the nsParent.
  509. // So we do the recursive search ourselves.
  510. return [self _recursiveResolveNamespaceForPrefix:prefix atNode:(xmlNodePtr)genericPtr];
  511. }
  512. return nil;
  513. }
  514. /**
  515. * Recursively searches the given node for a namespace with the given URI, and a set prefix.
  516. **/
  517. - (NSString *)_recursiveResolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)nodePtr
  518. {
  519. // This is a private/internal method
  520. if (nodePtr == NULL) return nil;
  521. xmlNsPtr ns = nodePtr->nsDef;
  522. if (ns)
  523. {
  524. const xmlChar *xmlUri = [uri xmlChar];
  525. do
  526. {
  527. if (xmlStrEqual(ns->href, xmlUri))
  528. {
  529. if (ns->prefix != NULL)
  530. {
  531. return [NSString stringWithUTF8String:((const char *)ns->prefix)];
  532. }
  533. }
  534. ns = ns->next;
  535. } while (ns);
  536. }
  537. return [self _recursiveResolvePrefixForURI:uri atNode:nodePtr->parent];
  538. }
  539. /**
  540. * Returns the prefix associated with the specified URI.
  541. * Returns a string that is the matching prefix or nil if it finds no matching prefix.
  542. **/
  543. - (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI
  544. {
  545. #if DDXML_DEBUG_MEMORY_ISSUES
  546. DDXMLNotZombieAssert();
  547. #endif
  548. // We can't use xmlSearchNsByHref because it will return xmlNsPtr's with NULL prefixes.
  549. // We're looking for a definitive prefix for the given URI.
  550. return [self _recursiveResolvePrefixForURI:namespaceURI atNode:(xmlNodePtr)genericPtr];
  551. }
  552. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  553. #pragma mark Children
  554. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  555. - (void)addChild:(DDXMLNode *)child
  556. {
  557. #if DDXML_DEBUG_MEMORY_ISSUES
  558. DDXMLNotZombieAssert();
  559. #endif
  560. // NSXML version uses these same assertions
  561. DDXMLAssert([child _hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
  562. DDXMLAssert(IsXmlNodePtr(child->genericPtr),
  563. @"Elements can only have text, elements, processing instructions, and comments as children");
  564. xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
  565. // The node is now part of the xml tree heirarchy
  566. child->owner = self;
  567. }
  568. - (void)insertChild:(DDXMLNode *)child atIndex:(NSUInteger)index
  569. {
  570. #if DDXML_DEBUG_MEMORY_ISSUES
  571. DDXMLNotZombieAssert();
  572. #endif
  573. // NSXML version uses these same assertions
  574. DDXMLAssert([child _hasParent] == NO, @"Cannot add a child that has a parent; detach or copy first");
  575. DDXMLAssert(IsXmlNodePtr(child->genericPtr),
  576. @"Elements can only have text, elements, processing instructions, and comments as children");
  577. NSUInteger i = 0;
  578. xmlNodePtr childNodePtr = ((xmlNodePtr)genericPtr)->children;
  579. while (childNodePtr != NULL)
  580. {
  581. // Ignore all but element, comment, text, or processing instruction nodes
  582. if (IsXmlNodePtr(childNodePtr))
  583. {
  584. if (i == index)
  585. {
  586. xmlAddPrevSibling(childNodePtr, (xmlNodePtr)child->genericPtr);
  587. child->owner = self;
  588. return;
  589. }
  590. i++;
  591. }
  592. childNodePtr = childNodePtr->next;
  593. }
  594. if (i == index)
  595. {
  596. xmlAddChild((xmlNodePtr)genericPtr, (xmlNodePtr)child->genericPtr);
  597. child->owner = self;
  598. return;
  599. }
  600. // NSXML version uses this same assertion
  601. DDXMLAssert(NO, @"index (%u) beyond bounds (%u)", (unsigned)index, (unsigned)++i);
  602. }
  603. - (void)removeChildAtIndex:(NSUInteger)index
  604. {
  605. #if DDXML_DEBUG_MEMORY_ISSUES
  606. DDXMLNotZombieAssert();
  607. #endif
  608. NSUInteger i = 0;
  609. xmlNodePtr child = ((xmlNodePtr)genericPtr)->children;
  610. while (child != NULL)
  611. {
  612. // Ignore all but element, comment, text, or processing instruction nodes
  613. if (IsXmlNodePtr(child))
  614. {
  615. if (i == index)
  616. {
  617. [DDXMLNode removeChild:child];
  618. return;
  619. }
  620. i++;
  621. }
  622. child = child->next;
  623. }
  624. }
  625. - (void)setChildren:(NSArray *)children
  626. {
  627. #if DDXML_DEBUG_MEMORY_ISSUES
  628. DDXMLNotZombieAssert();
  629. #endif
  630. [DDXMLNode removeAllChildrenFromNode:(xmlNodePtr)genericPtr];
  631. NSUInteger i;
  632. for (i = 0; i < [children count]; i++)
  633. {
  634. DDXMLNode *child = [children objectAtIndex:i];
  635. [self addChild:child];
  636. // Note: The addChild method properly sets the freeOnDealloc ivar.
  637. }
  638. }
  639. @end