XMLWriterBase.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. // Generated by CoffeeScript 2.4.1
  2. (function() {
  3. var NodeType, WriterState, XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLDummy, XMLElement, XMLProcessingInstruction, XMLRaw, XMLText, XMLWriterBase, assign,
  4. hasProp = {}.hasOwnProperty;
  5. ({assign} = require('./Utility'));
  6. NodeType = require('./NodeType');
  7. XMLDeclaration = require('./XMLDeclaration');
  8. XMLDocType = require('./XMLDocType');
  9. XMLCData = require('./XMLCData');
  10. XMLComment = require('./XMLComment');
  11. XMLElement = require('./XMLElement');
  12. XMLRaw = require('./XMLRaw');
  13. XMLText = require('./XMLText');
  14. XMLProcessingInstruction = require('./XMLProcessingInstruction');
  15. XMLDummy = require('./XMLDummy');
  16. XMLDTDAttList = require('./XMLDTDAttList');
  17. XMLDTDElement = require('./XMLDTDElement');
  18. XMLDTDEntity = require('./XMLDTDEntity');
  19. XMLDTDNotation = require('./XMLDTDNotation');
  20. WriterState = require('./WriterState');
  21. // Base class for XML writers
  22. module.exports = XMLWriterBase = class XMLWriterBase {
  23. // Initializes a new instance of `XMLWriterBase`
  24. // `options.pretty` pretty prints the result
  25. // `options.indent` indentation string
  26. // `options.newline` newline sequence
  27. // `options.offset` a fixed number of indentations to add to every line
  28. // `options.width` maximum column width
  29. // `options.allowEmpty` do not self close empty element tags
  30. // 'options.dontPrettyTextNodes' if any text is present in node, don't indent or LF
  31. // `options.spaceBeforeSlash` add a space before the closing slash of empty elements
  32. constructor(options) {
  33. var key, ref, value;
  34. options || (options = {});
  35. this.options = options;
  36. ref = options.writer || {};
  37. for (key in ref) {
  38. if (!hasProp.call(ref, key)) continue;
  39. value = ref[key];
  40. this["_" + key] = this[key];
  41. this[key] = value;
  42. }
  43. }
  44. // Filters writer options and provides defaults
  45. // `options` writer options
  46. filterOptions(options) {
  47. var filteredOptions, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7;
  48. options || (options = {});
  49. options = assign({}, this.options, options);
  50. filteredOptions = {
  51. writer: this
  52. };
  53. filteredOptions.pretty = options.pretty || false;
  54. filteredOptions.allowEmpty = options.allowEmpty || false;
  55. filteredOptions.indent = (ref = options.indent) != null ? ref : ' ';
  56. filteredOptions.newline = (ref1 = options.newline) != null ? ref1 : '\n';
  57. filteredOptions.offset = (ref2 = options.offset) != null ? ref2 : 0;
  58. filteredOptions.width = (ref3 = options.width) != null ? ref3 : 0;
  59. filteredOptions.dontPrettyTextNodes = (ref4 = (ref5 = options.dontPrettyTextNodes) != null ? ref5 : options.dontprettytextnodes) != null ? ref4 : 0;
  60. filteredOptions.spaceBeforeSlash = (ref6 = (ref7 = options.spaceBeforeSlash) != null ? ref7 : options.spacebeforeslash) != null ? ref6 : '';
  61. if (filteredOptions.spaceBeforeSlash === true) {
  62. filteredOptions.spaceBeforeSlash = ' ';
  63. }
  64. filteredOptions.suppressPrettyCount = 0;
  65. filteredOptions.user = {};
  66. filteredOptions.state = WriterState.None;
  67. return filteredOptions;
  68. }
  69. // Returns the indentation string for the current level
  70. // `node` current node
  71. // `options` writer options
  72. // `level` current indentation level
  73. indent(node, options, level) {
  74. var indentLevel;
  75. if (!options.pretty || options.suppressPrettyCount) {
  76. return '';
  77. } else if (options.pretty) {
  78. indentLevel = (level || 0) + options.offset + 1;
  79. if (indentLevel > 0) {
  80. return new Array(indentLevel).join(options.indent);
  81. }
  82. }
  83. return '';
  84. }
  85. // Returns the newline string
  86. // `node` current node
  87. // `options` writer options
  88. // `level` current indentation level
  89. endline(node, options, level) {
  90. if (!options.pretty || options.suppressPrettyCount) {
  91. return '';
  92. } else {
  93. return options.newline;
  94. }
  95. }
  96. attribute(att, options, level) {
  97. var r;
  98. this.openAttribute(att, options, level);
  99. if (options.pretty && options.width > 0) {
  100. r = att.name + '="' + att.value + '"';
  101. } else {
  102. r = ' ' + att.name + '="' + att.value + '"';
  103. }
  104. this.closeAttribute(att, options, level);
  105. return r;
  106. }
  107. cdata(node, options, level) {
  108. var r;
  109. this.openNode(node, options, level);
  110. options.state = WriterState.OpenTag;
  111. r = this.indent(node, options, level) + '<![CDATA[';
  112. options.state = WriterState.InsideTag;
  113. r += node.value;
  114. options.state = WriterState.CloseTag;
  115. r += ']]>' + this.endline(node, options, level);
  116. options.state = WriterState.None;
  117. this.closeNode(node, options, level);
  118. return r;
  119. }
  120. comment(node, options, level) {
  121. var r;
  122. this.openNode(node, options, level);
  123. options.state = WriterState.OpenTag;
  124. r = this.indent(node, options, level) + '<!-- ';
  125. options.state = WriterState.InsideTag;
  126. r += node.value;
  127. options.state = WriterState.CloseTag;
  128. r += ' -->' + this.endline(node, options, level);
  129. options.state = WriterState.None;
  130. this.closeNode(node, options, level);
  131. return r;
  132. }
  133. declaration(node, options, level) {
  134. var r;
  135. this.openNode(node, options, level);
  136. options.state = WriterState.OpenTag;
  137. r = this.indent(node, options, level) + '<?xml';
  138. options.state = WriterState.InsideTag;
  139. r += ' version="' + node.version + '"';
  140. if (node.encoding != null) {
  141. r += ' encoding="' + node.encoding + '"';
  142. }
  143. if (node.standalone != null) {
  144. r += ' standalone="' + node.standalone + '"';
  145. }
  146. options.state = WriterState.CloseTag;
  147. r += options.spaceBeforeSlash + '?>';
  148. r += this.endline(node, options, level);
  149. options.state = WriterState.None;
  150. this.closeNode(node, options, level);
  151. return r;
  152. }
  153. docType(node, options, level) {
  154. var child, i, len1, r, ref;
  155. level || (level = 0);
  156. this.openNode(node, options, level);
  157. options.state = WriterState.OpenTag;
  158. r = this.indent(node, options, level);
  159. r += '<!DOCTYPE ' + node.root().name;
  160. // external identifier
  161. if (node.pubID && node.sysID) {
  162. r += ' PUBLIC "' + node.pubID + '" "' + node.sysID + '"';
  163. } else if (node.sysID) {
  164. r += ' SYSTEM "' + node.sysID + '"';
  165. }
  166. // internal subset
  167. if (node.children.length > 0) {
  168. r += ' [';
  169. r += this.endline(node, options, level);
  170. options.state = WriterState.InsideTag;
  171. ref = node.children;
  172. for (i = 0, len1 = ref.length; i < len1; i++) {
  173. child = ref[i];
  174. r += this.writeChildNode(child, options, level + 1);
  175. }
  176. options.state = WriterState.CloseTag;
  177. r += ']';
  178. }
  179. // close tag
  180. options.state = WriterState.CloseTag;
  181. r += options.spaceBeforeSlash + '>';
  182. r += this.endline(node, options, level);
  183. options.state = WriterState.None;
  184. this.closeNode(node, options, level);
  185. return r;
  186. }
  187. element(node, options, level) {
  188. var att, attLen, child, childNodeCount, firstChildNode, i, j, len, len1, len2, name, prettySuppressed, r, ratt, ref, ref1, ref2, ref3, rline;
  189. level || (level = 0);
  190. prettySuppressed = false;
  191. // open tag
  192. this.openNode(node, options, level);
  193. options.state = WriterState.OpenTag;
  194. r = this.indent(node, options, level) + '<' + node.name;
  195. // attributes
  196. if (options.pretty && options.width > 0) {
  197. len = r.length;
  198. ref = node.attribs;
  199. for (name in ref) {
  200. if (!hasProp.call(ref, name)) continue;
  201. att = ref[name];
  202. ratt = this.attribute(att, options, level);
  203. attLen = ratt.length;
  204. if (len + attLen > options.width) {
  205. rline = this.indent(node, options, level + 1) + ratt;
  206. r += this.endline(node, options, level) + rline;
  207. len = rline.length;
  208. } else {
  209. rline = ' ' + ratt;
  210. r += rline;
  211. len += rline.length;
  212. }
  213. }
  214. } else {
  215. ref1 = node.attribs;
  216. for (name in ref1) {
  217. if (!hasProp.call(ref1, name)) continue;
  218. att = ref1[name];
  219. r += this.attribute(att, options, level);
  220. }
  221. }
  222. childNodeCount = node.children.length;
  223. firstChildNode = childNodeCount === 0 ? null : node.children[0];
  224. if (childNodeCount === 0 || node.children.every(function(e) {
  225. return (e.type === NodeType.Text || e.type === NodeType.Raw || e.type === NodeType.CData) && e.value === '';
  226. })) {
  227. // empty element
  228. if (options.allowEmpty) {
  229. r += '>';
  230. options.state = WriterState.CloseTag;
  231. r += '</' + node.name + '>' + this.endline(node, options, level);
  232. } else {
  233. options.state = WriterState.CloseTag;
  234. r += options.spaceBeforeSlash + '/>' + this.endline(node, options, level);
  235. }
  236. } else if (options.pretty && childNodeCount === 1 && (firstChildNode.type === NodeType.Text || firstChildNode.type === NodeType.Raw || firstChildNode.type === NodeType.CData) && (firstChildNode.value != null)) {
  237. // do not indent text-only nodes
  238. r += '>';
  239. options.state = WriterState.InsideTag;
  240. options.suppressPrettyCount++;
  241. prettySuppressed = true;
  242. r += this.writeChildNode(firstChildNode, options, level + 1);
  243. options.suppressPrettyCount--;
  244. prettySuppressed = false;
  245. options.state = WriterState.CloseTag;
  246. r += '</' + node.name + '>' + this.endline(node, options, level);
  247. } else {
  248. // if ANY are a text node, then suppress pretty now
  249. if (options.dontPrettyTextNodes) {
  250. ref2 = node.children;
  251. for (i = 0, len1 = ref2.length; i < len1; i++) {
  252. child = ref2[i];
  253. if ((child.type === NodeType.Text || child.type === NodeType.Raw || child.type === NodeType.CData) && (child.value != null)) {
  254. options.suppressPrettyCount++;
  255. prettySuppressed = true;
  256. break;
  257. }
  258. }
  259. }
  260. // close the opening tag, after dealing with newline
  261. r += '>' + this.endline(node, options, level);
  262. options.state = WriterState.InsideTag;
  263. ref3 = node.children;
  264. // inner tags
  265. for (j = 0, len2 = ref3.length; j < len2; j++) {
  266. child = ref3[j];
  267. r += this.writeChildNode(child, options, level + 1);
  268. }
  269. // close tag
  270. options.state = WriterState.CloseTag;
  271. r += this.indent(node, options, level) + '</' + node.name + '>';
  272. if (prettySuppressed) {
  273. options.suppressPrettyCount--;
  274. }
  275. r += this.endline(node, options, level);
  276. options.state = WriterState.None;
  277. }
  278. this.closeNode(node, options, level);
  279. return r;
  280. }
  281. writeChildNode(node, options, level) {
  282. switch (node.type) {
  283. case NodeType.CData:
  284. return this.cdata(node, options, level);
  285. case NodeType.Comment:
  286. return this.comment(node, options, level);
  287. case NodeType.Element:
  288. return this.element(node, options, level);
  289. case NodeType.Raw:
  290. return this.raw(node, options, level);
  291. case NodeType.Text:
  292. return this.text(node, options, level);
  293. case NodeType.ProcessingInstruction:
  294. return this.processingInstruction(node, options, level);
  295. case NodeType.Dummy:
  296. return '';
  297. case NodeType.Declaration:
  298. return this.declaration(node, options, level);
  299. case NodeType.DocType:
  300. return this.docType(node, options, level);
  301. case NodeType.AttributeDeclaration:
  302. return this.dtdAttList(node, options, level);
  303. case NodeType.ElementDeclaration:
  304. return this.dtdElement(node, options, level);
  305. case NodeType.EntityDeclaration:
  306. return this.dtdEntity(node, options, level);
  307. case NodeType.NotationDeclaration:
  308. return this.dtdNotation(node, options, level);
  309. default:
  310. throw new Error("Unknown XML node type: " + node.constructor.name);
  311. }
  312. }
  313. processingInstruction(node, options, level) {
  314. var r;
  315. this.openNode(node, options, level);
  316. options.state = WriterState.OpenTag;
  317. r = this.indent(node, options, level) + '<?';
  318. options.state = WriterState.InsideTag;
  319. r += node.target;
  320. if (node.value) {
  321. r += ' ' + node.value;
  322. }
  323. options.state = WriterState.CloseTag;
  324. r += options.spaceBeforeSlash + '?>';
  325. r += this.endline(node, options, level);
  326. options.state = WriterState.None;
  327. this.closeNode(node, options, level);
  328. return r;
  329. }
  330. raw(node, options, level) {
  331. var r;
  332. this.openNode(node, options, level);
  333. options.state = WriterState.OpenTag;
  334. r = this.indent(node, options, level);
  335. options.state = WriterState.InsideTag;
  336. r += node.value;
  337. options.state = WriterState.CloseTag;
  338. r += this.endline(node, options, level);
  339. options.state = WriterState.None;
  340. this.closeNode(node, options, level);
  341. return r;
  342. }
  343. text(node, options, level) {
  344. var r;
  345. this.openNode(node, options, level);
  346. options.state = WriterState.OpenTag;
  347. r = this.indent(node, options, level);
  348. options.state = WriterState.InsideTag;
  349. r += node.value;
  350. options.state = WriterState.CloseTag;
  351. r += this.endline(node, options, level);
  352. options.state = WriterState.None;
  353. this.closeNode(node, options, level);
  354. return r;
  355. }
  356. dtdAttList(node, options, level) {
  357. var r;
  358. this.openNode(node, options, level);
  359. options.state = WriterState.OpenTag;
  360. r = this.indent(node, options, level) + '<!ATTLIST';
  361. options.state = WriterState.InsideTag;
  362. r += ' ' + node.elementName + ' ' + node.attributeName + ' ' + node.attributeType;
  363. if (node.defaultValueType !== '#DEFAULT') {
  364. r += ' ' + node.defaultValueType;
  365. }
  366. if (node.defaultValue) {
  367. r += ' "' + node.defaultValue + '"';
  368. }
  369. options.state = WriterState.CloseTag;
  370. r += options.spaceBeforeSlash + '>' + this.endline(node, options, level);
  371. options.state = WriterState.None;
  372. this.closeNode(node, options, level);
  373. return r;
  374. }
  375. dtdElement(node, options, level) {
  376. var r;
  377. this.openNode(node, options, level);
  378. options.state = WriterState.OpenTag;
  379. r = this.indent(node, options, level) + '<!ELEMENT';
  380. options.state = WriterState.InsideTag;
  381. r += ' ' + node.name + ' ' + node.value;
  382. options.state = WriterState.CloseTag;
  383. r += options.spaceBeforeSlash + '>' + this.endline(node, options, level);
  384. options.state = WriterState.None;
  385. this.closeNode(node, options, level);
  386. return r;
  387. }
  388. dtdEntity(node, options, level) {
  389. var r;
  390. this.openNode(node, options, level);
  391. options.state = WriterState.OpenTag;
  392. r = this.indent(node, options, level) + '<!ENTITY';
  393. options.state = WriterState.InsideTag;
  394. if (node.pe) {
  395. r += ' %';
  396. }
  397. r += ' ' + node.name;
  398. if (node.value) {
  399. r += ' "' + node.value + '"';
  400. } else {
  401. if (node.pubID && node.sysID) {
  402. r += ' PUBLIC "' + node.pubID + '" "' + node.sysID + '"';
  403. } else if (node.sysID) {
  404. r += ' SYSTEM "' + node.sysID + '"';
  405. }
  406. if (node.nData) {
  407. r += ' NDATA ' + node.nData;
  408. }
  409. }
  410. options.state = WriterState.CloseTag;
  411. r += options.spaceBeforeSlash + '>' + this.endline(node, options, level);
  412. options.state = WriterState.None;
  413. this.closeNode(node, options, level);
  414. return r;
  415. }
  416. dtdNotation(node, options, level) {
  417. var r;
  418. this.openNode(node, options, level);
  419. options.state = WriterState.OpenTag;
  420. r = this.indent(node, options, level) + '<!NOTATION';
  421. options.state = WriterState.InsideTag;
  422. r += ' ' + node.name;
  423. if (node.pubID && node.sysID) {
  424. r += ' PUBLIC "' + node.pubID + '" "' + node.sysID + '"';
  425. } else if (node.pubID) {
  426. r += ' PUBLIC "' + node.pubID + '"';
  427. } else if (node.sysID) {
  428. r += ' SYSTEM "' + node.sysID + '"';
  429. }
  430. options.state = WriterState.CloseTag;
  431. r += options.spaceBeforeSlash + '>' + this.endline(node, options, level);
  432. options.state = WriterState.None;
  433. this.closeNode(node, options, level);
  434. return r;
  435. }
  436. openNode(node, options, level) {}
  437. closeNode(node, options, level) {}
  438. openAttribute(att, options, level) {}
  439. closeAttribute(att, options, level) {}
  440. };
  441. }).call(this);