dom_util.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import { Engine, SREError } from './engine.js';
  2. import * as EngineConst from '../common/engine_const.js';
  3. import { SystemExternal } from './system_external.js';
  4. import * as XpathUtil from './xpath_util.js';
  5. export function toArray(nodeList) {
  6. const nodeArray = [];
  7. for (let i = 0, m = nodeList.length; i < m; i++) {
  8. nodeArray.push(nodeList[i]);
  9. }
  10. return nodeArray;
  11. }
  12. function trimInput(input) {
  13. input = input.replace(/&nbsp;/g, ' ');
  14. return input.replace(/>[ \f\n\r\t\v\u200b]+</g, '><').trim();
  15. }
  16. export function parseInput(input) {
  17. const dp = new SystemExternal.xmldom.DOMParser();
  18. const clean_input = trimInput(input);
  19. const allValues = clean_input.match(/&(?!lt|gt|amp|quot|apos)\w+;/g);
  20. const html = !!allValues;
  21. if (!clean_input) {
  22. throw new Error('Empty input!');
  23. }
  24. try {
  25. const doc = dp.parseFromString(clean_input, html ? 'text/html' : 'text/xml');
  26. if (Engine.getInstance().mode === EngineConst.Mode.HTTP) {
  27. XpathUtil.xpath.currentDocument = doc;
  28. return html ? doc.body.childNodes[0] : doc.documentElement;
  29. }
  30. return doc.documentElement;
  31. }
  32. catch (err) {
  33. throw new SREError('Illegal input: ' + err.message);
  34. }
  35. }
  36. export var NodeType;
  37. (function (NodeType) {
  38. NodeType[NodeType["ELEMENT_NODE"] = 1] = "ELEMENT_NODE";
  39. NodeType[NodeType["ATTRIBUTE_NODE"] = 2] = "ATTRIBUTE_NODE";
  40. NodeType[NodeType["TEXT_NODE"] = 3] = "TEXT_NODE";
  41. NodeType[NodeType["CDATA_SECTION_NODE"] = 4] = "CDATA_SECTION_NODE";
  42. NodeType[NodeType["ENTITY_REFERENCE_NODE"] = 5] = "ENTITY_REFERENCE_NODE";
  43. NodeType[NodeType["ENTITY_NODE"] = 6] = "ENTITY_NODE";
  44. NodeType[NodeType["PROCESSING_INSTRUCTION_NODE"] = 7] = "PROCESSING_INSTRUCTION_NODE";
  45. NodeType[NodeType["COMMENT_NODE"] = 8] = "COMMENT_NODE";
  46. NodeType[NodeType["DOCUMENT_NODE"] = 9] = "DOCUMENT_NODE";
  47. NodeType[NodeType["DOCUMENT_TYPE_NODE"] = 10] = "DOCUMENT_TYPE_NODE";
  48. NodeType[NodeType["DOCUMENT_FRAGMENT_NODE"] = 11] = "DOCUMENT_FRAGMENT_NODE";
  49. NodeType[NodeType["NOTATION_NODE"] = 12] = "NOTATION_NODE";
  50. })(NodeType || (NodeType = {}));
  51. export function replaceNode(oldNode, newNode) {
  52. if (!oldNode.parentNode) {
  53. return;
  54. }
  55. oldNode.parentNode.insertBefore(newNode, oldNode);
  56. oldNode.parentNode.removeChild(oldNode);
  57. }
  58. export function createElement(tag) {
  59. return SystemExternal.document.createElement(tag);
  60. }
  61. export function createElementNS(url, tag) {
  62. return SystemExternal.document.createElementNS(url, tag);
  63. }
  64. export function createTextNode(content) {
  65. return SystemExternal.document.createTextNode(content);
  66. }
  67. export function formatXml(xml) {
  68. let formatted = '';
  69. let reg = /(>)(<)(\/*)/g;
  70. xml = xml.replace(reg, '$1\r\n$2$3');
  71. let pad = 0;
  72. let split = xml.split('\r\n');
  73. reg = /(\.)*(<)(\/*)/g;
  74. split = split
  75. .map((x) => x.replace(reg, '$1\r\n$2$3').split('\r\n'))
  76. .reduce((x, y) => x.concat(y), []);
  77. while (split.length) {
  78. let node = split.shift();
  79. if (!node) {
  80. continue;
  81. }
  82. let indent = 0;
  83. if (node.match(/^<\w[^>/]*>[^>]+$/)) {
  84. const match = matchingStartEnd(node, split[0]);
  85. if (match[0]) {
  86. if (match[1]) {
  87. node = node + split.shift().slice(0, -match[1].length);
  88. if (match[1].trim()) {
  89. split.unshift(match[1]);
  90. }
  91. }
  92. else {
  93. node = node + split.shift();
  94. }
  95. }
  96. else {
  97. indent = 1;
  98. }
  99. }
  100. else if (node.match(/^<\/\w/)) {
  101. if (pad !== 0) {
  102. pad -= 1;
  103. }
  104. }
  105. else if (node.match(/^<\w[^>]*[^/]>.*$/)) {
  106. indent = 1;
  107. }
  108. else if (node.match(/^<\w[^>]*\/>.+$/)) {
  109. const position = node.indexOf('>') + 1;
  110. const rest = node.slice(position);
  111. if (rest.trim()) {
  112. split.unshift();
  113. }
  114. node = node.slice(0, position) + rest;
  115. }
  116. else {
  117. indent = 0;
  118. }
  119. formatted += new Array(pad + 1).join(' ') + node + '\r\n';
  120. pad += indent;
  121. }
  122. return formatted;
  123. }
  124. function matchingStartEnd(start, end) {
  125. if (!end) {
  126. return [false, ''];
  127. }
  128. const tag1 = start.match(/^<([^> ]+).*>/);
  129. const tag2 = end.match(/^<\/([^>]+)>(.*)/);
  130. return tag1 && tag2 && tag1[1] === tag2[1] ? [true, tag2[2]] : [false, ''];
  131. }
  132. export function querySelectorAllByAttr(node, attr) {
  133. return node.querySelectorAll
  134. ? toArray(node.querySelectorAll(`[${attr}]`))
  135. : XpathUtil.evalXPath(`.//*[@${attr}]`, node);
  136. }
  137. export function querySelectorAllByAttrValue(node, attr, value) {
  138. return node.querySelectorAll
  139. ? toArray(node.querySelectorAll(`[${attr}="${value}"]`))
  140. : XpathUtil.evalXPath(`.//*[@${attr}="${value}"]`, node);
  141. }
  142. export function querySelectorAll(node, tag) {
  143. return node.querySelectorAll
  144. ? toArray(node.querySelectorAll(tag))
  145. : XpathUtil.evalXPath(`.//${tag}`, node);
  146. }
  147. export function tagName(node) {
  148. return node.tagName.toUpperCase();
  149. }
  150. export function cloneNode(node) {
  151. return node.cloneNode(true);
  152. }
  153. export function serializeXml(node) {
  154. const xmls = new SystemExternal.xmldom.XMLSerializer();
  155. return xmls.serializeToString(node);
  156. }