find-tag-by-name.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. const indexOfMatch = require("./index-of-match.js");
  2. const indexOfMatchEnd = require("./index-of-match-end.js");
  3. const countSubstring = require("./count-substring.js");
  4. function findTagByName(xml, tagName, options) {
  5. const debug = (options && options.debug) || false;
  6. const nested = !(options && typeof options.nested === false);
  7. const startIndex = (options && options.startIndex) || 0;
  8. if (debug) console.log("[xml-utils] starting findTagByName with", tagName, " and ", options);
  9. const start = indexOfMatch(xml, `\<${tagName}[ \>\/]`, startIndex);
  10. if (debug) console.log("[xml-utils] start:", start);
  11. if (start === -1) return undefined;
  12. const afterStart = xml.slice(start + tagName.length);
  13. let relativeEnd = indexOfMatchEnd(afterStart, "^[^<]*[ /]>", 0);
  14. const selfClosing = relativeEnd !== -1 && afterStart[relativeEnd - 1] === "/";
  15. if (debug) console.log("[xml-utils] selfClosing:", selfClosing);
  16. if (selfClosing === false) {
  17. // check if tag has subtags with the same name
  18. if (nested) {
  19. let startIndex = 0;
  20. let openings = 1;
  21. let closings = 0;
  22. while ((relativeEnd = indexOfMatchEnd(afterStart, "[ /]" + tagName + ">", startIndex)) !== -1) {
  23. const clip = afterStart.substring(startIndex, relativeEnd + 1);
  24. openings += countSubstring(clip, "<" + tagName);
  25. closings += countSubstring(clip, "/" + tagName + ">");
  26. // we can't have more openings than closings
  27. if (closings >= openings) break;
  28. startIndex = relativeEnd;
  29. }
  30. } else {
  31. relativeEnd = indexOfMatchEnd(afterStart, "[ /]" + tagName + ">", 0);
  32. }
  33. }
  34. const end = start + tagName.length + relativeEnd + 1;
  35. if (debug) console.log("[xml-utils] end:", end);
  36. if (end === -1) return undefined;
  37. const outer = xml.slice(start, end);
  38. // tag is like <gml:identifier codeSpace="OGP">urn:ogc:def:crs:EPSG::32617</gml:identifier>
  39. let inner;
  40. if (selfClosing) {
  41. inner = null;
  42. } else {
  43. inner = outer.slice(outer.indexOf(">") + 1, outer.lastIndexOf("<"));
  44. }
  45. return { inner, outer, start, end };
  46. }
  47. module.exports = findTagByName;
  48. module.exports.default = findTagByName;