xmlParser.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. const sax = require('./sax');
  2. function formatXml(xmlParsed, encoding = 'utf-8', textFilterFunc) {
  3. let out = `<?xml version="1.0" encoding="${encoding}"?>`;
  4. out += formatXmlNode(xmlParsed, textFilterFunc);
  5. return out;
  6. }
  7. function formatXmlNode(node, textFilterFunc) {
  8. textFilterFunc = (textFilterFunc ? textFilterFunc : text => text);
  9. const formatNode = (node, name) => {
  10. let out = '';
  11. if (Array.isArray(node)) {
  12. for (const n of node) {
  13. out += formatNode(n);
  14. }
  15. } else if (typeof node == 'string') {
  16. if (name)
  17. out += `<${name}>${textFilterFunc(node)}</${name}>`;
  18. else
  19. out += textFilterFunc(node);
  20. } else {
  21. if (node._n)
  22. name = node._n;
  23. let attrs = '';
  24. if (node._attrs) {
  25. for (let attrName in node._attrs) {
  26. attrs += ` ${attrName}="${node._attrs[attrName]}"`;
  27. }
  28. }
  29. let tOpen = '';
  30. let tBody = '';
  31. let tClose = '';
  32. if (name)
  33. tOpen += `<${name}${attrs}>`;
  34. if (node.hasOwnProperty('_t'))
  35. tBody += textFilterFunc(node._t);
  36. for (let nodeName in node) {
  37. if (nodeName && nodeName[0] == '_' && nodeName != '_a')
  38. continue;
  39. const n = node[nodeName];
  40. tBody += formatNode(n, nodeName);
  41. }
  42. if (name)
  43. tClose += `</${name}>`;
  44. out += `${tOpen}${tBody}${tClose}`;
  45. }
  46. return out;
  47. }
  48. return formatNode(node);
  49. }
  50. function parseXml(xmlString, lowerCase = true) {
  51. let result = {};
  52. let node = result;
  53. const onTextNode = (text, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
  54. node._t = text;
  55. };
  56. const onStartNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
  57. if (tag == '?xml')
  58. return;
  59. const newNode = {_n: tag, _p: node};
  60. if (tail) {
  61. const parsedAttrs = sax.getAttrsSync(tail, lowerCase);
  62. const atKeys = Object.keys(parsedAttrs);
  63. if (atKeys.length) {
  64. const attrs = {};
  65. for (let i = 0; i < atKeys.length; i++) {
  66. const attrName = atKeys[i];
  67. attrs[parsedAttrs[attrName].fn] = parsedAttrs[attrName].value;
  68. }
  69. newNode._attrs = attrs;
  70. }
  71. }
  72. if (!node._a)
  73. node._a = [];
  74. node._a.push(newNode);
  75. node = newNode;
  76. };
  77. const onEndNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
  78. if (node._p && node._n == tag)
  79. node = node._p;
  80. };
  81. sax.parseSync(xmlString, {
  82. onStartNode, onEndNode, onTextNode, lowerCase
  83. });
  84. if (result._a)
  85. result = result._a[0];
  86. return result;
  87. }
  88. function simplifyXmlParsed(node) {
  89. const simplifyNodeArray = (a) => {
  90. const result = {};
  91. for (let i = 0; i < a.length; i++) {
  92. const child = a[i];
  93. if (child._n && !result[child._n]) {
  94. result[child._n] = {};
  95. if (child._a) {
  96. result[child._n] = simplifyNodeArray(child._a);
  97. }
  98. if (child._t) {
  99. result[child._n]._t = child._t;
  100. }
  101. if (child._attrs) {
  102. result[child._n]._attrs = child._attrs;
  103. }
  104. }
  105. }
  106. return result;
  107. };
  108. return simplifyNodeArray([node]);
  109. }
  110. module.exports = {
  111. formatXml,
  112. formatXmlNode,
  113. parseXml,
  114. simplifyXmlParsed
  115. }