xml-writer.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. Copyright 2012-2015, Yahoo Inc.
  3. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  4. */
  5. const INDENT = ' ';
  6. /**
  7. * a utility class to produce well-formed, indented XML
  8. * @param {ContentWriter} contentWriter the content writer that this utility wraps
  9. * @constructor
  10. */
  11. function XMLWriter(contentWriter) {
  12. this.cw = contentWriter;
  13. this.stack = [];
  14. }
  15. function attrString(attrs) {
  16. if (!attrs) {
  17. return '';
  18. }
  19. const ret = [];
  20. Object.keys(attrs).forEach(k => {
  21. const v = attrs[k];
  22. ret.push(k + '="' + v + '"');
  23. });
  24. return ret.length === 0 ? '' : ' ' + ret.join(' ');
  25. }
  26. XMLWriter.prototype.indent = function(str) {
  27. return this.stack.map(() => INDENT).join('') + str;
  28. };
  29. /**
  30. * writes the opening XML tag with the supplied attributes
  31. * @param {String} name tag name
  32. * @param {Object} [attrs=null] attrs attributes for the tag
  33. */
  34. XMLWriter.prototype.openTag = function(name, attrs) {
  35. const str = this.indent('<' + name + attrString(attrs) + '>');
  36. this.cw.println(str);
  37. this.stack.push(name);
  38. };
  39. /**
  40. * closes an open XML tag.
  41. * @param {String} name - tag name to close. This must match the writer's
  42. * notion of the tag that is currently open.
  43. */
  44. XMLWriter.prototype.closeTag = function(name) {
  45. if (this.stack.length === 0) {
  46. throw new Error('Attempt to close tag ' + name + ' when not opened');
  47. }
  48. const stashed = this.stack.pop();
  49. const str = '</' + name + '>';
  50. if (stashed !== name) {
  51. throw new Error(
  52. 'Attempt to close tag ' +
  53. name +
  54. ' when ' +
  55. stashed +
  56. ' was the one open'
  57. );
  58. }
  59. this.cw.println(this.indent(str));
  60. };
  61. /**
  62. * writes a tag and its value opening and closing it at the same time
  63. * @param {String} name tag name
  64. * @param {Object} [attrs=null] attrs tag attributes
  65. * @param {String} [content=null] content optional tag content
  66. */
  67. XMLWriter.prototype.inlineTag = function(name, attrs, content) {
  68. let str = '<' + name + attrString(attrs);
  69. if (content) {
  70. str += '>' + content + '</' + name + '>';
  71. } else {
  72. str += '/>';
  73. }
  74. str = this.indent(str);
  75. this.cw.println(str);
  76. };
  77. /**
  78. * closes all open tags and ends the document
  79. */
  80. XMLWriter.prototype.closeAll = function() {
  81. this.stack
  82. .slice()
  83. .reverse()
  84. .forEach(name => {
  85. this.closeTag(name);
  86. });
  87. };
  88. module.exports = XMLWriter;