/iphone/Classes/TiDOMElementProxy.m

https://github.com/ayeung/titanium_mobile · Objective C · 666 lines · 564 code · 76 blank · 26 comment · 119 complexity · 8090ac171ea505d22759c17dc8d44126 MD5 · raw file

  1. /**
  2. * Appcelerator Titanium Mobile
  3. * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved.
  4. * Licensed under the terms of the Apache Public License
  5. * Please see the LICENSE included with this distribution for details.
  6. */
  7. #if defined(USE_TI_XML) || defined(USE_TI_NETWORK)
  8. #import "TiDOMElementProxy.h"
  9. #import "TiDOMNodeProxy.h"
  10. #import "TiDOMNodeListProxy.h"
  11. #import "TiDOMAttrProxy.h"
  12. #import "TiUtils.h"
  13. @implementation TiDOMElementProxy
  14. -(void)dealloc
  15. {
  16. RELEASE_TO_NIL(element);
  17. [super dealloc];
  18. }
  19. -(void)setElement:(GDataXMLElement*)element_
  20. {
  21. RELEASE_TO_NIL(element);
  22. element = [element_ retain];
  23. [self setNode:element];
  24. }
  25. -(id)nodeValue
  26. {
  27. // DOM spec says nodeValue for element must return null
  28. return [NSNull null];
  29. }
  30. -(id)tagName
  31. {
  32. return [element name];
  33. }
  34. -(id)evaluate:(id)args
  35. {
  36. ENSURE_SINGLE_ARG(args,NSString);
  37. NSError *error = nil;
  38. NSArray *nodes = [node nodesForXPath:args error:&error];
  39. if (error==nil)
  40. {
  41. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  42. TiDOMNodeListProxy *proxy = [[[TiDOMNodeListProxy alloc] _initWithPageContext:context] autorelease];
  43. [proxy setNodes:nodes];
  44. [proxy setDocument:[self document]];
  45. return proxy;
  46. }
  47. return [NSNull null];
  48. }
  49. -(id)getElementsByTagName:(id)args
  50. {
  51. ENSURE_SINGLE_ARG(args,NSString);
  52. NSError *error = nil;
  53. NSString *xpath = [NSString stringWithFormat:@"self::node()/descendant::*[local-name()='%@']",args];
  54. // see if it's a namespace
  55. NSRange range = [args rangeOfString:@":"];
  56. if (range.location!=NSNotFound)
  57. {
  58. xpath = [NSString stringWithFormat:@"self::node()/descendant::*[name()='%@']",args];
  59. }
  60. NSArray *nodes = [element nodesForXPath:xpath error:&error];
  61. if (error==nil)
  62. {
  63. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  64. TiDOMNodeListProxy *proxy = [[[TiDOMNodeListProxy alloc] _initWithPageContext:context] autorelease];
  65. [proxy setNodes:nodes];
  66. [proxy setDocument:[self document]];
  67. return proxy;
  68. }
  69. else
  70. {
  71. [self throwException:[error description] subreason:nil location:CODELOCATION];
  72. return nil;
  73. }
  74. }
  75. -(id)getElementsByTagNameNS:(id)args
  76. {
  77. ENSURE_ARG_COUNT(args, 2);
  78. NSString * theURI;
  79. NSString * localName;
  80. ENSURE_ARG_AT_INDEX(theURI, args, 0, NSString);
  81. ENSURE_ARG_AT_INDEX(localName, args, 1, NSString);
  82. NSError *error = nil;
  83. //PARAMETER IS SPECIFIED AS LOCAL NAME
  84. NSString *xpath = [NSString stringWithFormat:@"self::node()/descendant::*[local-name()='%@' and namespace-uri()='%@']",localName, theURI];
  85. NSArray *nodes = [element nodesForXPath:xpath error:&error];
  86. if (error==nil)
  87. {
  88. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  89. TiDOMNodeListProxy *proxy = [[[TiDOMNodeListProxy alloc] _initWithPageContext:context] autorelease];
  90. [proxy setNodes:nodes];
  91. [proxy setDocument:[self document]];
  92. return proxy;
  93. }
  94. else
  95. {
  96. [self throwException:[error description] subreason:nil location:CODELOCATION];
  97. return nil;
  98. }
  99. }
  100. -(id)getAttribute:(id)args
  101. {
  102. ENSURE_SINGLE_ARG(args,NSString);
  103. GDataXMLNode *_node = [element attributeForName:args];
  104. if (_node!=nil)
  105. {
  106. return [_node stringValue];
  107. }
  108. return @"";
  109. }
  110. -(id)getAttributeNS:(id)args
  111. {
  112. ENSURE_ARG_COUNT(args, 2);
  113. NSString * theURI;
  114. NSString * localName;
  115. ENSURE_ARG_AT_INDEX(theURI, args, 0, NSString);
  116. ENSURE_ARG_AT_INDEX(localName, args, 1, NSString);
  117. GDataXMLNode *_node = [element attributeForLocalName:localName URI:theURI];
  118. if(_node != nil)
  119. {
  120. return [_node stringValue];
  121. }
  122. return @"";
  123. }
  124. -(void)setAttribute:(id)args
  125. {
  126. ENSURE_ARG_COUNT(args, 2);
  127. NSString *name = [args objectAtIndex:0];
  128. ENSURE_STRING_OR_NIL(name);
  129. NSString *val = [args objectAtIndex:1];
  130. ENSURE_STRING_OR_NIL(val);
  131. if (name != nil && val != nil)
  132. {
  133. GDataXMLNode * attributeNode = [element attributeForName:name];
  134. if(attributeNode != nil)
  135. {
  136. [attributeNode setStringValue:val];
  137. }
  138. else
  139. {
  140. [element addAttribute: [GDataXMLNode attributeWithName: name stringValue: val]];
  141. }
  142. }
  143. }
  144. -(void)setAttributeNS:(id)args
  145. {
  146. ENSURE_ARG_COUNT(args, 3);
  147. NSString *theURI = [args objectAtIndex:0];
  148. ENSURE_STRING_OR_NIL(theURI);
  149. NSString *name = [args objectAtIndex:1];
  150. ENSURE_STRING_OR_NIL(name);
  151. NSString *val = [args objectAtIndex:2];
  152. ENSURE_STRING_OR_NIL(val);
  153. if (theURI != nil && name != nil && val != nil)
  154. {
  155. GDataXMLNode * attributeNode = [element attributeForLocalName:[GDataXMLNode localNameForName:name] URI:theURI];
  156. if(attributeNode != nil)
  157. {
  158. //Retain it here so that the node does not get freed when cached values are released
  159. [attributeNode retain];
  160. //Switch the flag here so that the node is freed only when the object is freed
  161. [attributeNode setShouldFreeXMLNode:YES];
  162. [element removeChild:attributeNode];
  163. //Release now and this will free the underlying memory
  164. [attributeNode release];
  165. }
  166. [element addAttribute: [GDataXMLNode attributeWithName:name URI:theURI stringValue:val]];
  167. }
  168. }
  169. -(void)removeAttribute:(id)args
  170. {
  171. ENSURE_SINGLE_ARG(args, NSString);
  172. GDataXMLNode * attributeNode = [element attributeForName:args];
  173. if (attributeNode != nil)
  174. {
  175. //Retain it here so that the node does not get freed when cached values are released
  176. [attributeNode retain];
  177. //Switch the flag here so that the node is freed only when the object is freed
  178. [attributeNode setShouldFreeXMLNode:YES];
  179. [element removeChild:attributeNode];
  180. //Release now and this will free the underlying memory
  181. [attributeNode release];
  182. }
  183. }
  184. -(void)removeAttributeNS:(id)args
  185. {
  186. ENSURE_ARG_COUNT(args, 2);
  187. NSString *theURI = [args objectAtIndex:0];
  188. ENSURE_STRING_OR_NIL(theURI);
  189. NSString *name = [args objectAtIndex:1];
  190. ENSURE_STRING_OR_NIL(name);
  191. if(theURI != nil && name != nil)
  192. {
  193. GDataXMLNode * attributeNode = [element attributeForLocalName:name URI:theURI];
  194. if (attributeNode != nil)
  195. {
  196. //Retain it here so that the node does not get freed when cached values are released
  197. [attributeNode retain];
  198. //Switch the flag here so that the node is freed only when the object is freed
  199. [attributeNode setShouldFreeXMLNode:YES];
  200. [element removeChild:attributeNode];
  201. //Release now and this will free the underlying memory
  202. [attributeNode release];
  203. }
  204. }
  205. }
  206. -(id)getAttributeNode:(id)args
  207. {
  208. ENSURE_SINGLE_ARG(args, NSString);
  209. GDataXMLNode * attributeNode = [element attributeForName:args];
  210. if (attributeNode == nil)
  211. {
  212. return [NSNull null];
  213. }
  214. xmlNodePtr resultPtr = [attributeNode XMLNode];
  215. id resultNode = [TiDOMNodeProxy nodeForXMLNode:resultPtr];
  216. if(resultNode != nil)
  217. return resultNode;
  218. NSString* nodeString = [attributeNode stringValue];
  219. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  220. TiDOMAttrProxy * result = [[[TiDOMAttrProxy alloc] _initWithPageContext:context] autorelease];
  221. [result setAttribute:[attributeNode name] value:nodeString owner:element];
  222. [result setNode:attributeNode];
  223. [result setDocument:[self document]];
  224. [TiDOMNodeProxy setNode:result forXMLNode:resultPtr];
  225. return result;
  226. }
  227. -(id)getAttributeNodeNS:(id)args
  228. {
  229. ENSURE_ARG_COUNT(args, 2);
  230. NSString *theURI = [args objectAtIndex:0];
  231. ENSURE_STRING_OR_NIL(theURI);
  232. NSString *name = [args objectAtIndex:1];
  233. ENSURE_STRING_OR_NIL(name);
  234. if(theURI != nil && name != nil)
  235. {
  236. GDataXMLNode * attributeNode = [element attributeForLocalName:name URI:theURI];
  237. if(attributeNode != nil)
  238. {
  239. xmlNodePtr resultPtr = [attributeNode XMLNode];
  240. id resultNode = [TiDOMNodeProxy nodeForXMLNode:resultPtr];
  241. if(resultNode != nil)
  242. return resultNode;
  243. NSString* nodeString = [attributeNode stringValue];
  244. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  245. TiDOMAttrProxy * result = [[[TiDOMAttrProxy alloc] _initWithPageContext:context] autorelease];
  246. [result setAttribute:[attributeNode name] value:nodeString owner:element];
  247. [result setNode:attributeNode];
  248. [result setDocument:[self document]];
  249. [TiDOMNodeProxy setNode:result forXMLNode:resultPtr];
  250. return result;
  251. }
  252. }
  253. return [NSNull null];
  254. }
  255. -(id)setAttributeNode:(id)args
  256. {
  257. ENSURE_SINGLE_ARG(args, TiDOMAttrProxy);
  258. TiDOMAttrProxy* attProxy = (TiDOMAttrProxy*)args;
  259. NSString* name = [[attProxy node]name];
  260. NSString* val = [attProxy value];
  261. TiDOMAttrProxy* result = nil;
  262. if(name != nil && val != nil)
  263. {
  264. NSObject* ownerObj = [attProxy ownerElement];
  265. if(![ownerObj isKindOfClass:[NSNull class]])
  266. {
  267. GDataXMLElement *owner = [attProxy ownerElement];
  268. if( (owner != nil)&&([node isEqual:owner] == NO) )
  269. {
  270. [self throwException:@"mismatched owner elements" subreason:nil location:CODELOCATION];
  271. return [NSNull null];
  272. }
  273. }
  274. if ([attProxy document] != [self document])
  275. {
  276. [self throwException:@"mismatched documents" subreason:nil location:CODELOCATION];
  277. return [NSNull null];
  278. }
  279. GDataXMLNode * attributeNode = [element attributeForName:name];
  280. if (attributeNode != nil)
  281. {
  282. //Switch the flag here so that the node is freed only when the object is freed
  283. [attributeNode setShouldFreeXMLNode:YES];
  284. xmlNodePtr oldNodePtr = [attributeNode XMLNode];
  285. result = [TiDOMNodeProxy nodeForXMLNode:oldNodePtr];
  286. if(result == nil)
  287. {
  288. NSString* nodeString = [attributeNode stringValue];
  289. //Need to return the old attribute node
  290. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  291. result = [[[TiDOMAttrProxy alloc] _initWithPageContext:context] autorelease];
  292. [result setAttribute:[attributeNode name] value:nodeString owner:element];
  293. [result setNode:attributeNode];
  294. [result setDocument:[self document]];
  295. [TiDOMNodeProxy setNode:result forXMLNode:[attributeNode XMLNode]];
  296. }
  297. else
  298. {
  299. [TiDOMNodeProxy removeNodeForXMLNode:oldNodePtr];
  300. [TiDOMNodeProxy setNode:result forXMLNode:[attributeNode XMLNode]];
  301. [result setAttribute:[attributeNode name] value:[attributeNode stringValue] owner:element];
  302. [result setNode:attributeNode];
  303. [result setDocument:[self document]];
  304. }
  305. [element removeChild:attributeNode];
  306. }
  307. xmlNodePtr oldNodePtr = [[attProxy node]XMLNode];
  308. if(oldNodePtr != NULL)
  309. {
  310. [TiDOMNodeProxy removeNodeForXMLNode:oldNodePtr];
  311. }
  312. [element addAttribute: [attProxy node]];
  313. attributeNode = [element attributeForName:name];
  314. [attProxy setNode:attributeNode];
  315. [attProxy setAttribute:[attributeNode name] value:[attributeNode stringValue] owner:element];
  316. [TiDOMNodeProxy setNode:attProxy forXMLNode:[attributeNode XMLNode]];
  317. }
  318. if(result == nil)
  319. return [NSNull null];
  320. return result;
  321. }
  322. -(id)setAttributeNodeNS:(id)args
  323. {
  324. ENSURE_SINGLE_ARG(args, TiDOMAttrProxy);
  325. TiDOMAttrProxy* attProxy = (TiDOMAttrProxy*)args;
  326. NSString* name = [[attProxy node]name];
  327. NSString* val = [attProxy value];
  328. NSString* theURI = [[attProxy node]URI];
  329. TiDOMAttrProxy* result = nil;
  330. if(name != nil && val != nil)
  331. {
  332. NSObject* ownerObj = [attProxy ownerElement];
  333. if(![ownerObj isKindOfClass:[NSNull class]])
  334. {
  335. GDataXMLElement *owner = [attProxy ownerElement];
  336. if( (owner != nil)&&([node isEqual:owner] == NO) )
  337. {
  338. [self throwException:@"mismatched owner elements" subreason:nil location:CODELOCATION];
  339. return [NSNull null];
  340. }
  341. }
  342. if ([attProxy document] != [self document])
  343. {
  344. [self throwException:@"mismatched documents" subreason:nil location:CODELOCATION];
  345. return [NSNull null];
  346. }
  347. GDataXMLNode * attributeNode = [element attributeForLocalName:[GDataXMLNode localNameForName:name] URI:theURI];
  348. if (attributeNode != nil)
  349. {
  350. //Switch the flag here so that the node is freed only when the object is freed
  351. [attributeNode setShouldFreeXMLNode:YES];
  352. xmlNodePtr oldNodePtr = [attributeNode XMLNode];
  353. result = [TiDOMNodeProxy nodeForXMLNode:oldNodePtr];
  354. if(result == nil)
  355. {
  356. NSString* nodeString = [attributeNode stringValue];
  357. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  358. //Need to return the old attribute node
  359. result = [[[TiDOMAttrProxy alloc] _initWithPageContext:context] autorelease];
  360. [result setAttribute:[attributeNode name] value:nodeString owner:nil];
  361. [result setNode:attributeNode];
  362. [result setDocument:[self document]];
  363. [TiDOMNodeProxy setNode:result forXMLNode:[attributeNode XMLNode]];
  364. }
  365. else
  366. {
  367. [TiDOMNodeProxy removeNodeForXMLNode:oldNodePtr];
  368. [TiDOMNodeProxy setNode:result forXMLNode:[attributeNode XMLNode]];
  369. [result setAttribute:[attributeNode name] value:[attributeNode stringValue] owner:element];
  370. [result setNode:attributeNode];
  371. [result setDocument:[self document]];
  372. }
  373. [element removeChild:attributeNode];
  374. }
  375. xmlNodePtr oldNodePtr = [[attProxy node]XMLNode];
  376. if(oldNodePtr != NULL)
  377. {
  378. [TiDOMNodeProxy removeNodeForXMLNode:oldNodePtr];
  379. }
  380. [element addAttribute: [attProxy node]];
  381. attributeNode = [element attributeForLocalName:[GDataXMLNode localNameForName:name] URI:theURI];
  382. [attProxy setNode:attributeNode];
  383. [attProxy setAttribute:[attributeNode name] value:[attributeNode stringValue] owner:element];
  384. [TiDOMNodeProxy setNode:attProxy forXMLNode:[attributeNode XMLNode]];
  385. }
  386. if(result == nil)
  387. return [NSNull null];
  388. return result;
  389. }
  390. -(id)removeAttributeNode:(id)args
  391. {
  392. ENSURE_SINGLE_ARG(args, TiDOMAttrProxy);
  393. TiDOMAttrProxy* attProxy = (TiDOMAttrProxy*)args;
  394. xmlNodePtr theNodeToRemove = [[attProxy node]XMLNode];
  395. NSArray* elemAttributes = [element attributes];
  396. GDataXMLNode* nodeToRemove = nil;
  397. if([elemAttributes count]>0)
  398. {
  399. for(GDataXMLNode* node_ in elemAttributes)
  400. {
  401. if([node_ XMLNode] == theNodeToRemove)
  402. {
  403. nodeToRemove = node_;
  404. break;
  405. }
  406. }
  407. if(nodeToRemove == nil)
  408. {
  409. [self throwException:@"no node found to remove" subreason:nil location:CODELOCATION];
  410. return;
  411. }
  412. else
  413. {
  414. //Switch the flag here so that the node is freed only when the object is freed
  415. [[attProxy node]setShouldFreeXMLNode:YES];
  416. [element removeChild:nodeToRemove];
  417. return attProxy;
  418. }
  419. }
  420. else
  421. {
  422. [self throwException:@"no node found to remove" subreason:nil location:CODELOCATION];
  423. return;
  424. }
  425. }
  426. -(id)insertBefore:(id)args
  427. {
  428. ENSURE_ARG_COUNT(args, 2);
  429. TiDOMNodeProxy* newChild;
  430. TiDOMNodeProxy* refChild;
  431. ENSURE_ARG_AT_INDEX(newChild, args, 0, TiDOMNodeProxy);
  432. ENSURE_ARG_AT_INDEX(refChild, args, 1, TiDOMNodeProxy);
  433. NSArray* children = [node children];
  434. GDataXMLNode* refChildNode = [refChild node];
  435. GDataXMLNode* actualRefChildNode = nil;
  436. for(GDataXMLNode* childNode in children)
  437. {
  438. if ([childNode XMLNode] == [refChildNode XMLNode])
  439. {
  440. actualRefChildNode = childNode;
  441. break;
  442. }
  443. }
  444. if(actualRefChildNode != nil)
  445. {
  446. xmlNodePtr returnNode = xmlAddPrevSibling([actualRefChildNode XMLNode], [[newChild node] XMLNode]);
  447. if(returnNode != NULL)
  448. {
  449. [[self node]releaseCachedValues];
  450. if (returnNode == [[newChild node] XMLNode])
  451. {
  452. //Now it is part of the tree so switch flag to ensur it gets freed when doc is released
  453. [[newChild node]setShouldFreeXMLNode:NO];
  454. return newChild;
  455. }
  456. GDataXMLNode* retVal = [GDataXMLNode nodeBorrowingXMLNode:returnNode];
  457. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  458. return [TiDOMNodeProxy makeNode:retVal context:context];
  459. }
  460. return [NSNull null];
  461. }
  462. return [NSNull null];
  463. }
  464. -(id)replaceChild:(id)args
  465. {
  466. ENSURE_ARG_COUNT(args, 2);
  467. TiDOMNodeProxy* newChild;
  468. TiDOMNodeProxy* refChild;
  469. ENSURE_ARG_AT_INDEX(newChild, args, 0, TiDOMNodeProxy);
  470. ENSURE_ARG_AT_INDEX(refChild, args, 1, TiDOMNodeProxy);
  471. if(newChild == refChild)
  472. return;
  473. NSArray* children = [node children];
  474. GDataXMLNode* refChildNode = [refChild node];
  475. GDataXMLNode* actualRefChildNode = nil;
  476. for(GDataXMLNode* childNode in children)
  477. {
  478. if ([childNode XMLNode] == [refChildNode XMLNode])
  479. {
  480. actualRefChildNode = childNode;
  481. break;
  482. }
  483. }
  484. if(actualRefChildNode != nil)
  485. {
  486. xmlNodePtr returnNode = xmlReplaceNode([actualRefChildNode XMLNode], [[newChild node]XMLNode]);
  487. if(returnNode != nil)
  488. {
  489. //No longer part of tree. Set to free node ptr on object dealloc
  490. [[self node]releaseCachedValues];
  491. if (returnNode == [[refChild node] XMLNode])
  492. {
  493. [[refChild node]setShouldFreeXMLNode:YES];
  494. return refChild;
  495. }
  496. GDataXMLNode* retVal = [GDataXMLNode nodeConsumingXMLNode:returnNode];
  497. id context = ([self executionContext]==nil)?[self pageContext]:[self executionContext];
  498. return [TiDOMNodeProxy makeNode:retVal context:context];
  499. }
  500. return [NSNull null];
  501. }
  502. return [NSNull null];
  503. }
  504. -(id)removeChild:(id)args
  505. {
  506. ENSURE_SINGLE_ARG(args, TiDOMNodeProxy);
  507. TiDOMNodeProxy * oldChild = (TiDOMNodeProxy*)args;
  508. NSArray* children = [node children];
  509. GDataXMLNode* refChildNode = [oldChild node];
  510. GDataXMLNode* actualRefChildNode = nil;
  511. for(GDataXMLNode* childNode in children)
  512. {
  513. if ([childNode XMLNode] == [refChildNode XMLNode])
  514. {
  515. actualRefChildNode = childNode;
  516. break;
  517. }
  518. }
  519. if(actualRefChildNode != nil)
  520. {
  521. [actualRefChildNode setShouldFreeXMLNode:YES];
  522. if ([oldChild isKindOfClass:[TiDOMElementProxy class]])
  523. {
  524. [(TiDOMElementProxy*)oldChild setElement:(GDataXMLElement*)actualRefChildNode];
  525. }
  526. else
  527. {
  528. [oldChild setNode:actualRefChildNode];
  529. }
  530. [element removeChild:actualRefChildNode];
  531. return oldChild;
  532. }
  533. else
  534. {
  535. [self throwException:@"no node found to remove" subreason:nil location:CODELOCATION];
  536. return [NSNull null];
  537. }
  538. }
  539. -(id)appendChild:(id)args
  540. {
  541. ENSURE_SINGLE_ARG(args, TiDOMNodeProxy);
  542. TiDOMNodeProxy * newChild = (TiDOMNodeProxy*)args;
  543. xmlNodePtr oldNodePtr = [[newChild node]XMLNode];
  544. GDataXMLNode* resultElement = [element addChild:[newChild node]];
  545. if (resultElement != nil)
  546. {
  547. //No longer part of tree set to free node since add child adds by creating copy
  548. [[newChild node]setShouldFreeXMLNode:YES];
  549. if (oldNodePtr != NULL)
  550. {
  551. [TiDOMNodeProxy removeNodeForXMLNode:oldNodePtr];
  552. }
  553. if ([newChild isKindOfClass:[TiDOMElementProxy class]])
  554. {
  555. [(TiDOMElementProxy*)newChild setElement:(GDataXMLElement*)resultElement];
  556. }
  557. else
  558. {
  559. [newChild setNode:resultElement];
  560. }
  561. [TiDOMNodeProxy setNode:newChild forXMLNode:[resultElement XMLNode]];
  562. return newChild;
  563. }
  564. else
  565. {
  566. return [NSNull null];
  567. }
  568. }
  569. -(id)hasAttribute:(id)args
  570. {
  571. ENSURE_SINGLE_ARG(args,NSString);
  572. GDataXMLNode *_node = [element attributeForName:args];
  573. return NUMBOOL(_node!=nil);
  574. }
  575. -(id)hasAttributeNS:(id)args
  576. {
  577. ENSURE_ARG_COUNT(args, 2);
  578. NSString *theURI = [args objectAtIndex:0];
  579. ENSURE_STRING_OR_NIL(theURI);
  580. NSString *name = [args objectAtIndex:1];
  581. ENSURE_STRING_OR_NIL(name);
  582. if(theURI != nil && name != nil)
  583. {
  584. GDataXMLNode *_node = [element attributeForLocalName:name URI:theURI];
  585. return NUMBOOL(_node!=nil);
  586. }
  587. return NUMBOOL(NO);
  588. }
  589. @end
  590. #endif