Node.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. //
  2. // Node.m
  3. // SVGKit
  4. //
  5. // Created by adam on 22/05/2012.
  6. // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
  7. //
  8. #import "Node.h"
  9. #import "Node+Mutable.h"
  10. #import "NodeList+Mutable.h"
  11. #import "NamedNodeMap.h"
  12. #import "NamedNodeMap_Iterable.h" // Needed for the optional (non-SVG spec) "recursive toXML" method
  13. @implementation Node
  14. @synthesize nodeName;
  15. @synthesize nodeValue;
  16. @synthesize nodeType;
  17. @synthesize parentNode;
  18. @synthesize childNodes;
  19. @synthesize attributes;
  20. // Modified in DOM Level 2:
  21. @synthesize ownerDocument;
  22. @synthesize hasAttributes, hasChildNodes;
  23. @synthesize localName;
  24. - (id)init
  25. {
  26. NSAssert( FALSE, @"This class has no init method - it MUST NOT be init'd via init - you MUST use one of the multi-argument constructors instead" );
  27. return nil;
  28. }
  29. - (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v
  30. {
  31. if( [v isKindOfClass:[NSMutableString class]])
  32. {
  33. /** Apple allows this, but it breaks the whole of Obj-C / cocoa, which is damn stupid
  34. So we have to fix it.*/
  35. v = [NSString stringWithString:v];
  36. }
  37. self = [super init];
  38. if (self) {
  39. self.nodeType = nt;
  40. switch( nt )
  41. {
  42. case DOMNodeType_ATTRIBUTE_NODE:
  43. case DOMNodeType_CDATA_SECTION_NODE:
  44. case DOMNodeType_COMMENT_NODE:
  45. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  46. case DOMNodeType_TEXT_NODE:
  47. {
  48. self.nodeName = n;
  49. self.nodeValue = v;
  50. }break;
  51. case DOMNodeType_DOCUMENT_NODE:
  52. case DOMNodeType_DOCUMENT_TYPE_NODE:
  53. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  54. case DOMNodeType_ENTITY_REFERENCE_NODE:
  55. case DOMNodeType_ENTITY_NODE:
  56. case DOMNodeType_NOTATION_NODE:
  57. case DOMNodeType_ELEMENT_NODE:
  58. {
  59. NSAssert( FALSE, @"NodeType = %i cannot be init'd with a value; nodes of that type have no value in the DOM spec", nt);
  60. self = nil;
  61. }break;
  62. }
  63. self.childNodes = [[NodeList alloc] init];
  64. }
  65. return self;
  66. }
  67. - (id)initType:(DOMNodeType) nt name:(NSString*) n
  68. {
  69. self = [super init];
  70. if (self) {
  71. self.nodeType = nt;
  72. switch( nt )
  73. {
  74. case DOMNodeType_ATTRIBUTE_NODE:
  75. case DOMNodeType_CDATA_SECTION_NODE:
  76. case DOMNodeType_COMMENT_NODE:
  77. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  78. case DOMNodeType_TEXT_NODE:
  79. {
  80. NSAssert( FALSE, @"NodeType = %i cannot be init'd without a value; nodes of that type MUST have a value in the DOM spec", nt);
  81. self = nil;
  82. }break;
  83. case DOMNodeType_DOCUMENT_NODE:
  84. case DOMNodeType_DOCUMENT_TYPE_NODE:
  85. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  86. case DOMNodeType_ENTITY_REFERENCE_NODE:
  87. case DOMNodeType_ENTITY_NODE:
  88. case DOMNodeType_NOTATION_NODE:
  89. {
  90. self.nodeName = n;
  91. }break;
  92. case DOMNodeType_ELEMENT_NODE:
  93. {
  94. self.nodeName = n;
  95. self.attributes = [[NamedNodeMap alloc] init];
  96. }break;
  97. }
  98. self.childNodes = [[NodeList alloc] init];
  99. }
  100. return self;
  101. }
  102. #pragma mark - Objective-C init methods DOM LEVEL 2 (preferred init - safer/better!)
  103. -(void) postInitNamespaceHandling:(NSString*) nsURI
  104. {
  105. NSArray* nameSpaceParts = [self.nodeName componentsSeparatedByString:@":"];
  106. self.localName = [nameSpaceParts lastObject];
  107. if( [nameSpaceParts count] > 1 )
  108. self.prefix = [nameSpaceParts objectAtIndex:0];
  109. self.namespaceURI = nsURI;
  110. }
  111. - (id)initType:(DOMNodeType) nt name:(NSString*) n inNamespace:(NSString*) nsURI
  112. {
  113. self = [self initType:nt name:n];
  114. if( self )
  115. {
  116. [self postInitNamespaceHandling:nsURI];
  117. }
  118. return self;
  119. }
  120. - (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v inNamespace:(NSString*) nsURI
  121. {
  122. if( [v isKindOfClass:[NSMutableString class]])
  123. {
  124. /** Apple allows this, but it breaks the whole of Obj-C / cocoa, which is damn stupid
  125. So we have to fix it.*/
  126. v = [NSString stringWithString:v];
  127. }
  128. self = [self initType:nt name:n value:v];
  129. if( self )
  130. {
  131. [self postInitNamespaceHandling:nsURI];
  132. }
  133. return self;
  134. }
  135. #pragma mark - Official DOM method implementations
  136. -(Node *)firstChild
  137. {
  138. if( [self.childNodes length] < 1 )
  139. return nil;
  140. else
  141. return [self.childNodes item:0];
  142. }
  143. -(Node *)lastChild
  144. {
  145. if( [self.childNodes length] < 1 )
  146. return nil;
  147. else
  148. return [self.childNodes item: [self.childNodes length] - 1];
  149. }
  150. -(Node *)previousSibling
  151. {
  152. if( self.parentNode == nil )
  153. return nil;
  154. else
  155. {
  156. NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
  157. if( indexInParent < 1 )
  158. return nil;
  159. else
  160. return [self.parentNode.childNodes item:indexInParent-1];
  161. }
  162. }
  163. -(Node *)nextSibling
  164. {
  165. if( self.parentNode == nil )
  166. return nil;
  167. else
  168. {
  169. NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
  170. if( indexInParent >= [self.parentNode.childNodes length] )
  171. return nil;
  172. else
  173. return [self.parentNode.childNodes item:indexInParent + 1];
  174. }
  175. }
  176. -(Node*) insertBefore:(Node*) newChild refChild:(Node*) refChild
  177. {
  178. if( refChild == nil )
  179. {
  180. [self.childNodes.internalArray addObject:newChild];
  181. newChild.parentNode = self;
  182. }
  183. else
  184. {
  185. [self.childNodes.internalArray insertObject:newChild atIndex:[self.childNodes.internalArray indexOfObject:refChild]];
  186. }
  187. return newChild;
  188. }
  189. -(Node*) replaceChild:(Node*) newChild oldChild:(Node*) oldChild
  190. {
  191. if( newChild.nodeType == DOMNodeType_DOCUMENT_FRAGMENT_NODE )
  192. {
  193. /** Spec:
  194. "If newChild is a DocumentFragment object, oldChild is replaced by all of the DocumentFragment children, which are inserted in the same order. If the newChild is already in the tree, it is first removed."
  195. */
  196. NSUInteger oldIndex = [self.childNodes.internalArray indexOfObject:oldChild];
  197. NSAssert( FALSE, @"We should be recursing down the tree to find 'newChild' at any location, and removing it - required by spec - but we have no convenience method for that search, yet" );
  198. for( Node* child in newChild.childNodes.internalArray )
  199. {
  200. [self.childNodes.internalArray insertObject:child atIndex:oldIndex++];
  201. }
  202. newChild.parentNode = self;
  203. oldChild.parentNode = nil;
  204. return oldChild;
  205. }
  206. else
  207. {
  208. [self.childNodes.internalArray replaceObjectAtIndex:[self.childNodes.internalArray indexOfObject:oldChild] withObject:newChild];
  209. newChild.parentNode = self;
  210. oldChild.parentNode = nil;
  211. return oldChild;
  212. }
  213. }
  214. -(Node*) removeChild:(Node*) oldChild
  215. {
  216. [self.childNodes.internalArray removeObject:oldChild];
  217. oldChild.parentNode = nil;
  218. return oldChild;
  219. }
  220. -(Node*) appendChild:(Node*) newChild
  221. {
  222. [self.childNodes.internalArray removeObject:newChild]; // required by spec
  223. [self.childNodes.internalArray addObject:newChild];
  224. newChild.parentNode = self;
  225. return newChild;
  226. }
  227. -(BOOL)hasChildNodes
  228. {
  229. return (self.childNodes.length > 0);
  230. }
  231. -(Node*) cloneNode:(BOOL) deep
  232. {
  233. NSAssert( FALSE, @"Not implemented yet - read the spec. Sounds tricky. I'm too tired, and would probably screw it up right now" );
  234. return nil;
  235. }
  236. // Modified in DOM Level 2:
  237. -(void) normalize
  238. {
  239. NSAssert( FALSE, @"Not implemented yet - read the spec. Sounds tricky. I'm too tired, and would probably screw it up right now" );
  240. }
  241. // Introduced in DOM Level 2:
  242. -(BOOL) isSupportedFeature:(NSString*) feature version:(NSString*) version
  243. {
  244. NSAssert( FALSE, @"Not implemented yet - read the spec. I have literally no idea what this is supposed to do." );
  245. return FALSE;
  246. }
  247. // Introduced in DOM Level 2:
  248. @synthesize namespaceURI;
  249. // Introduced in DOM Level 2:
  250. @synthesize prefix;
  251. // Introduced in DOM Level 2:
  252. -(BOOL)hasAttributes
  253. {
  254. if( self.attributes == nil )
  255. return FALSE;
  256. return (self.attributes.length > 0 );
  257. }
  258. #pragma mark - SPECIAL CASE: DOM level 3 method
  259. /**
  260. Note that the DOM 3 spec defines this as RECURSIVE:
  261. http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
  262. */
  263. -(NSString *)textContent
  264. {
  265. switch( self.nodeType )
  266. {
  267. case DOMNodeType_ELEMENT_NODE:
  268. case DOMNodeType_ATTRIBUTE_NODE:
  269. case DOMNodeType_ENTITY_NODE:
  270. case DOMNodeType_ENTITY_REFERENCE_NODE:
  271. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  272. {
  273. /** DOM 3 Spec:
  274. "concatenation of the textContent attribute value of every child node, excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the empty string if the node has no children."
  275. */
  276. NSMutableString* stringAccumulator = [[NSMutableString alloc] init];
  277. for( Node* subNode in self.childNodes.internalArray )
  278. {
  279. NSString* subText = subNode.textContent; // don't call this method twice; it's expensive to calculate!
  280. if( subText != nil ) // Yes, really: Apple docs require that you never append a nil substring. Sigh
  281. [stringAccumulator appendString:subText];
  282. }
  283. return [NSString stringWithString:stringAccumulator];
  284. }
  285. case DOMNodeType_TEXT_NODE:
  286. case DOMNodeType_CDATA_SECTION_NODE:
  287. case DOMNodeType_COMMENT_NODE:
  288. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  289. {
  290. return self.nodeValue; // should never be nil; anything with a valid value will be at least an empty string i.e. ""
  291. }
  292. case DOMNodeType_DOCUMENT_NODE:
  293. case DOMNodeType_NOTATION_NODE:
  294. case DOMNodeType_DOCUMENT_TYPE_NODE:
  295. {
  296. return nil;
  297. }
  298. }
  299. }
  300. #pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
  301. -(NSString *)description
  302. {
  303. NSString* nodeTypeName;
  304. switch( self.nodeType )
  305. {
  306. case DOMNodeType_ELEMENT_NODE:
  307. nodeTypeName = @"ELEMENT";
  308. break;
  309. case DOMNodeType_TEXT_NODE:
  310. nodeTypeName = @"TEXT";
  311. break;
  312. case DOMNodeType_ENTITY_NODE:
  313. nodeTypeName = @"ENTITY";
  314. break;
  315. case DOMNodeType_COMMENT_NODE:
  316. nodeTypeName = @"COMMENT";
  317. break;
  318. case DOMNodeType_DOCUMENT_NODE:
  319. nodeTypeName = @"DOCUMENT";
  320. break;
  321. case DOMNodeType_NOTATION_NODE:
  322. nodeTypeName = @"NOTATION";
  323. break;
  324. case DOMNodeType_ATTRIBUTE_NODE:
  325. nodeTypeName = @"ATTRIBUTE";
  326. break;
  327. case DOMNodeType_CDATA_SECTION_NODE:
  328. nodeTypeName = @"CDATA";
  329. break;
  330. case DOMNodeType_DOCUMENT_TYPE_NODE:
  331. nodeTypeName = @"DOC TYPE";
  332. break;
  333. case DOMNodeType_ENTITY_REFERENCE_NODE:
  334. nodeTypeName = @"ENTITY REF";
  335. break;
  336. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  337. nodeTypeName = @"DOC FRAGMENT";
  338. break;
  339. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  340. nodeTypeName = @"PROCESSING INSTRUCTION";
  341. break;
  342. default:
  343. nodeTypeName = @"N/A (DATA IS MISSING FROM NODE INSTANCE)";
  344. }
  345. return [NSString stringWithFormat:@"Node: %@ (%@) value:[%@] @@%ld attributes + %ld x children", self.nodeName, nodeTypeName, [self.nodeValue length]<11 ? self.nodeValue : [NSString stringWithFormat:@"%@...",[self.nodeValue substringToIndex:10]], self.attributes.length, (unsigned long)self.childNodes.length];
  346. }
  347. #pragma mark - Objective-C serialization method to serialize a DOM tree back to XML (used heavily in SVGKit's output/conversion features)
  348. /** EXPERIMENTAL: not fully implemented or tested - this correctly outputs most SVG files, but is missing esoteric
  349. features such as EntityReferences, currently they are simply ignored
  350. This method should be used hand-in-hand with the proprietary SVGDocument method "allNamespaces" and the SVGSVGElement method "
  351. @param outputString an empty MUTABLE string we can accumulate with output (NB: this method uses a lot of memory, needs to accumulate data)
  352. @param prefixesByKNOWNNamespace (required): a dictionary mapping "XML namespace URI" to "prefix to use inside the xml-tags", e.g. "http://w3.org/2000/svg" usually is mapped to "svg" (or to "", signifying it's the default namespace). This MUST include ALL NAMESPACES FOUND IN THE DOCUMENT (it's recommended you use SVGDocument's "allPrefixesByNamespace" method, and some post-processing, to get an accurate input here)
  353. @param prefixesByACTIVENamespace (required): a mutable dictionary listing which elements of the other dictionary are active in-scope - i.e. which namespaces have been output by this node or a higher node in the tree. You pass-in an empty dictionary to the root SVG node and it fills it in as required.
  354. */
  355. -(void) appendXMLToString:(NSMutableString*) outputString availableNamespaces:(NSDictionary*) prefixesByKNOWNNamespace activeNamespaces:(NSMutableDictionary*) prefixesByACTIVENamespace
  356. {
  357. // NSAssert(namespaceShortnames != nil, @"Must supply an empty dictionary for me to fill with encountered namespaces, and the shortnames I invented for them!");
  358. /** Opening */
  359. switch( self.nodeType )
  360. {
  361. case DOMNodeType_ATTRIBUTE_NODE:
  362. {
  363. // ?
  364. }break;
  365. case DOMNodeType_CDATA_SECTION_NODE:
  366. {
  367. [outputString appendFormat:@"<!--"];
  368. }break;
  369. case DOMNodeType_COMMENT_NODE:
  370. {
  371. [outputString appendFormat:@"<![CDATA["];
  372. }break;
  373. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  374. case DOMNodeType_DOCUMENT_NODE:
  375. case DOMNodeType_ELEMENT_NODE:
  376. {
  377. [outputString appendFormat:@"<%@", self.nodeName];
  378. }break;
  379. case DOMNodeType_DOCUMENT_TYPE_NODE:
  380. case DOMNodeType_ENTITY_NODE:
  381. case DOMNodeType_ENTITY_REFERENCE_NODE:
  382. case DOMNodeType_NOTATION_NODE:
  383. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  384. case DOMNodeType_TEXT_NODE:
  385. {
  386. // ?
  387. }break;
  388. }
  389. /** ATTRIBUTES on the node (generally only applies to things of type "DOMNodeType_ELEMENT_NODE") */
  390. NSDictionary* nodeMapsByNamespace = [self.attributes allNodesUnsortedDOM2];
  391. NSMutableDictionary* newlyActivatedPrefixesByNamespace = [NSMutableDictionary dictionary];
  392. /**
  393. First, find all the attributes that declare a new Namespace at this point */
  394. NSString* xmlnsNamespace = @"http://www.w3.org/2000/xmlns/";
  395. NSDictionary* xmlnsNodemap = [nodeMapsByNamespace objectForKey:xmlnsNamespace];
  396. /** ... output them, making them 'active' in the output tree */
  397. for( NSString* xmlnsNodeName in xmlnsNodemap )
  398. {
  399. Node* attribute = [xmlnsNodemap objectForKey:xmlnsNodeName];
  400. if( [prefixesByACTIVENamespace objectForKey:xmlnsNodeName] == nil )
  401. {
  402. [newlyActivatedPrefixesByNamespace setObject:xmlnsNodeName forKey:attribute.nodeValue];
  403. if( xmlnsNodeName.length == 0 ) // special case: the "default" namespace we encode elsewhere in SVGKit as a namespace of ""
  404. [outputString appendFormat:@" xmlns=\"%@\"", attribute.nodeValue];
  405. else
  406. [outputString appendFormat:@" xmlns:%@=\"%@\"", xmlnsNodeName, attribute.nodeValue];
  407. }
  408. }
  409. /**
  410. Second, process "all" attributes, by namespace. Any time we find an attribute that "needs" a new
  411. namespace, we ACTIVATE it, and store it in the set of newly-activated namespaces.
  412. We will later replace our current "active" set with this new "active" set before we recurse to our
  413. child nodes
  414. */
  415. for( NSString* namespace in nodeMapsByNamespace )
  416. {
  417. if( [namespace isEqualToString:xmlnsNamespace] )
  418. continue; // we had to handle this FIRST, so we've already done it
  419. NSString* localPrefix = [prefixesByACTIVENamespace objectForKey:namespace];
  420. if( localPrefix == nil )
  421. {
  422. /** check if it's one of our freshly-activated ones */
  423. localPrefix = [newlyActivatedPrefixesByNamespace objectForKey:namespace];
  424. }
  425. if( localPrefix == nil )
  426. {
  427. /** If it STILL isn't active, (no parent Node has output it yet), we must activate it */
  428. localPrefix = [prefixesByKNOWNNamespace objectForKey:namespace];
  429. NSAssert( localPrefix != nil, @"Found a namespace (%@) in node (%@) which wasn't listed in the KNOWN namespaces you provided (%@); you MUST provide a COMPLETE list of known-namespaces to this method", namespace, self.nodeName, prefixesByKNOWNNamespace );
  430. [newlyActivatedPrefixesByNamespace setObject:localPrefix forKey:namespace];
  431. [outputString appendFormat:@" xmlns:%@=\"%@\"", localPrefix, namespace];
  432. }
  433. /** Finally: output the plain-old-attributes, overwriting their prefixes where necessary */
  434. NSDictionary* nodeMap = [nodeMapsByNamespace objectForKey:namespace];
  435. for( NSString* nodeNameFromMap in nodeMap )
  436. {
  437. Node* attribute = [nodeMap objectForKey:nodeNameFromMap];
  438. attribute.prefix = localPrefix; /** Overrides any default pre-existing value */
  439. [outputString appendFormat:@" %@=\"%@\"", attribute.nodeName, attribute.nodeValue];
  440. }
  441. }
  442. /** Post-processing: after ATTRIBUTES, we need to modify the "ACTIVE" set of namespaces we're passing-down
  443. to our child nodes
  444. Create a NEW dictionary to pass to our descendents, so that our ancestors don't get to see it
  445. */
  446. prefixesByACTIVENamespace = [NSMutableDictionary dictionaryWithDictionary:prefixesByACTIVENamespace];
  447. [prefixesByACTIVENamespace addEntriesFromDictionary:newlyActivatedPrefixesByNamespace];
  448. switch( self.nodeType )
  449. {
  450. case DOMNodeType_ATTRIBUTE_NODE:
  451. case DOMNodeType_CDATA_SECTION_NODE:
  452. case DOMNodeType_COMMENT_NODE:
  453. {
  454. // nothing
  455. }break;
  456. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  457. case DOMNodeType_DOCUMENT_NODE:
  458. case DOMNodeType_ELEMENT_NODE:
  459. {
  460. [outputString appendString:@">"];
  461. }break;
  462. case DOMNodeType_DOCUMENT_TYPE_NODE:
  463. case DOMNodeType_ENTITY_NODE:
  464. case DOMNodeType_ENTITY_REFERENCE_NODE:
  465. case DOMNodeType_NOTATION_NODE:
  466. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  467. case DOMNodeType_TEXT_NODE:
  468. {
  469. // nothing
  470. }break;
  471. }
  472. /** Middle: include child nodes (only applies to some nodes - others will have values, others will have simply "zero children") */
  473. switch( self.nodeType )
  474. {
  475. case DOMNodeType_ATTRIBUTE_NODE:
  476. case DOMNodeType_CDATA_SECTION_NODE:
  477. case DOMNodeType_COMMENT_NODE:
  478. case DOMNodeType_DOCUMENT_TYPE_NODE:
  479. case DOMNodeType_ENTITY_NODE:
  480. case DOMNodeType_ENTITY_REFERENCE_NODE:
  481. case DOMNodeType_NOTATION_NODE:
  482. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  483. case DOMNodeType_TEXT_NODE:
  484. {
  485. [outputString appendString:self.nodeValue];
  486. }break;
  487. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  488. case DOMNodeType_DOCUMENT_NODE:
  489. case DOMNodeType_ELEMENT_NODE:
  490. {
  491. for( Node* child in self.childNodes )
  492. {
  493. [child appendXMLToString:outputString availableNamespaces:prefixesByKNOWNNamespace activeNamespaces:prefixesByACTIVENamespace];
  494. }
  495. }break;
  496. }
  497. /** End: close any nodes that opened an XML tag, or an XML comment or CDATA, during Opening */
  498. switch( self.nodeType )
  499. {
  500. case DOMNodeType_ATTRIBUTE_NODE:
  501. {
  502. // nothing
  503. }break;
  504. case DOMNodeType_CDATA_SECTION_NODE:
  505. {
  506. [outputString appendFormat:@"-->"];
  507. }break;
  508. case DOMNodeType_COMMENT_NODE:
  509. {
  510. [outputString appendFormat:@"]]>"];
  511. }break;
  512. case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
  513. case DOMNodeType_DOCUMENT_NODE:
  514. case DOMNodeType_ELEMENT_NODE:
  515. {
  516. [outputString appendFormat:@"</%@>", self.nodeName];
  517. }break;
  518. case DOMNodeType_DOCUMENT_TYPE_NODE:
  519. case DOMNodeType_ENTITY_NODE:
  520. case DOMNodeType_ENTITY_REFERENCE_NODE:
  521. case DOMNodeType_NOTATION_NODE:
  522. case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
  523. case DOMNodeType_TEXT_NODE:
  524. {
  525. // nothing
  526. }break;
  527. }
  528. }
  529. @end