json2xml.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //copyright Ryan Day 2010 <http://ryanday.org>, Joscha Feth 2013 <http://www.feth.com> [MIT Licensed]
  2. var element_start_char =
  3. "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD";
  4. var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040";
  5. var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g");
  6. var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm;
  7. var objKeys = function (obj) {
  8. var l = [];
  9. if (obj instanceof Object) {
  10. for (var k in obj) {
  11. if (obj.hasOwnProperty(k)) {
  12. l.push(k);
  13. }
  14. }
  15. }
  16. return l;
  17. };
  18. var process_to_xml = function (node_data, options) {
  19. var makeNode = function (name, content, attributes, level, hasSubNodes) {
  20. var indent_value = options.indent !== undefined ? options.indent : "\t";
  21. var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : '';
  22. if (options.removeIllegalNameCharacters) {
  23. name = name.replace(element_replace, '_');
  24. }
  25. var node = [indent, '<', name, (attributes || '')];
  26. if (content && content.length > 0) {
  27. node.push('>')
  28. node.push(content);
  29. hasSubNodes && node.push(indent);
  30. node.push('</');
  31. node.push(name);
  32. node.push('>');
  33. } else {
  34. node.push('/>');
  35. }
  36. return node.join('');
  37. };
  38. return (function fn(node_data, node_descriptor, level) {
  39. var type = typeof node_data;
  40. if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) {
  41. type = 'array';
  42. } else if (node_data instanceof Date) {
  43. type = 'date';
  44. }
  45. switch (type) {
  46. //if value is an array create child nodes from values
  47. case 'array':
  48. var ret = [];
  49. node_data.map(function (v) {
  50. ret.push(fn(v, 1, level + 1));
  51. //entries that are values of an array are the only ones that can be special node descriptors
  52. });
  53. options.prettyPrint && ret.push('\n');
  54. return ret.join('');
  55. break;
  56. case 'date':
  57. // cast dates to ISO 8601 date (soap likes it)
  58. return node_data.toJSON ? node_data.toJSON() : node_data + '';
  59. break;
  60. case 'object':
  61. var nodes = [];
  62. for (var name in node_data) {
  63. if (node_data.hasOwnProperty(name)) {
  64. if (node_data[name] instanceof Array) {
  65. for (var j in node_data[name]) {
  66. if (node_data[name].hasOwnProperty(j))
  67. nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length));
  68. }
  69. } else {
  70. nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1));
  71. }
  72. }
  73. }
  74. options.prettyPrint && nodes.length > 0 && nodes.push('\n');
  75. return nodes.join('');
  76. break;
  77. case 'function':
  78. return node_data();
  79. break;
  80. default:
  81. return options.escape ? esc(node_data) : '' + node_data;
  82. }
  83. }(node_data, 0, 0))
  84. };
  85. var xml_header = function (standalone) {
  86. var ret = ['<?xml version="1.0" encoding="UTF-8"'];
  87. if (standalone) {
  88. ret.push(' standalone="yes"');
  89. }
  90. ret.push('?>');
  91. return ret.join('');
  92. };
  93. function esc(str) {
  94. return ('' + str).replace(/&/g, '&amp;')
  95. .replace(/</g, '&lt;')
  96. .replace(/>/g, '&gt;')
  97. .replace(/'/g, '&apos;')
  98. .replace(/"/g, '&quot;')
  99. .replace(not_safe_in_xml, '');
  100. }
  101. var json2xml = function (obj, options) {
  102. if (!options) {
  103. options = {
  104. xmlHeader: {
  105. standalone: true
  106. },
  107. prettyPrint: true,
  108. indent: " "
  109. };
  110. }
  111. if (typeof obj == 'string') {
  112. try {
  113. obj = JSON.parse(obj.toString());
  114. } catch (e) {
  115. return false;
  116. }
  117. }
  118. var xmlheader = '';
  119. var docType = '';
  120. if (options) {
  121. if (typeof options == 'object') {
  122. // our config is an object
  123. if (options.xmlHeader) {
  124. // the user wants an xml header
  125. xmlheader = xml_header(!!options.xmlHeader.standalone);
  126. }
  127. if (typeof options.docType != 'undefined') {
  128. docType = '<!DOCTYPE ' + options.docType + '>'
  129. }
  130. } else {
  131. // our config is a boolean value, so just add xml header
  132. xmlheader = xml_header();
  133. }
  134. }
  135. options = options || {}
  136. var ret = [
  137. xmlheader,
  138. (options.prettyPrint && docType ? '\n' : ''),
  139. docType,
  140. process_to_xml(obj, options)
  141. ];
  142. return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, '');
  143. };
  144. module.exports = json2xml;