saxen.umd.js 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (factory((global.Saxen = {})));
  5. }(this, (function (exports) { 'use strict';
  6. var fromCharCode = String.fromCharCode;
  7. var hasOwnProperty = Object.prototype.hasOwnProperty;
  8. var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
  9. var ENTITY_MAPPING = {
  10. 'amp': '&',
  11. 'apos': '\'',
  12. 'gt': '>',
  13. 'lt': '<',
  14. 'quot': '"'
  15. };
  16. // map UPPERCASE variants of supported special chars
  17. Object.keys(ENTITY_MAPPING).forEach(function(k) {
  18. ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
  19. });
  20. function replaceEntities(_, d, x, z) {
  21. // reserved names, i.e. &nbsp;
  22. if (z) {
  23. if (hasOwnProperty.call(ENTITY_MAPPING, z)) {
  24. return ENTITY_MAPPING[z];
  25. } else {
  26. // fall back to original value
  27. return '&' + z + ';';
  28. }
  29. }
  30. // decimal encoded char
  31. if (d) {
  32. return fromCharCode(d);
  33. }
  34. // hex encoded char
  35. return fromCharCode(parseInt(x, 16));
  36. }
  37. /**
  38. * A basic entity decoder that can decode a minimal
  39. * sub-set of reserved names (&amp;) as well as
  40. * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
  41. *
  42. * @param {string} str
  43. *
  44. * @return {string} decoded string
  45. */
  46. function decodeEntities(s) {
  47. if (s.length > 3 && s.indexOf('&') !== -1) {
  48. return s.replace(ENTITY_PATTERN, replaceEntities);
  49. }
  50. return s;
  51. }
  52. var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
  53. var XSI_PREFIX = 'xsi';
  54. var XSI_TYPE = 'xsi:type';
  55. var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
  56. function error(msg) {
  57. return new Error(msg);
  58. }
  59. function missingNamespaceForPrefix(prefix) {
  60. return 'missing namespace for prefix <' + prefix + '>';
  61. }
  62. function getter(getFn) {
  63. return {
  64. 'get': getFn,
  65. 'enumerable': true
  66. };
  67. }
  68. function cloneNsMatrix(nsMatrix) {
  69. var clone = {}, key;
  70. for (key in nsMatrix) {
  71. clone[key] = nsMatrix[key];
  72. }
  73. return clone;
  74. }
  75. function uriPrefix(prefix) {
  76. return prefix + '$uri';
  77. }
  78. function buildNsMatrix(nsUriToPrefix) {
  79. var nsMatrix = {},
  80. uri,
  81. prefix;
  82. for (uri in nsUriToPrefix) {
  83. prefix = nsUriToPrefix[uri];
  84. nsMatrix[prefix] = prefix;
  85. nsMatrix[uriPrefix(prefix)] = uri;
  86. }
  87. return nsMatrix;
  88. }
  89. function noopGetContext() {
  90. return { 'line': 0, 'column': 0 };
  91. }
  92. function throwFunc(err) {
  93. throw err;
  94. }
  95. /**
  96. * Creates a new parser with the given options.
  97. *
  98. * @constructor
  99. *
  100. * @param {!Object<string, ?>=} options
  101. */
  102. function Parser(options) {
  103. if (!this) {
  104. return new Parser(options);
  105. }
  106. var proxy = options && options['proxy'];
  107. var onText,
  108. onOpenTag,
  109. onCloseTag,
  110. onCDATA,
  111. onError = throwFunc,
  112. onWarning,
  113. onComment,
  114. onQuestion,
  115. onAttention;
  116. var getContext = noopGetContext;
  117. /**
  118. * Do we need to parse the current elements attributes for namespaces?
  119. *
  120. * @type {boolean}
  121. */
  122. var maybeNS = false;
  123. /**
  124. * Do we process namespaces at all?
  125. *
  126. * @type {boolean}
  127. */
  128. var isNamespace = false;
  129. /**
  130. * The caught error returned on parse end
  131. *
  132. * @type {Error}
  133. */
  134. var returnError = null;
  135. /**
  136. * Should we stop parsing?
  137. *
  138. * @type {boolean}
  139. */
  140. var parseStop = false;
  141. /**
  142. * A map of { uri: prefix } used by the parser.
  143. *
  144. * This map will ensure we can normalize prefixes during processing;
  145. * for each uri, only one prefix will be exposed to the handlers.
  146. *
  147. * @type {!Object<string, string>}}
  148. */
  149. var nsUriToPrefix;
  150. /**
  151. * Handle parse error.
  152. *
  153. * @param {string|Error} err
  154. */
  155. function handleError(err) {
  156. if (!(err instanceof Error)) {
  157. err = error(err);
  158. }
  159. returnError = err;
  160. onError(err, getContext);
  161. }
  162. /**
  163. * Handle parse error.
  164. *
  165. * @param {string|Error} err
  166. */
  167. function handleWarning(err) {
  168. if (!onWarning) {
  169. return;
  170. }
  171. if (!(err instanceof Error)) {
  172. err = error(err);
  173. }
  174. onWarning(err, getContext);
  175. }
  176. /**
  177. * Register parse listener.
  178. *
  179. * @param {string} name
  180. * @param {Function} cb
  181. *
  182. * @return {Parser}
  183. */
  184. this['on'] = function(name, cb) {
  185. if (typeof cb !== 'function') {
  186. throw error('required args <name, cb>');
  187. }
  188. switch (name) {
  189. case 'openTag': onOpenTag = cb; break;
  190. case 'text': onText = cb; break;
  191. case 'closeTag': onCloseTag = cb; break;
  192. case 'error': onError = cb; break;
  193. case 'warn': onWarning = cb; break;
  194. case 'cdata': onCDATA = cb; break;
  195. case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
  196. case 'question': onQuestion = cb; break; // <? .... ?>
  197. case 'comment': onComment = cb; break;
  198. default:
  199. throw error('unsupported event: ' + name);
  200. }
  201. return this;
  202. };
  203. /**
  204. * Set the namespace to prefix mapping.
  205. *
  206. * @example
  207. *
  208. * parser.ns({
  209. * 'http://foo': 'foo',
  210. * 'http://bar': 'bar'
  211. * });
  212. *
  213. * @param {!Object<string, string>} nsMap
  214. *
  215. * @return {Parser}
  216. */
  217. this['ns'] = function(nsMap) {
  218. if (typeof nsMap === 'undefined') {
  219. nsMap = {};
  220. }
  221. if (typeof nsMap !== 'object') {
  222. throw error('required args <nsMap={}>');
  223. }
  224. var _nsUriToPrefix = {}, k;
  225. for (k in nsMap) {
  226. _nsUriToPrefix[k] = nsMap[k];
  227. }
  228. // FORCE default mapping for schema instance
  229. _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
  230. isNamespace = true;
  231. nsUriToPrefix = _nsUriToPrefix;
  232. return this;
  233. };
  234. /**
  235. * Parse xml string.
  236. *
  237. * @param {string} xml
  238. *
  239. * @return {Error} returnError, if not thrown
  240. */
  241. this['parse'] = function(xml) {
  242. if (typeof xml !== 'string') {
  243. throw error('required args <xml=string>');
  244. }
  245. returnError = null;
  246. parse(xml);
  247. getContext = noopGetContext;
  248. parseStop = false;
  249. return returnError;
  250. };
  251. /**
  252. * Stop parsing.
  253. */
  254. this['stop'] = function() {
  255. parseStop = true;
  256. };
  257. /**
  258. * Parse string, invoking configured listeners on element.
  259. *
  260. * @param {string} xml
  261. */
  262. function parse(xml) {
  263. var nsMatrixStack = isNamespace ? [] : null,
  264. nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
  265. _nsMatrix,
  266. nodeStack = [],
  267. anonymousNsCount = 0,
  268. tagStart = false,
  269. tagEnd = false,
  270. i = 0, j = 0,
  271. x, y, q, w, v,
  272. xmlns,
  273. elementName,
  274. _elementName,
  275. elementProxy
  276. ;
  277. var attrsString = '',
  278. attrsStart = 0,
  279. cachedAttrs // false = parsed with errors, null = needs parsing
  280. ;
  281. /**
  282. * Parse attributes on demand and returns the parsed attributes.
  283. *
  284. * Return semantics: (1) `false` on attribute parse error,
  285. * (2) object hash on extracted attrs.
  286. *
  287. * @return {boolean|Object}
  288. */
  289. function getAttrs() {
  290. if (cachedAttrs !== null) {
  291. return cachedAttrs;
  292. }
  293. var nsUri,
  294. nsUriPrefix,
  295. nsName,
  296. defaultAlias = isNamespace && nsMatrix['xmlns'],
  297. attrList = isNamespace && maybeNS ? [] : null,
  298. i = attrsStart,
  299. s = attrsString,
  300. l = s.length,
  301. hasNewMatrix,
  302. newalias,
  303. value,
  304. alias,
  305. name,
  306. attrs = {},
  307. seenAttrs = {},
  308. skipAttr,
  309. w,
  310. j;
  311. parseAttr:
  312. for (; i < l; i++) {
  313. skipAttr = false;
  314. w = s.charCodeAt(i);
  315. if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
  316. continue;
  317. }
  318. // wait for non whitespace character
  319. if (w < 65 || w > 122 || (w > 90 && w < 97)) {
  320. if (w !== 95 && w !== 58) { // char 95"_" 58":"
  321. handleWarning('illegal first char attribute name');
  322. skipAttr = true;
  323. }
  324. }
  325. // parse attribute name
  326. for (j = i + 1; j < l; j++) {
  327. w = s.charCodeAt(j);
  328. if (
  329. w > 96 && w < 123 ||
  330. w > 64 && w < 91 ||
  331. w > 47 && w < 59 ||
  332. w === 46 || // '.'
  333. w === 45 || // '-'
  334. w === 95 // '_'
  335. ) {
  336. continue;
  337. }
  338. // unexpected whitespace
  339. if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
  340. handleWarning('missing attribute value');
  341. i = j;
  342. continue parseAttr;
  343. }
  344. // expected "="
  345. if (w === 61) { // "=" == 61
  346. break;
  347. }
  348. handleWarning('illegal attribute name char');
  349. skipAttr = true;
  350. }
  351. name = s.substring(i, j);
  352. if (name === 'xmlns:xmlns') {
  353. handleWarning('illegal declaration of xmlns');
  354. skipAttr = true;
  355. }
  356. w = s.charCodeAt(j + 1);
  357. if (w === 34) { // '"'
  358. j = s.indexOf('"', i = j + 2);
  359. if (j === -1) {
  360. j = s.indexOf('\'', i);
  361. if (j !== -1) {
  362. handleWarning('attribute value quote missmatch');
  363. skipAttr = true;
  364. }
  365. }
  366. } else if (w === 39) { // "'"
  367. j = s.indexOf('\'', i = j + 2);
  368. if (j === -1) {
  369. j = s.indexOf('"', i);
  370. if (j !== -1) {
  371. handleWarning('attribute value quote missmatch');
  372. skipAttr = true;
  373. }
  374. }
  375. } else {
  376. handleWarning('missing attribute value quotes');
  377. skipAttr = true;
  378. // skip to next space
  379. for (j = j + 1; j < l; j++) {
  380. w = s.charCodeAt(j + 1);
  381. if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
  382. break;
  383. }
  384. }
  385. }
  386. if (j === -1) {
  387. handleWarning('missing closing quotes');
  388. j = l;
  389. skipAttr = true;
  390. }
  391. if (!skipAttr) {
  392. value = s.substring(i, j);
  393. }
  394. i = j;
  395. // ensure SPACE follows attribute
  396. // skip illegal content otherwise
  397. // example a="b"c
  398. for (; j + 1 < l; j++) {
  399. w = s.charCodeAt(j + 1);
  400. if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
  401. break;
  402. }
  403. // FIRST ILLEGAL CHAR
  404. if (i === j) {
  405. handleWarning('illegal character after attribute end');
  406. skipAttr = true;
  407. }
  408. }
  409. // advance cursor to next attribute
  410. i = j + 1;
  411. if (skipAttr) {
  412. continue parseAttr;
  413. }
  414. // check attribute re-declaration
  415. if (name in seenAttrs) {
  416. handleWarning('attribute <' + name + '> already defined');
  417. continue;
  418. }
  419. seenAttrs[name] = true;
  420. if (!isNamespace) {
  421. attrs[name] = value;
  422. continue;
  423. }
  424. // try to extract namespace information
  425. if (maybeNS) {
  426. newalias = (
  427. name === 'xmlns'
  428. ? 'xmlns'
  429. : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
  430. ? name.substr(6)
  431. : null
  432. );
  433. // handle xmlns(:alias) assignment
  434. if (newalias !== null) {
  435. nsUri = decodeEntities(value);
  436. nsUriPrefix = uriPrefix(newalias);
  437. alias = nsUriToPrefix[nsUri];
  438. if (!alias) {
  439. // no prefix defined or prefix collision
  440. if (
  441. (newalias === 'xmlns') ||
  442. (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
  443. ) {
  444. // alocate free ns prefix
  445. do {
  446. alias = 'ns' + (anonymousNsCount++);
  447. } while (typeof nsMatrix[alias] !== 'undefined');
  448. } else {
  449. alias = newalias;
  450. }
  451. nsUriToPrefix[nsUri] = alias;
  452. }
  453. if (nsMatrix[newalias] !== alias) {
  454. if (!hasNewMatrix) {
  455. nsMatrix = cloneNsMatrix(nsMatrix);
  456. hasNewMatrix = true;
  457. }
  458. nsMatrix[newalias] = alias;
  459. if (newalias === 'xmlns') {
  460. nsMatrix[uriPrefix(alias)] = nsUri;
  461. defaultAlias = alias;
  462. }
  463. nsMatrix[nsUriPrefix] = nsUri;
  464. }
  465. // expose xmlns(:asd)="..." in attributes
  466. attrs[name] = value;
  467. continue;
  468. }
  469. // collect attributes until all namespace
  470. // declarations are processed
  471. attrList.push(name, value);
  472. continue;
  473. } /** end if (maybeNs) */
  474. // handle attributes on element without
  475. // namespace declarations
  476. w = name.indexOf(':');
  477. if (w === -1) {
  478. attrs[name] = value;
  479. continue;
  480. }
  481. // normalize ns attribute name
  482. if (!(nsName = nsMatrix[name.substring(0, w)])) {
  483. handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
  484. continue;
  485. }
  486. name = defaultAlias === nsName
  487. ? name.substr(w + 1)
  488. : nsName + name.substr(w);
  489. // end: normalize ns attribute name
  490. // normalize xsi:type ns attribute value
  491. if (name === XSI_TYPE) {
  492. w = value.indexOf(':');
  493. if (w !== -1) {
  494. nsName = value.substring(0, w);
  495. // handle default prefixes, i.e. xs:String gracefully
  496. nsName = nsMatrix[nsName] || nsName;
  497. value = nsName + value.substring(w);
  498. } else {
  499. value = defaultAlias + ':' + value;
  500. }
  501. }
  502. // end: normalize xsi:type ns attribute value
  503. attrs[name] = value;
  504. }
  505. // handle deferred, possibly namespaced attributes
  506. if (maybeNS) {
  507. // normalize captured attributes
  508. for (i = 0, l = attrList.length; i < l; i++) {
  509. name = attrList[i++];
  510. value = attrList[i];
  511. w = name.indexOf(':');
  512. if (w !== -1) {
  513. // normalize ns attribute name
  514. if (!(nsName = nsMatrix[name.substring(0, w)])) {
  515. handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
  516. continue;
  517. }
  518. name = defaultAlias === nsName
  519. ? name.substr(w + 1)
  520. : nsName + name.substr(w);
  521. // end: normalize ns attribute name
  522. // normalize xsi:type ns attribute value
  523. if (name === XSI_TYPE) {
  524. w = value.indexOf(':');
  525. if (w !== -1) {
  526. nsName = value.substring(0, w);
  527. // handle default prefixes, i.e. xs:String gracefully
  528. nsName = nsMatrix[nsName] || nsName;
  529. value = nsName + value.substring(w);
  530. } else {
  531. value = defaultAlias + ':' + value;
  532. }
  533. }
  534. // end: normalize xsi:type ns attribute value
  535. }
  536. attrs[name] = value;
  537. }
  538. // end: normalize captured attributes
  539. }
  540. return cachedAttrs = attrs;
  541. }
  542. /**
  543. * Extract the parse context { line, column, part }
  544. * from the current parser position.
  545. *
  546. * @return {Object} parse context
  547. */
  548. function getParseContext() {
  549. var splitsRe = /(\r\n|\r|\n)/g;
  550. var line = 0;
  551. var column = 0;
  552. var startOfLine = 0;
  553. var endOfLine = j;
  554. var match;
  555. var data;
  556. while (i >= startOfLine) {
  557. match = splitsRe.exec(xml);
  558. if (!match) {
  559. break;
  560. }
  561. // end of line = (break idx + break chars)
  562. endOfLine = match[0].length + match.index;
  563. if (endOfLine > i) {
  564. break;
  565. }
  566. // advance to next line
  567. line += 1;
  568. startOfLine = endOfLine;
  569. }
  570. // EOF errors
  571. if (i == -1) {
  572. column = endOfLine;
  573. data = xml.substring(j);
  574. } else
  575. // start errors
  576. if (j === 0) {
  577. data = xml.substring(j, i);
  578. }
  579. // other errors
  580. else {
  581. column = i - startOfLine;
  582. data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
  583. }
  584. return {
  585. 'data': data,
  586. 'line': line,
  587. 'column': column
  588. };
  589. }
  590. getContext = getParseContext;
  591. if (proxy) {
  592. elementProxy = Object.create({}, {
  593. 'name': getter(function() {
  594. return elementName;
  595. }),
  596. 'originalName': getter(function() {
  597. return _elementName;
  598. }),
  599. 'attrs': getter(getAttrs),
  600. 'ns': getter(function() {
  601. return nsMatrix;
  602. })
  603. });
  604. }
  605. // actual parse logic
  606. while (j !== -1) {
  607. if (xml.charCodeAt(j) === 60) { // "<"
  608. i = j;
  609. } else {
  610. i = xml.indexOf('<', j);
  611. }
  612. // parse end
  613. if (i === -1) {
  614. if (nodeStack.length) {
  615. return handleError('unexpected end of file');
  616. }
  617. if (j === 0) {
  618. return handleError('missing start tag');
  619. }
  620. if (j < xml.length) {
  621. if (xml.substring(j).trim()) {
  622. handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
  623. }
  624. }
  625. return;
  626. }
  627. // parse text
  628. if (j !== i) {
  629. if (nodeStack.length) {
  630. if (onText) {
  631. onText(xml.substring(j, i), decodeEntities, getContext);
  632. if (parseStop) {
  633. return;
  634. }
  635. }
  636. } else {
  637. if (xml.substring(j, i).trim()) {
  638. handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
  639. if (parseStop) {
  640. return;
  641. }
  642. }
  643. }
  644. }
  645. w = xml.charCodeAt(i+1);
  646. // parse comments + CDATA
  647. if (w === 33) { // "!"
  648. q = xml.charCodeAt(i+2);
  649. // CDATA section
  650. if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
  651. j = xml.indexOf(']]>', i);
  652. if (j === -1) {
  653. return handleError('unclosed cdata');
  654. }
  655. if (onCDATA) {
  656. onCDATA(xml.substring(i + 9, j), getContext);
  657. if (parseStop) {
  658. return;
  659. }
  660. }
  661. j += 3;
  662. continue;
  663. }
  664. // comment
  665. if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
  666. j = xml.indexOf('-->', i);
  667. if (j === -1) {
  668. return handleError('unclosed comment');
  669. }
  670. if (onComment) {
  671. onComment(xml.substring(i + 4, j), decodeEntities, getContext);
  672. if (parseStop) {
  673. return;
  674. }
  675. }
  676. j += 3;
  677. continue;
  678. }
  679. }
  680. // parse question <? ... ?>
  681. if (w === 63) { // "?"
  682. j = xml.indexOf('?>', i);
  683. if (j === -1) {
  684. return handleError('unclosed question');
  685. }
  686. if (onQuestion) {
  687. onQuestion(xml.substring(i, j + 2), getContext);
  688. if (parseStop) {
  689. return;
  690. }
  691. }
  692. j += 2;
  693. continue;
  694. }
  695. // find matching closing tag for attention or standard tags
  696. // for that we must skip through attribute values
  697. // (enclosed in single or double quotes)
  698. for (x = i + 1; ; x++) {
  699. v = xml.charCodeAt(x);
  700. if (isNaN(v)) {
  701. j = -1;
  702. return handleError('unclosed tag');
  703. }
  704. // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
  705. // skips the quoted string
  706. // (double quotes) does not appear in a literal enclosed by (double quotes)
  707. // (single quote) does not appear in a literal enclosed by (single quote)
  708. if (v === 34) { // '"'
  709. q = xml.indexOf('"', x + 1);
  710. x = q !== -1 ? q : x;
  711. } else if (v === 39) { // "'"
  712. q = xml.indexOf("'", x + 1);
  713. x = q !== -1 ? q : x;
  714. } else if (v === 62) { // '>'
  715. j = x;
  716. break;
  717. }
  718. }
  719. // parse attention <! ...>
  720. // previously comment and CDATA have already been parsed
  721. if (w === 33) { // "!"
  722. if (onAttention) {
  723. onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
  724. if (parseStop) {
  725. return;
  726. }
  727. }
  728. j += 1;
  729. continue;
  730. }
  731. // don't process attributes;
  732. // there are none
  733. cachedAttrs = {};
  734. // if (xml.charCodeAt(i+1) === 47) { // </...
  735. if (w === 47) { // </...
  736. tagStart = false;
  737. tagEnd = true;
  738. if (!nodeStack.length) {
  739. return handleError('missing open tag');
  740. }
  741. // verify open <-> close tag match
  742. x = elementName = nodeStack.pop();
  743. q = i + 2 + x.length;
  744. if (xml.substring(i + 2, q) !== x) {
  745. return handleError('closing tag mismatch');
  746. }
  747. // verify chars in close tag
  748. for (; q < j; q++) {
  749. w = xml.charCodeAt(q);
  750. if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
  751. continue;
  752. }
  753. return handleError('close tag');
  754. }
  755. } else {
  756. if (xml.charCodeAt(j - 1) === 47) { // .../>
  757. x = elementName = xml.substring(i + 1, j - 1);
  758. tagStart = true;
  759. tagEnd = true;
  760. } else {
  761. x = elementName = xml.substring(i + 1, j);
  762. tagStart = true;
  763. tagEnd = false;
  764. }
  765. if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
  766. return handleError('illegal first char nodeName');
  767. }
  768. for (q = 1, y = x.length; q < y; q++) {
  769. w = x.charCodeAt(q);
  770. if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
  771. continue;
  772. }
  773. if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
  774. elementName = x.substring(0, q);
  775. // maybe there are attributes
  776. cachedAttrs = null;
  777. break;
  778. }
  779. return handleError('invalid nodeName');
  780. }
  781. if (!tagEnd) {
  782. nodeStack.push(elementName);
  783. }
  784. }
  785. if (isNamespace) {
  786. _nsMatrix = nsMatrix;
  787. if (tagStart) {
  788. // remember old namespace
  789. // unless we're self-closing
  790. if (!tagEnd) {
  791. nsMatrixStack.push(_nsMatrix);
  792. }
  793. if (cachedAttrs === null) {
  794. // quick check, whether there may be namespace
  795. // declarations on the node; if that is the case
  796. // we need to eagerly parse the node attributes
  797. if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
  798. attrsStart = q;
  799. attrsString = x;
  800. getAttrs();
  801. maybeNS = false;
  802. }
  803. }
  804. }
  805. _elementName = elementName;
  806. w = elementName.indexOf(':');
  807. if (w !== -1) {
  808. xmlns = nsMatrix[elementName.substring(0, w)];
  809. // prefix given; namespace must exist
  810. if (!xmlns) {
  811. return handleError('missing namespace on <' + _elementName + '>');
  812. }
  813. elementName = elementName.substr(w + 1);
  814. } else {
  815. xmlns = nsMatrix['xmlns'];
  816. // if no default namespace is defined,
  817. // we'll import the element as anonymous.
  818. //
  819. // it is up to users to correct that to the document defined
  820. // targetNamespace, or whatever their undersanding of the
  821. // XML spec mandates.
  822. }
  823. // adjust namespace prefixs as configured
  824. if (xmlns) {
  825. elementName = xmlns + ':' + elementName;
  826. }
  827. }
  828. if (tagStart) {
  829. attrsStart = q;
  830. attrsString = x;
  831. if (onOpenTag) {
  832. if (proxy) {
  833. onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
  834. } else {
  835. onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
  836. }
  837. if (parseStop) {
  838. return;
  839. }
  840. }
  841. }
  842. if (tagEnd) {
  843. if (onCloseTag) {
  844. onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
  845. if (parseStop) {
  846. return;
  847. }
  848. }
  849. // restore old namespace
  850. if (isNamespace) {
  851. if (!tagStart) {
  852. nsMatrix = nsMatrixStack.pop();
  853. } else {
  854. nsMatrix = _nsMatrix;
  855. }
  856. }
  857. }
  858. j += 1;
  859. }
  860. } /** end parse */
  861. }
  862. exports.Parser = Parser;
  863. exports.decode = decodeEntities;
  864. Object.defineProperty(exports, '__esModule', { value: true });
  865. })));