1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | if (typeof exports === 'object' ) {
|
63 | module.exports.EasySAXParser = EasySAXParser;
|
64 | };
|
65 |
|
66 | function EasySAXParser() {
|
67 | 'use strict';
|
68 |
|
69 | if (!this) return null;
|
70 |
|
71 | this.angularSyntax = false;
|
72 |
|
73 | function nullFunc() {};
|
74 |
|
75 | this.onTextNode = nullFunc;
|
76 | this.onStartNode = nullFunc;
|
77 | this.onEndNode = nullFunc;
|
78 | this.onCDATA = nullFunc;
|
79 | this.onError = nullFunc;
|
80 | this.onComment = null;
|
81 | this.onQuestion = null;
|
82 | this.onAttention = null;
|
83 | this.is_onComment = this.is_onQuestion = this.is_onAttention = false;
|
84 |
|
85 | this.isNamespace = false;
|
86 | this.useNS = null;
|
87 | this.default_xmlns = null;
|
88 | this.xmlns = null;
|
89 | this.nsmatrix = {xmlns: this.xmlns};
|
90 | this.hasSurmiseNS = false;
|
91 | ;
|
92 |
|
93 |
|
94 | this.attr_string = '';
|
95 | this.attr_posstart = 0;
|
96 | this.attr_res;
|
97 | }
|
98 |
|
99 | EasySAXParser.prototype.on = function(name, cb) {
|
100 | if (typeof cb !== 'function') {
|
101 | if (cb !== null) return;
|
102 | };
|
103 |
|
104 | switch(name) {
|
105 | case 'error': this.onError = cb || nullFunc; break;
|
106 | case 'startNode': this.onStartNode = cb || nullFunc; break;
|
107 | case 'endNode': this.onEndNode = cb || nullFunc; break;
|
108 | case 'textNode': this.onTextNode = cb || nullFunc; break;
|
109 | case 'cdata': this.onCDATA = cb || nullFunc; break;
|
110 |
|
111 | case 'comment': this.onComment = cb; this.is_onComment = !!cb; break;
|
112 | case 'question': this.onQuestion = cb; this.is_onQuestion = !!cb; break;
|
113 | case 'attention': this.onAttention = cb; this.is_onAttention = !!cb; break;
|
114 | };
|
115 | };
|
116 |
|
117 | EasySAXParser.prototype.ns = function(root, ns) {
|
118 | if (!root || typeof root !== 'string' || !ns) {
|
119 | return;
|
120 | };
|
121 |
|
122 | var u, x = {}, ok, v, i;
|
123 |
|
124 | for(i in ns) {
|
125 | v = ns[i];
|
126 | if (typeof v === 'string') {
|
127 | if (root === v) ok = true;
|
128 | x[i] = v;
|
129 | };
|
130 | };
|
131 |
|
132 | if (ok) {
|
133 | this.isNamespace = true;
|
134 | this.default_xmlns = root;
|
135 | this.useNS = x;
|
136 | };
|
137 | };
|
138 |
|
139 |
|
140 | EasySAXParser.prototype.parse = function(xml) {
|
141 | if (typeof xml !== 'string') {
|
142 | return;
|
143 | };
|
144 |
|
145 | if (this.isNamespace) {
|
146 | this.nsmatrix = {xmlns: this.default_xmlns};
|
147 |
|
148 | parse(xml);
|
149 |
|
150 | this.nsmatrix = false;
|
151 |
|
152 | } else {
|
153 | parse(xml);
|
154 | };
|
155 |
|
156 | this.attr_res = true;
|
157 | };
|
158 |
|
159 |
|
160 |
|
161 | var xharsQuot={constructor: false, hasOwnProperty: false, isPrototypeOf: false, propertyIsEnumerable: false, toLocaleString: false, toString: false, valueOf: false
|
162 | , quot: '"'
|
163 | , QUOT: '"'
|
164 | , amp: '&'
|
165 | , AMP: '&'
|
166 | , nbsp: '\u00A0'
|
167 | , apos: '\''
|
168 | , lt: '<'
|
169 | , LT: '<'
|
170 | , gt: '>'
|
171 | , GT: '>'
|
172 | , copy: '\u00A9'
|
173 | , laquo: '\u00AB'
|
174 | , raquo: '\u00BB'
|
175 | , reg: '\u00AE'
|
176 | , deg: '\u00B0'
|
177 | , plusmn: '\u00B1'
|
178 | , sup2: '\u00B2'
|
179 | , sup3: '\u00B3'
|
180 | , micro: '\u00B5'
|
181 | , para: '\u00B6'
|
182 | };
|
183 |
|
184 |
|
185 | function rpEntities(s, d, x, z) {
|
186 | if (z) {
|
187 | return xharsQuot[z] || '\x01';
|
188 | };
|
189 |
|
190 | if (d) {
|
191 | return String.fromCodePoint(d);
|
192 | };
|
193 |
|
194 | return String.fromCodePoint(parseInt(x, 16));
|
195 | };
|
196 |
|
197 | function unEntities(s, i) {
|
198 | s = String(s);
|
199 | if (s.length > 3 && s.indexOf('&') !== -1) {
|
200 | if (s.indexOf('>') !== -1) s = s.replace(/>/g, '>');
|
201 | if (s.indexOf('<') !== -1) s = s.replace(/</g, '<');
|
202 | if (s.indexOf('"') !== -1) s = s.replace(/"/g, '"');
|
203 |
|
204 | if (s.indexOf('&') !== -1) {
|
205 | s = s.replace(/&#(\d+);|&#x([0123456789abcdef]+);|&(\w+);/ig, rpEntities);
|
206 | };
|
207 | };
|
208 |
|
209 | return s;
|
210 | };
|
211 |
|
212 |
|
213 | EasySAXParser.prototype.allowedAngularAttributeChars = function(w) {
|
214 | if (!this.angularSyntax) {
|
215 | return false;
|
216 | } else {
|
217 | return (
|
218 | w === 40 ||
|
219 | w === 41 ||
|
220 | w === 91 ||
|
221 | w === 93 ||
|
222 | w === 94 ||
|
223 | w === 35
|
224 | );
|
225 | }
|
226 | };
|
227 |
|
228 | |
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 | EasySAXParser.prototype.getAttrs = function() {
|
237 | if (this.attr_res !== null) {
|
238 | return this.attr_res;
|
239 | };
|
240 |
|
241 | |
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | var u
|
254 | , res = {}
|
255 | , s = this.attr_string
|
256 | , i = this.attr_posstart
|
257 | , l = s.length
|
258 | , attr_list = this.hasSurmiseNS ? [] : false
|
259 | , name, value = ''
|
260 | , ok = false
|
261 | , noValueAttribute = false
|
262 | , j, w, nn, n
|
263 | , hasNewMatrix
|
264 | , alias, newalias
|
265 | ;
|
266 |
|
267 | aa:
|
268 | for(; i < l; i++) {
|
269 | w = s.charCodeAt(i);
|
270 |
|
271 | if (w===32 || (w<14 && w > 8) ) {
|
272 | continue
|
273 | };
|
274 |
|
275 |
|
276 | if ((w < 65 && !this.allowedAngularAttributeChars(w)) ||
|
277 | w > 122 || (w > 90 && w < 97 && !this.allowedAngularAttributeChars(w)) ) {
|
278 | return this.attr_res = false;
|
279 | };
|
280 |
|
281 | for(j = i + 1; j < l; j++) {
|
282 | w = s.charCodeAt(j);
|
283 |
|
284 | if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 ) {
|
285 | if (noValueAttribute) {
|
286 | j--;
|
287 | break;
|
288 | } else {
|
289 | continue;
|
290 | }
|
291 | };
|
292 |
|
293 | if (this.allowedAngularAttributeChars(w)) {
|
294 | continue;
|
295 | }
|
296 |
|
297 | if (w === 32 || (w > 8 && w < 14) ) {
|
298 | noValueAttribute = true;
|
299 | continue;
|
300 | } else if (w === 61) {
|
301 | noValueAttribute = false;
|
302 | break;
|
303 | } else {
|
304 |
|
305 | if (!noValueAttribute)
|
306 | return this.attr_res = false;
|
307 | };
|
308 |
|
309 | break;
|
310 | };
|
311 |
|
312 | name = s.substring(i, j).trim();
|
313 | ok = true;
|
314 |
|
315 | if (name === 'xmlns:xmlns') {
|
316 |
|
317 | return this.attr_res = false;
|
318 | };
|
319 |
|
320 | w = s.charCodeAt(j+1);
|
321 |
|
322 | while (w = s.charCodeAt(j+1)) {
|
323 | if (w===32 || (w > 8 && w<14) ) {
|
324 | j++;
|
325 | } else {
|
326 | break;
|
327 | }
|
328 | }
|
329 |
|
330 | if (!noValueAttribute) {
|
331 | if (w === 34) {
|
332 | j = s.indexOf('"', i = j+2 );
|
333 |
|
334 | } else {
|
335 | if (w === 39) {
|
336 | j = s.indexOf('\'', i = j+2 );
|
337 |
|
338 | } else {
|
339 | return this.attr_res = false;
|
340 | };
|
341 | };
|
342 | }
|
343 |
|
344 | if (j === -1) {
|
345 |
|
346 | return this.attr_res = false;
|
347 | };
|
348 |
|
349 |
|
350 | if (j+1 < l && !noValueAttribute) {
|
351 | w = s.charCodeAt(j+1);
|
352 |
|
353 | if (w > 32 || w < 9 || (w < 32 && w > 13)) {
|
354 |
|
355 |
|
356 | return this.attr_res = false;
|
357 | };
|
358 | };
|
359 |
|
360 |
|
361 | if (noValueAttribute) {
|
362 | value = '';
|
363 | } else {
|
364 | value = s.substring(i, j);
|
365 | }
|
366 |
|
367 |
|
368 | i = j;
|
369 |
|
370 | if (this.isNamespace) {
|
371 | if (this.hasSurmiseNS) {
|
372 |
|
373 |
|
374 | if (newalias = name === 'xmlns' ? 'xmlns' : name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:' && name.substr(6) ) {
|
375 | alias = this.useNS[unEntities(value)];
|
376 |
|
377 | if (alias) {
|
378 | if (this.nsmatrix[newalias] !== alias) {
|
379 | if (!hasNewMatrix) {
|
380 | hasNewMatrix = true;
|
381 | nn = {}; for (n in this.nsmatrix) nn[n] = this.nsmatrix[n];
|
382 | this.nsmatrix = nn;
|
383 | };
|
384 |
|
385 | this.nsmatrix[newalias] = alias;
|
386 | };
|
387 | } else {
|
388 | if (this.nsmatrix[newalias]) {
|
389 | if (!hasNewMatrix) {
|
390 | hasNewMatrix = true;
|
391 | nn = {}; for (n in this.nsmatrix) nn[n] = this.nsmatrix[n];
|
392 | this.nsmatrix = nn;
|
393 | };
|
394 |
|
395 | this.nsmatrix[newalias] = false;
|
396 | };
|
397 | };
|
398 |
|
399 | res[name] = value;
|
400 | continue;
|
401 | };
|
402 |
|
403 | attr_list.push(name, value);
|
404 | continue;
|
405 | };
|
406 |
|
407 | w = name.length;
|
408 | while(--w) {
|
409 | if (name.charCodeAt(w) === 58) {
|
410 | if (w = this.nsmatrix[name.substring(0, w)] ) {
|
411 | res[w + name.substr(w)] = value;
|
412 | };
|
413 | continue aa;
|
414 |
|
415 |
|
416 | };
|
417 | };
|
418 | };
|
419 |
|
420 | res[name] = value;
|
421 | noValueAttribute = false;
|
422 | };
|
423 |
|
424 |
|
425 | if (!ok) {
|
426 | return this.attr_res = true;
|
427 | };
|
428 |
|
429 |
|
430 | if (this.hasSurmiseNS) {
|
431 | bb:
|
432 |
|
433 | for (i = 0, l = attr_list.length; i < l; i++) {
|
434 | name = attr_list[i++];
|
435 |
|
436 | w = name.length;
|
437 | while(--w) {
|
438 | if (name.charCodeAt(w) === 58) {
|
439 | if (w = this.nsmatrix[name.substring(0, w)]) {
|
440 | res[w + name.substr(w)] = attr_list[i];
|
441 | };
|
442 | continue bb;
|
443 | break;
|
444 | };
|
445 | };
|
446 |
|
447 | res[name] = attr_list[i];
|
448 | };
|
449 | };
|
450 |
|
451 | return this.attr_res = res;
|
452 | };
|
453 |
|
454 |
|
455 |
|
456 | EasySAXParser.prototype.parse = function(xml) {
|
457 | var u
|
458 | , xml = String(xml)
|
459 | , nodestack = []
|
460 | , stacknsmatrix = []
|
461 |
|
462 | , elem
|
463 | , tagend = false
|
464 | , tagstart = false
|
465 | , j = 0, i = 0, k = 0, len
|
466 | , x, y, q, w
|
467 | , xmlns
|
468 | , stopIndex = 0
|
469 | , stop
|
470 | , _nsmatrix
|
471 | , ok
|
472 | , pos = 0, ln = 0, lnStart = -2, lnEnd = -1
|
473 | ;
|
474 |
|
475 | len = xml.length;
|
476 | function getStringNode() {
|
477 | return xml.substring(i, j+1)
|
478 | };
|
479 | function findLineAndColumnFromPos() {
|
480 | while (lnStart < lnEnd && lnEnd < pos) {
|
481 | lnStart = lnEnd;
|
482 | lnEnd = xml.indexOf("\n", lnEnd + 1);
|
483 | ++ln;
|
484 | }
|
485 | return { line: ln, column: pos - lnStart };
|
486 | }
|
487 | function position(p) {
|
488 | pos = p;
|
489 | return findLineAndColumnFromPos;
|
490 | }
|
491 |
|
492 | while(j !== -1) {
|
493 | stop = stopIndex > 0;
|
494 |
|
495 | if (xml.charCodeAt(j) === 60) {
|
496 | i = j;
|
497 | } else {
|
498 | i = xml.indexOf('<', j);
|
499 | };
|
500 |
|
501 | if (i === -1) {
|
502 |
|
503 | if (nodestack.length) {
|
504 | this.onError('end file', position(j));
|
505 | return;
|
506 | };
|
507 |
|
508 | return;
|
509 | };
|
510 |
|
511 | if (j !== i && !stop) {
|
512 | ok = this.onTextNode(xml.substring(j, i), unEntities, position(j));
|
513 | if (ok === false) return;
|
514 | };
|
515 |
|
516 | w = xml.charCodeAt(i+1);
|
517 |
|
518 | if (w === 33) {
|
519 | w = xml.charCodeAt(i+2);
|
520 | if (w === 91 && xml.substr(i+3, 6) === 'CDATA[') {
|
521 | j = xml.indexOf(']]>', i);
|
522 | if (j === -1) {
|
523 | this.onError('cdata', position(i));
|
524 | return;
|
525 | };
|
526 |
|
527 |
|
528 | if (!stop) {
|
529 | ok = this.onCDATA(xml.substring(i+9, j), false, position(i));
|
530 | if (ok === false) return;
|
531 | };
|
532 |
|
533 | j += 3;
|
534 | continue;
|
535 | };
|
536 |
|
537 | if (w === 45 && xml.charCodeAt(i+3) === 45) {
|
538 | j = xml.indexOf('-->', i);
|
539 | if (j === -1) {
|
540 | this.onError('expected -->', position(i));
|
541 | return;
|
542 | };
|
543 |
|
544 |
|
545 | if (this.is_onComment && !stop) {
|
546 | ok = this.onComment(xml.substring(i+4, j), unEntities, position(i));
|
547 | if (ok === false) return;
|
548 | };
|
549 |
|
550 | j += 3;
|
551 | continue;
|
552 | };
|
553 |
|
554 | j = xml.indexOf('>', i+1);
|
555 | if (j === -1) {
|
556 | this.onError('expected ">"', position(i + 1));
|
557 | return;
|
558 | };
|
559 |
|
560 | if (this.is_onAttention && !stop) {
|
561 | ok = this.onAttention(xml.substring(i, j+1), unEntities, position(i));
|
562 | if (ok === false) return;
|
563 | };
|
564 |
|
565 | j += 1;
|
566 | continue;
|
567 |
|
568 | } else {
|
569 | if (w === 63) {
|
570 | j = xml.indexOf('?>', i);
|
571 | if (j === -1) {
|
572 | this.onError('...?>', position(i));
|
573 | return;
|
574 | };
|
575 |
|
576 | if (this.is_onQuestion) {
|
577 | ok = this.onQuestion(xml.substring(i, j+2), position(i));
|
578 | if (ok === false) return;
|
579 | };
|
580 |
|
581 | j += 2;
|
582 | continue;
|
583 | };
|
584 | };
|
585 |
|
586 | var inside=false;
|
587 | for (k=i,j=-1;k<len;k++) {
|
588 | var c = xml.charCodeAt(k);
|
589 | if (!inside) {
|
590 |
|
591 | if (c === 34) {
|
592 | inside = c;
|
593 | }
|
594 | else if (c === 39) {
|
595 | inside = c;
|
596 | }
|
597 | else if (c === 62) {
|
598 | j = k; break;
|
599 | }
|
600 | } else {
|
601 | if (c === inside) { inside = false; }
|
602 | }
|
603 | }
|
604 |
|
605 | if (j == -1) {
|
606 | this.onError('...>', position(i + 1));
|
607 | return;
|
608 | };
|
609 |
|
610 | this.attr_res = true;
|
611 |
|
612 |
|
613 | if (w === 47) {
|
614 | tagstart = false;
|
615 | tagend = true;
|
616 |
|
617 |
|
618 | x = elem = nodestack.pop();
|
619 | q = i + 2 + x.length;
|
620 |
|
621 |
|
622 | if (xml.substring(i+2, q) !== x) {
|
623 | this.onError('close tagname', position(i + 2));
|
624 | return;
|
625 | };
|
626 |
|
627 |
|
628 | for(; q < j; q++) {
|
629 | w = xml.charCodeAt(q);
|
630 |
|
631 | if (w===32 || (w > 8 && w<14) ) {
|
632 | continue;
|
633 | };
|
634 |
|
635 | this.onError('close tag', position(i + 2));
|
636 | return;
|
637 | };
|
638 |
|
639 | } else {
|
640 | if (xml.charCodeAt(j-1) === 47) {
|
641 | x = elem = xml.substring(i+1, j-1);
|
642 |
|
643 | tagstart = true;
|
644 | tagend = true;
|
645 | } else {
|
646 | x = elem = xml.substring(i+1, j);
|
647 |
|
648 | tagstart = true;
|
649 | tagend = false;
|
650 | };
|
651 |
|
652 | if ( !(w > 96 && w < 123 || w > 64 && w <91) ) {
|
653 | this.onError('first char nodeName', position(i + 1));
|
654 | return;
|
655 | };
|
656 |
|
657 | for(q = 1, y = x.length; q < y; q++) {
|
658 | w = x.charCodeAt(q);
|
659 |
|
660 | if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w === 46 ) {
|
661 | continue;
|
662 | };
|
663 |
|
664 | if (w===32 || (w<14 && w > 8)) {
|
665 | elem = x.substring(0, q)
|
666 | this.attr_res = null;
|
667 | break;
|
668 | };
|
669 |
|
670 | this.onError('invalid nodeName', position(i + 1));
|
671 | return;
|
672 | };
|
673 |
|
674 | if (!tagend) {
|
675 | nodestack.push(elem);
|
676 | };
|
677 | };
|
678 |
|
679 |
|
680 | if (this.isNamespace) {
|
681 | if (stop) {
|
682 | if (tagend) {
|
683 | if (!tagstart) {
|
684 | if (--stopIndex === 0) {
|
685 | this.nsmatrix = stacknsmatrix.pop();
|
686 | };
|
687 | };
|
688 |
|
689 | } else {
|
690 | stopIndex += 1;
|
691 | };
|
692 |
|
693 |
|
694 | j += 1;
|
695 | continue;
|
696 | };
|
697 |
|
698 | _nsmatrix = this.nsmatrix;
|
699 |
|
700 | if (!tagend) {
|
701 | stacknsmatrix.push(this.nsmatrix);
|
702 |
|
703 | if (this.attr_res !== true) {
|
704 | if (this.hasSurmiseNS = x.indexOf('xmlns', q) !== -1) {
|
705 | this.attr_string = x;
|
706 | this.attr_posstart = q;
|
707 |
|
708 | this.getAttrs();
|
709 |
|
710 | this.hasSurmiseNS = false;
|
711 | };
|
712 | };
|
713 | };
|
714 |
|
715 |
|
716 | w = elem.indexOf(':');
|
717 | if (w !== -1) {
|
718 | xmlns = this.nsmatrix[elem.substring(0, w)];
|
719 | elem = elem.substr(w+1);
|
720 |
|
721 | } else {
|
722 | xmlns = this.nsmatrix.xmlns;
|
723 | };
|
724 |
|
725 | if (!xmlns) {
|
726 | if (tagend) {
|
727 | if (tagstart) {
|
728 | this.nsmatrix = _nsmatrix;
|
729 | } else {
|
730 | this.nsmatrix = stacknsmatrix.pop();
|
731 | };
|
732 | } else {
|
733 | stopIndex = 1;
|
734 | this.attr_res = true;
|
735 | };
|
736 |
|
737 | j += 1;
|
738 | continue;
|
739 | };
|
740 |
|
741 | elem = xmlns + ':' + elem;
|
742 | };
|
743 |
|
744 |
|
745 |
|
746 | if (tagstart) {
|
747 | this.attr_string = x;
|
748 | this.attr_posstart = q;
|
749 |
|
750 | var that = this;
|
751 | ok = this.onStartNode(elem, function() { return that.getAttrs() }, unEntities, tagend
|
752 | , getStringNode, position(i)
|
753 | );
|
754 |
|
755 | if (ok === false) {
|
756 | return;
|
757 | };
|
758 |
|
759 | this.attr_res = true;
|
760 | };
|
761 |
|
762 | if (tagend) {
|
763 | ok = this.onEndNode(elem, unEntities, tagstart
|
764 | , getStringNode, position(i)
|
765 | );
|
766 |
|
767 | if (ok === false) {
|
768 | return;
|
769 | };
|
770 |
|
771 | if (this.isNamespace) {
|
772 | if (tagstart) {
|
773 | this.nsmatrix = _nsmatrix;
|
774 | } else {
|
775 | this.nsmatrix = stacknsmatrix.pop();
|
776 | };
|
777 | };
|
778 | };
|
779 |
|
780 | j += 1;
|
781 | };
|
782 | };
|