source: main/trunk/greenstone3/web/interfaces/oran/js/annotator/lib/vendor/xpath.js@ 24771

Last change on this file since 24771 was 24771, checked in by papitha, 13 years ago

Changes to JS

File size: 32.2 KB
Line 
1/*
2 XPath.js, an JavaScript implementation of XML Path Language (XPath) Version 1.0
3 Copyright (C) 2008 Henrik Lindqvist <[email protected]>
4
5 This library is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18(function (w, d, f) {
19
20
21function XPath (e) {
22 this.e = e;
23 this.i = 0;
24 this.js = [ 'with(XPath){return ', '}' ];
25 this.expression(1, 1) || this.error();
26 //console.log(this.js.join(''));
27 return new Function('n', 'nsr', this.js.join(''));
28}
29XPath.ie = /MSIE/.test(navigator.userAgent);
30XPath.prototype = {
31 match : function (rx, x) {
32 var m, r;
33 if ( !(m = rx.exec(this.e.substr(this.i)))
34 || (typeof x == 'number' && !(r = m[x]))
35 || (typeof x == 'object' && !(r = x[m[1]]))) return false;
36 this.m = m;
37 this.i += m[0].length;
38 return r || m;
39 },
40 error : function (m) {
41 m = (m || 'Syntax error')+' at index '+this.i+': '+this.e.substr(this.i);
42 var e;
43 try { e = new XPathException(51, m) }
44 catch (x) { e = new Error(m) }
45 throw e;
46 },
47 step : function (l, r, s, n) {
48 var i = 3;
49 if (this.match(/^(\/\/?|\.\.?|@)\s*/, 1)) {
50 switch (this.m[1]) {
51 case '/':
52 if (s) this.error();
53 if (!n) return this.step(l, r, 1);
54 this.js.splice(l, 0, ' axis(axes["','document-root','"],');
55 i += this.nodeTypes.node.call(this, l + i);
56 s = 1;
57 break;
58 case '//':
59 if (s) this.error();
60 this.js.splice(l, 0, ' axis(axes["','descendant-or-self','"],');
61 i += this.nodeTypes.node.call(this, l + i);
62 s = 1;
63 break;
64 case '.':
65 if (!s && !n) this.error();
66 this.js.splice(l, 0, ' axis(axes["','self','"],');
67 i += this.nodeTypes.node.call(this, l + i);
68 s = 0;
69 break;
70 case '..':
71 if (!s && !n) this.error();
72 this.js.splice(l, 0, ' axis(axes["','parent','"],');
73 i += this.nodeTypes.node.call(this, l + i);
74 s = 0;
75 break;
76 case '@':
77 if (!s && !n) this.error();
78 this.js.splice(l, 0, ' axis(axes["','attribute','"],');
79 i += this.nodeTest(l + i, 'node') || this.error('Missing nodeTest after @');
80 s = 0;
81 }
82 }
83 else if (!s && !n) return s ? this.error() : 0;
84 else if (this.match(/^([a-z]+(?:-[a-z]+)*)\s*::\s*/, XPath.axes)) {
85 this.js.splice(l, 0, ' axis(axes["',this.m[1],'"],');
86 i += this.nodeTest(l + i, (this.m[1]=='attribute')?'node':'element') || this.error('Missing nodeTest after ::');
87 s = 0;
88 }
89 else if (i = this.nodeTest(l, 'element')) {
90 this.js.splice(l, 0, ' axis(axes["','child','"],');
91 i += 3;
92 s = 0;
93 }
94 else return 0;
95 for (var j; j = this.predicate(l + i); i += j);
96 if (n) this.js.splice(r + i++, 0, n);
97 i += this.step(l, r + i, s);
98 this.js.splice(r + i++, 0, ')');
99 return i;
100 },
101 expression : function (l, r, p) {
102 var o, i = this.operand(l);
103 while (o = this.match(/^(or|and|!?=|[<>]=?|[|*+-]|div|mod)\s*/, this.operators)) {
104 if (p && p[0] >= o[0]) {
105 this.i -= this.m[0].length;
106 break;
107 }
108 this.js.splice(l, 0, o[1]);
109 i++;
110 this.js.splice(l + i++, 0, o[2]);
111 i += this.expression(l + i, r, o) || this.error('Missing operand');
112 this.js.splice(l + i++, 0, o[3]);
113 }
114 return i;
115 },
116 operand : function (l) {
117 if (this.match(/^(-?(?:[0-9]+(?:\.[0-9]+)?|\.[0-9]+)|"[^"]*"|'[^']*')\s*/, 1)) {
118 this.js.splice(l, 0, this.m[1]);
119 return 1;
120 }
121 var fn;
122 if (fn = this.match(/^([a-z]+(?:-[a-z]+)*)\s*\(\s*/, this.functions)) {
123 var i = 1, j;
124 this.js.splice(l, 0, fn[1]);
125 do {
126 if (j) this.js.splice(l + i++, 0, ',');
127 i += (j = this.expression(l + i, l + i));
128 } while (j && this.match(/^,\s*/));
129 this.match(/^\)\s*/) || this.error('Missing (');
130 if (fn[0]) {
131 if (j) this.js.splice(l + i++, 0, ',');
132 this.js.splice(l + i++, 0, fn[0]);
133 }
134 if (fn[2]) this.js.splice(l + i++, 0, fn[2]);
135 else if (j > 1) this.error('Function has arguments');
136 i += this.step(l, l + i);
137 return i;
138 }
139 if (this.match(/^\(\s*/)) {
140 var i = 1;
141 this.js.splice(l, 0, '(');
142 i += this.expression(l + i, l + i);
143 this.match(/^\)\s*/) || this.error('Missing )');
144 this.js.splice(l + i++, ')');
145 return i;
146 }
147 return this.step(l, l, 0, '[n]');
148 },
149 operators : {
150 '|' : [1,'union(',',',')'],
151 'or' : [1,'bool(',')||bool(',')'],
152 'and' : [2,'bool(',')&&bool(',')'],
153 '=' : [3,'compare(eq,',',',')'],
154 '!=' : [3,'compare(ne,',',',')'],
155 '<' : [4,'compare(lt,',',',')'],
156 '>' : [4,'compare(gt,',',',')'],
157 '<=' : [4,'compare(le,',',',')'],
158 '>=' : [4,'compare(ge,',',',')'],
159 '+' : [5,'number(',')+number(',')'],
160 '-' : [5,'number(',')-number(',')'],
161 '*' : [6,'number(',')*number(',')'],
162 'div' : [6,'number(',')/number(',')'],
163 'mod' : [6,'number(',')%number(',')']
164 },
165 functions : {
166 // Node Set
167 'last' : [0,'nl.length'],
168 'position' : [0,'(i+1)'],
169 'count' : ['nl','(','.length||0)'],
170 'id' : ['n','id(',')'],
171 'local-name' : ['nl','localName(',')'],
172 'namespace-uri' : ['nl','namespaceURI(',')'],
173 'name' : ['nl','qName(',')'],
174 // String
175 'string' : ['n','string(',')'],
176 'concat' : [0,'concat(',')'],
177 'starts-with' : [0,'startsWith(',')'],
178 'contains' : [0,'contains(',')'],
179 'substring-before' : [0,'substringBefore(',')'],
180 'substring-after' : [0,'substringAfter(',')'],
181 'substring' : [0,'substring(',')'],
182 'string-length' : ['n','string(',').length'],
183 'normalize-space' : ['n','normalizeSpace(',')'],
184 'translate' : [0,'translate(',')'],
185 // Boolean
186 'boolean' : [0,'bool(',')'],
187 'not' : [0,'!bool(',')'],
188 'true' : [0,'true '],
189 'false' : [0,'false '],
190// 'lang' : [],
191 // Number
192 'number' : ['n','number(',')'],
193 'floor' : [0,'Math.floor(number(','))'],
194 'ceiling' : [0,'Math.ceil(number(','))'],
195 'round' : [0,'Math.round(number(','))'],
196 'sum' : [0,'sum(',')']
197 },
198 predicate : function (l) {
199 var i = 0;
200 if (this.match(/^\[\s*/)) {
201 if (i = this.expression(l, l)) {
202 this.js.splice(l, 0, 'function(n,i,nl){with(XPath){var r=');
203 i++;
204 this.js.splice(l + i++, 0, ';return typeof r=="number"?Math.round(r)==i+1:bool(r)}},');
205 }
206 this.match(/^\]\s*/) || this.error('Missing ]');
207 }
208 return i;
209 },
210 nodeTest : function (l, t) {
211 var fn;
212 if (fn = this.match(/^([a-z]+(?:-[a-z]+)*)\(([^)]*)\)\s*/, this.nodeTypes))
213 return fn.call(this, l, this.m[2]);
214 if (this.match(/^\*\s*/))
215 return this.nodeTypes[t].call(this, l);
216 return this.nodeName(l)
217 },
218 nodeType : function (l, t) {
219 this.js.splice(l, 0, 'function(n){return n.nodeType==',t,'},');
220 return 3;
221 },
222 nodeTypes : {
223 'node' : function (l) {
224 this.js.splice(l, 0, 'null,');
225 return 1;
226 },
227 'element' : function (l) {
228 return this.nodeType(l, 1);
229 },
230 'attribute' : function (l) {
231 return this.nodeType(l, 2);
232 },
233 'text' : function (l) {
234 return this.nodeType(l, 3);
235 },
236 'processing-instruction' : function (l, t) {
237 if (!t) return this.nodeType(l, 7);
238 this.js.splice(l, 0, 'function(n){return n.nodeType==7&&n.target==',t,'},');
239 return 3;
240 },
241 'comment' : function (l) {
242 return this.nodeType(l, 8);
243 }
244 },
245 nodeName : function (l) {
246 if (!this.match(/^([a-zA-Z_]+(?:-?[a-zA-Z0-9]+)*)(?::([a-zA-Z_]+(?:-?[a-zA-Z0-9]+)*))?\s*/, 1))
247 return 0;
248 if (this.m[2]) {
249 this.js.splice(l,0,'function(n){if(!nsr)throw new XPathException(14);return "',
250 this.m[2],'"==',XPath.ie?'n.baseName':'n.localName','&&nsr.lookupNamespaceURI("',
251 this.m[1],'")==n.namespaceURI},');
252 return 7;
253 }
254 else {
255 this.js.splice(l,0,'function(n){return/^',this.m[1],'$/i.test(n.nodeName)},');
256 return 3;
257 }
258 }
259};
260XPath.order = function (l, r) {
261 var x = l.compareDocumentPosition
262 ? l.compareDocumentPosition(r)
263 : XPath.compareDocumentPosition.call(l, r);
264 if (x & 32) {
265 l = Array.prototype.indexOf.call(l.attributes, l);
266 r = Array.prototype.indexOf.call(r.attributes, r);
267 return (l < r) ? -1 : (l > r) ? 1 : 0;
268 }
269 if (!x) {
270 if (l == r)
271 return 0;
272 if ((l = l.ownerElement) && (r = r.ownerElement))
273 return XPath.order(l, r);
274 return XPath.ie ? 1 : 0;
275 }
276 return 3 - ((x & 6) || 3);
277};
278// Runtime - Operand
279XPath.compare = function (fn, l, r) {
280 if (l instanceof Array && r instanceof Array) {
281 var ls = l.map(this.string), rs = r.map(this.string);
282 for (l = ls.length; --l >= 0;)
283 for (r = rs.length; --r >= 0;)
284 if (!fn(ls[l], rs[r])) return false;
285 return true;
286 }
287 if (l instanceof Array) {
288 for (var i = l.length; --i >= 0;)
289 if (!fn(this[typeof r](l[i]), r)) return false;
290 return l.length > 0;
291 }
292 if (r instanceof Array) {
293 for (var i = r.length; --i >= 0;)
294 if (!fn(l, this[typeof l](r[i]))) return false;
295 return r.length > 0;
296 }
297 if (typeof l == 'boolean' || typeof r == 'boolean')
298 return fn(this.bool(l), this.bool(r));
299 if (typeof l == 'number' || typeof r == 'number')
300 return fn(this.number(l), this.number(r));
301 return fn(this.string(l), this.string(r));
302};
303XPath.eq = function (l, r) { return l == r };
304XPath.ne = function (l, r) { return l != r };
305XPath.lt = function (l, r) { return l < r };
306XPath.gt = function (l, r) { return l > r };
307XPath.le = function (l, r) { return l <= r };
308XPath.ge = function (l, r) { return l >= r };
309// Runtime - Node Set
310XPath.id = function (s, n) {
311 if (arguments.length == 1) n = s;
312 var nl = [];
313 for (var id = this.string(s).split(/\s+/), i = id.length; --i >= 0;)
314 if (s = (n.ownerDocument || n).getElementById(id[i]))
315 nl.push(s);
316 return nl.sort(this.order);
317};
318XPath.localName = new Function ('nl',
319 'return (nl.length&&nl[0].'+(XPath.ie?'baseName':'localName')+')||""'
320);
321XPath.namespaceURI = function (nl) {
322 return (nl.length && nl[0].namespaceURI) || '';
323};
324XPath.qName = function (nl) {
325 return (nl.length && nl[0].nodeName) || '';
326};
327XPath.union = function (a, b) {
328 if (!a.length) return b;
329 if (!b.length) return a;
330 var nl = [], i = a.length - 1, j = b.length - 1;
331 for (;;) {
332 switch (this.order(a[i], b[j])) {
333 case -1: nl.unshift(b[j--]); break;
334 case 0: j--; // fallthru
335 case 1: nl.unshift(a[i--]); break;
336 default: throw new Error('Invalid order');
337 }
338 if (i < 0) {
339 if (++j > 0) nl.unshift.apply(nl, nl.slice.call(b, 0, j));
340 break;
341 }
342 if (j < 0) {
343 if (++i > 0) nl.unshift.apply(nl, nl.slice.call(a, 0, i));
344 break;
345 }
346 }
347 return nl;
348};
349// Runtime - String
350XPath.string = XPath.object = function (v) {
351 if (v instanceof Array && typeof (v = v[0]) == 'undefined') return '';
352 if (typeof v == 'string') return v;
353 switch (v.nodeType) {
354 case 1: case 9: case 11:
355 return Array.prototype.map.call(v.childNodes, this.string, this).join('');
356// case 3: case 4: case 8:
357// return v.data || '';
358 default:
359 return v.nodeValue || '';
360 }
361 return String(v);
362};
363XPath.concat = function () {
364 return Array.prototype.map.call(arguments, this.string, this).join('');
365};
366XPath.startsWith = function (a, b) {
367 return this.string(a).substr(0, (b = this.string(b)).length) == b;
368};
369XPath.contains = function (a, b) {
370 return this.string(a).indexOf(this.string(b)) != -1;
371};
372XPath.substringBefore = function (a, b) {
373 a = this.string(a);
374 b = a.indexOf(this.string(b));
375 return b != -1 ? a.substr(0, b) : '';
376};
377XPath.substringAfter = function (a, b) {
378 a = this.string(a); b = this.string(b);
379 var i = a.indexOf(b);
380 return i != -1 ? a.substr(i + b.length) : '';
381};
382XPath.substring = function (s, i, l) {
383 s = this.string(s);
384 i = Math.round(this.number(i)) - 1;
385 return (arguments.length == 2)
386 ? s.substr(i < 0 ? 0 : i)
387 : s.substr(i < 0 ? 0 : i, Math.round(this.number(l)) - Math.max(0, -i));
388};
389XPath.normalizeSpace = function(s) {
390 return this.string(s).replace(/^\s+/,'').replace(/\s+$/,'').replace(/\s+/g, ' ');
391};
392XPath.translate = function(a, b, c) {
393 a = this.string(a); b = this.string(b); c = this.string(c);
394 var o = [], l = a.length, i = 0, j, x;
395 while (--l >= 0)
396 if ( (j = b.indexOf(x = a.charAt(i++))) == -1
397 || (x = c.charAt(j))) o.push(x);
398 return o.join('');
399};
400// Runtime - Boolean
401XPath.bool = XPath['boolean'] = function (v) {
402 if (typeof v == 'boolean') return v;
403 if (v instanceof Array || typeof v == 'string') return v.length > 0;
404 return Boolean(v);
405};
406// Runtime - Number
407XPath.number = function (v) {
408 if (v instanceof Array && typeof (v = v[0]) == 'undefined') return 0;
409 if (typeof v == 'number') return v;
410 if (typeof v == 'boolean') return v ? 1 : 0;
411 return Number(this.string(v));
412};
413XPath.sum = function (nl) {
414 var r = 0, i = nl.length;
415 while (--i >= 0) r += this.number(nl[i]);
416 return r;
417};
418// Runtime - Axis
419XPath.walk = function (n, nl) {
420 var x, c = n.firstChild;
421 while (c) {
422 nl.push(c);
423 if (x = c.firstChild) c = x;
424 else for (x = c; !(c = x.nextSibling) && (x = x.parentNode) && (x != n););
425 }
426 return nl;
427};
428XPath.axes = {
429 'ancestor' : function (n) {
430 var nl = [];
431 while (n = n.parentNode) nl.unshift(n);
432 return nl;
433 },
434 'ancestor-or-self' : function (n) {
435 var nl = [];
436 do { nl.unshift(n) } while (n = n.parentNode);
437 return nl;
438 },
439 'attribute' : new Function ('n',
440 'var nl = [], a = n.attributes;if(a){attr:for(var x,i=a.length;--i>=0;){if(!(x=a[i]).specified){' +
441 (XPath.ie?'switch(x.nodeName){case"selected":case"value":if(x.nodeValue)break;default:continue attr;}' : 'continue;') +
442 '}nl.unshift(x);}}return nl;'
443 ),
444 'child' : function (n) {
445 return n.childNodes || [];
446 },
447 'descendant' : function (n) {
448 return this.walk(n, []);
449 },
450 'descendant-or-self' : function (n) {
451 return this.walk(n, [n]);
452 },
453 'following' : function (n) {
454 var nl = [], x;
455 while (n) {
456 if (x = n.nextSibling) {
457 nl.push(n = x);
458 if (x = n.firstChild) nl.push(n = x);
459 }
460 else n = n.parentNode;
461 }
462 return nl;
463 },
464 'following-sibling' : function (n) {
465 var nl = [];
466 while (n = n.nextSibling) nl.push(n);
467 return nl;
468 },
469 'parent' : function (n) {
470 return n.parentNode ? [n.parentNode] : [];
471 },
472 'preceding' : function (n) {
473 var nl = [], x, p = n.parentNode;
474 while (n) {
475 if (x = n.previousSibling) {
476 for (n = x; x = n.lastChild; n = x);
477 nl.unshift(n);
478 }
479 else if (n = n.parentNode) {
480 if (n == p) p = p.parentNode;
481 else nl.unshift(n);
482 }
483 }
484 return nl;
485 },
486 'preceding-sibling' : function (n) {
487 var nl = [];
488 while (n = n.previousSibling) nl.unshift(n);
489 return nl;
490 },
491 'self' : function (n) {
492 return [n];
493 },
494 'document-root' : function (n) {
495 return [n.ownerDocument || n];
496 }
497};
498XPath.axis = function (fn, nt/*, pr..., nl*/) {
499 var r, x, al = arguments.length - 1, nl = arguments[al], ap = Array.prototype;
500 for (var i = 0, j, l = nl.length; --l >= 0;) {
501 x = fn.call(this, nl[i++]);
502 if (nt && x.length) x = ap.filter.call(x, nt, this);
503 for (j = 2; j < al && x.length; x = ap.filter.call(x, arguments[j++], this));
504 r = r ? this.union(r, x) : x;
505 }
506 return r || [];
507};
508XPath.cache = {};
509
510/**
511 * Extends the native <code>Node</code> class with additional functionality.
512 * <p>Not available in Internet Exporer which don&rsquo;t have a <code>Node</code> class.</p>
513 * <p>See <a href="http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#ID-1950641247" target="_blank">http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#ID-1950641247</a></code>.</p>
514 * @class Node
515 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
516 */
517/**
518 * Compares a node with this node with regard to their position in the document and according to the document order.
519 * <p>When comparing two attribute nodes; <code>32</code> is returned if they have the
520 * same <code>ownerElement</code>, otherwise <code>0</code>. This is probably not standard,
521 * but it&rsquo;s what Firefox return, so we do the same.</p>
522 * <pre>
523 * DOCUMENT_POSITION_DISCONNECTED = 1;
524 * DOCUMENT_POSITION_PRECEDING = 2;
525 * DOCUMENT_POSITION_FOLLOWING = 4;
526 * DOCUMENT_POSITION_CONTAINS = 8;
527 * DOCUMENT_POSITION_IS_CONTAINED = 16;
528 * DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32;
529 * </pre>
530 * <p>See <a href="http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#Node3-compareDocumentPosition" target="_blank">http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#Node3-compareDocumentPosition</a></code>.</p>
531 * @function {number} compareDocumentPosition
532 * @param {Node} n - node to compare against.
533 * @returns <code>0</code> for nodes are equals or a number with some of the above bits set.
534 */
535/**
536 * Check if this node contains another node.
537 * @function {boolean} contains
538 * @param {Node} n - node to compare against.
539 * @returns <code>true</code> if <code>this</code> node cotains node <code>n</code>.
540 */
541function compareDocumentPosition (n) {
542 if (this == n) return 0; // Same
543 if (this.nodeType == 2 && n.nodeType == 2)
544 return (this.ownerElement && this.ownerElement == n.ownerElement) ? 32 : 0; // IMPLEMENT_SPECIFIC
545 var l = this.ownerElement || this, r = n.ownerElement || n;
546 if (l.sourceIndex >= 0 && r.sourceIndex >= 0 && l.contains && r.contains) {
547 return (
548 ((l.contains(r) && 16) || (r.contains(l) && 8))
549 | ((l.sourceIndex < r.sourceIndex && 4) || (r.sourceIndex < l.sourceIndex && 2))
550 ) || 1;
551 }
552 var la = l, ra = r, ld = 0, rd = 0;
553 while (la = la.parentNode) ld++;
554 while (ra = ra.parentNode) rd++;
555 if (ld > rd) {
556 while (ld-- != rd) l = l.parentNode;
557 if (l == r) return 2|8; // Preceding|Contains
558 }
559 else if (rd > ld) {
560 while (rd-- != ld) r = r.parentNode;
561 if (r == l) return 4|16; // Following|Contained By
562 }
563 while ((la = l.parentNode) != (ra = r.parentNode))
564 if (!(l = la) || !(r = ra)) return 1; // Disconnected
565 while (l = l.nextSibling)
566 if (l == r) return 4; // Following
567 return 2; // Preceding
568};
569if (w.Node) {
570 var np = w.Node.prototype;
571 if (f || !np.compareDocumentPosition)
572 np.compareDocumentPosition = compareDocumentPosition;
573 if (f || !np.contains) {
574 np.contains = function (n) {
575 return Boolean(this.compareDocumentPosition(n) & 16);
576 };
577 }
578}
579else
580 XPath.compareDocumentPosition = compareDocumentPosition;
581/**
582 * Exception throw when parser or expression fails.
583 * <p>See <code><a href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathException" target="_blank">http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathException</a></code>.</p>
584 * @class XPathException
585 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
586 */
587/**
588 * Namespace error.
589 * @property {static read number} NAMESPACE_ERR
590 */
591/**
592 * Expression syntax error.
593 * @property {static read number} INVALID_EXPRESSION_ERR
594 */
595/**
596 * Result type error.
597 * @property {static read number} TYPE_ERR
598 */
599/**
600 * XPathException constructor.
601 * @constructor XPathException
602 * @param {number} c - error code.
603 * @param {string} m - error message.
604 * @see NAMESPACE_ERR
605 * @see INVALID_EXPRESSION_ERR
606 * @see TYPE_ERR
607 */
608/**
609 * Exception name.
610 * @property {read string} name
611 */
612/**
613 * Exception code.
614 * @property {read number} code
615 * @see NAMESPACE_ERR
616 * @see INVALID_EXPRESSION_ERR
617 * @see TYPE_ERR
618 */
619/**
620 * Exception message.
621 * @property {read string} message
622 */
623if (f || !w.XPathException) {
624 function XPathException (c, m) {
625 this.name = 'XPathException';
626 this.code = c;
627 this.message = m;
628 }
629 var e = XPathException, p = new Error;
630 p.toString = function () {
631 return this.name+':'+this.message;
632 };
633 e.prototype = p;
634 e.NAMESPACE_ERR = 14;
635 e.INVALID_EXPRESSION_ERR = 51;
636 e.TYPE_ERR = 52;
637 w.XPathException = e;
638}
639/**
640 * Namespace resolver.
641 * <p>See <code><a href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathNSResolver" target="_blank">http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathNSResolver</a></code>.</p>
642 * @class XPathNSResolver
643 * @see XPathEvaluator.createNSResolver
644 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
645 */
646/**
647 * Look up a namespace URI by it&rsquo;s prefix use in document.
648 * @function {string} lookupNamespaceURI
649 * @param {string} p - <code>xmlns:</code> prefix, empty string for <code>targetNamespace</code>.
650 * @returns associated namespace URI, or <code>undefined</code> if none is found.
651 */
652if (f || !w.XPathNSResolver) {
653 function XPathNSResolver (n) {
654 this.ns = {};
655 for (var m, a, i = n.attributes.length; --i >= 0;)
656 if (m = /xmlns:(.+)/.exec((a = n.attributes[i]).nodeName))
657 this.ns[m[1]] = a.nodeValue;
658 this.ns[''] = n.getAttribute('targetNamespace');
659 }
660 XPathNSResolver.prototype = {
661 lookupNamespaceURI : function (p) {
662 return this.ns[p || ''];
663 }
664 };
665 w.XPathNSResolver = XPathNSResolver;
666}
667/**
668 * A pre-parsed XPath expression.
669 * <p>See <code><a href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression" target="_blank">http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression</a></code>.</p>
670 * @class XPathExpression
671 * @see XPathEvaluator.createExpression
672 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
673 */
674/**
675 * Evaluate this pre-parsed expression.
676 * @function {XPathResult} evaluate
677 * @param {Node} n - context node.
678 * @param {number} rt - return type, see <code>{@link XPathResult}</code>.
679 * @param {XPathResult} r - <code>{@link XPathResult}</code> that maybe reuse, or <code>null</code>.
680 * @returns a <code>{@link XPathResult}</code>.
681 */
682if (f || !w.XPathExpression) {
683 function XPathExpression (e, nsr) {
684 this.fn = XPath.cache[e] || (XPath.cache[e] = new XPath(e));
685 this.nsr = nsr;
686 }
687 XPathExpression.prototype = {
688 evaluate : function (n, rt) {
689 return new XPathResult(this.fn(n, this.nsr), rt);
690 }
691 };
692 w.XPathExpression = XPathExpression;
693}
694/**
695 * Container for XPath results.
696 * <p>See <code><a href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult" target="_blank">http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult</a></code>.</p>
697 * @class XPathResult
698 * @see XPathEvaluator.evaluate
699 * @see XPathExpression.evaluate
700 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
701 */
702/**
703 * Result will be accessed unconverted as the expression returned it.
704 * @property {static read number} ANY_TYPE
705 */
706/**
707 * Result will be accessed as a number.
708 * @property {static read number} NUMBER_TYPE
709 * @see numberValue
710 */
711/**
712 * Result will be accessed as a string.
713 * @property {static read number} STRING_TYPE
714 * @see stringValue
715 */
716/**
717 * Result will be accessed as boolean.
718 * @property {static read number} BOOLEAN_TYPE
719 * @see booleanValue
720 */
721/**
722 * Result will be accessed iteratively, node order insignificant.
723 * <p>This is equal to <code>{@link ORDERED_NODE_ITERATOR_TYPE}</code>
724 * since the result is always document-ordered.</p>
725 * @property {static read number} UNORDERED_NODE_ITERATOR_TYPE
726 * @see iterateNext
727 */
728/**
729 * Result will be accessed iteratively which must be document-ordered.
730 * @property {static read number} ORDERED_NODE_ITERATOR_TYPE
731 * @see iterateNext
732 */
733/**
734 * Result will be accessed as a snapshot list of nodes, node order insignificant.
735 * <p>This is equal to <code>{@link ORDERED_NODE_SNAPSHOT_TYPE}</code>
736 * since the result is always document-ordered.</p>
737 * @property {static read number} UNORDERED_NODE_SNAPSHOT_TYPE
738 * @see snapshotLength
739 * @see snapshotItem
740 */
741/**
742 * Result will be accessed as a snapshot list of nodes which must be document-ordered.
743 * @property {static read number} ORDERED_NODE_SNAPSHOT_TYPE
744 * @see snapshotLength
745 * @see snapshotItem
746 */
747/**
748 * Result will be accessed as a single node value, any of the resulting nodes.
749 * <p>This is equal to <code>{@link FIRST_ORDERED_NODE_TYPE}</code>
750 * since the result is always document-ordered.</p>
751 * @property {static read number} ANY_UNORDERED_NODE_TYPE
752 * @see singleNodeValue
753 */
754/**
755 * Result will be accessed as a single node value, the first resulting node in document-ordered.
756 * @property {static read number} FIRST_ORDERED_NODE_TYPE
757 * @see singleNodeValue
758 */
759/**
760 * Convert result to number.
761 * @property {static read number} NUMBER_TYPE
762 */
763/**
764 * Convert result to number.
765 * @property {static read number} NUMBER_TYPE
766 */
767/**
768 * Convert result to number.
769 * @property {static read number} NUMBER_TYPE
770 */
771/**
772 * Convert result to number.
773 * @property {static read number} NUMBER_TYPE
774 */
775/**
776 * Convert result to number.
777 * @property {static read number} NUMBER_TYPE
778 */
779/**
780 * Resulting number.
781 * @property {read number} numberValue
782 * @see NUMBER_TYPE
783 */
784/**
785 * Resulting string.
786 * @property {read string} stringValue
787 * @see STRING_TYPE
788 */
789/**
790 * Resulting boolean.
791 * @property {read boolean} booleanValue
792 * @see BOOLEAN_TYPE
793 */
794/**
795 * Signifies that the iterator has become invalid.
796 * @property {read boolean} invalidIteratorState
797 * @see UNORDERED_NODE_ITERATOR_TYPE
798 * @see ORDERED_NODE_ITERATOR_TYPE
799 */
800/**
801 * The number of nodes in the result snapshot.
802 * @property {read number} snapshotLength
803 * @see UNORDERED_NODE_SNAPSHOT_TYPE
804 * @see ORDERED_NODE_SNAPSHOT_TYPE
805 */
806/**
807 * The value of this single node result, maybe <code>undefined</code>.
808 * @property {read object} singleNodeValue
809 * @see ANY_UNORDERED_NODE_TYPE
810 * @see FIRST_ORDERED_NODE_TYPE
811 */
812/**
813 * Unconverted result as returned by our internal evaluator.
814 * <p>This is a non-standard property which is set to the raw unconverted result from our
815 * expression evaluator. It&rsquo;s of the type <code>number</code>, <code>string</code>,
816 * <code>boolean</code> or an <code>{@link Array}</code> with nodes depending on expression.
817 * If you prefer to work with arrays instead of <code>{@link XPathResult.snapshotItem}</code>
818 * You can check for this property and use it directly.</p>
819 * <h3>Example</h3>
820 * <pre>
821 * function selectNodes (expr) {
822 * // Cross-browser safe way of selecting nodes and return an Array
823 * var r = document.evaluate('//LI', document, null, 7, null);
824 * if (typeof r.value != 'undefined') return r.value;
825 * var a = [];
826 * for (var i = r.snapshotLength; --i >= 0; a[i] = r.snapshotItem(i));
827 * return a;
828 * }
829 * </pre>
830 * @property {read object} value
831 * @see ANY_TYPE
832 */
833/**
834 * Iterates and returns the next node from the resuling nodes.
835 * @function {object} iterateNext
836 * @returns a <code>Node</code>, or <code>undefined</code> if there are no more nodes.
837 */
838/**
839 * Returns the <code>index</code>th item in the snapshot collection.
840 * @function {object} snapshotItem
841 * @param {number} i - index of resuling node to return.
842 * @returns the <code>Node</code>, at provided index or <code>undefined</code> if invalid.
843 */
844if (f || !w.XPathResult) {
845 function XPathResult (r, rt) {
846 if (rt == 0) {
847 switch (typeof r) {
848 default: rt++;
849 case 'boolean': rt++;
850 case 'string': rt++;
851 case 'number': rt++;
852 }
853 }
854 this.resultType = rt;
855 switch (rt) {
856 case 1:
857 this.numberValue = XPath.number(r);
858 return;
859 case 2:
860 this.stringValue = XPath.string(r);
861 return;
862 case 3:
863 this.booleanValue = XPath.bool(r);
864 return;
865 case 4:
866 case 5:
867 if (r instanceof Array) {
868 this.value = r;
869 this.index = 0;
870 this.invalidIteratorState = false;
871 return;
872 }
873 break;
874 case 6:
875 case 7:
876 if (r instanceof Array) {
877 this.value = r;
878 this.snapshotLength = r.length;
879 return;
880 }
881 break;
882 case 8:
883 case 9:
884 if (r instanceof Array) {
885 this.singleNodeValue = r[0];
886 return;
887 }
888 }
889 throw new XPathException(52);
890 }
891 var r = XPathResult;
892 r.ANY_TYPE = 0;
893 r.NUMBER_TYPE = 1;
894 r.STRING_TYPE = 2;
895 r.BOOLEAN_TYPE = 3;
896 r.UNORDERED_NODE_ITERATOR_TYPE = 4;
897 r.ORDERED_NODE_ITERATOR_TYPE = 5;
898 r.UNORDERED_NODE_SNAPSHOT_TYPE = 6;
899 r.ORDERED_NODE_SNAPSHOT_TYPE = 7;
900 r.ANY_UNORDERED_NODE_TYPE = 8;
901 r.FIRST_ORDERED_NODE_TYPE = 9;
902 r.prototype = {
903 iterateNext : function () {
904 switch (this.resultType) {
905 case 4:
906 case 5:
907 return this.value[this.index++];
908 }
909 throw new XPathException(52);
910 },
911 snapshotItem : function (i) {
912 switch (this.resultType) {
913 case 6:
914 case 7:
915 return this.value[i];
916 }
917 throw new XPathException(52);
918 }
919 };
920 w.XPathResult = r;
921}
922/**
923 * An interface with the XPath functionality.
924 * <p><code>Document.prototype</code> and/or <code>document</code> will be
925 * extended using <code>{@link install}</code> to implements it&rsquo;s functions.</p>
926 * <p>See <code><a href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator" target="_blank">http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator</a></code>.</p>
927 * @interface XPathEvaluator
928 * @author Henrik Lindqvist &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;
929 */
930/**
931 * Non-standard function that extends the provided object with <code>{@link XPathEvaluator}</code> functions.
932 * @function {static} install
933 * @param {object} o - object (i.e document node) to extend.
934 * @param {optional boolean} f - force replace the build-in function even if they exists.
935 */
936/**
937 * Creates a pre-parsed expression.
938 * @function {XPathExpression} createExpression
939 * @param {string} e - expression.
940 * @param {XPathNSResolver} nsr - namespace resolver to use when evaluating, or <code>null</code>.
941 * @returns a new <code>{@link XPathExpression}</code>.
942 */
943/**
944 * Create a namespace resolver by scanning a node for <code>xmlns:</code> attributes.
945 * @function {XPathNSResolver} createNSResolver
946 * @param {Node} n - an <code>Node</code> with defined namespace attributes (i.e the documentElement).
947 * @returns a new <code>{@link XPathNSResolver}</code>.
948 */
949/**
950 * Evaluate an expression.
951 * <p>Same as <code>new XPathExpression(e, nsr).evaluate(n, rt)</code>.</p>
952 * @function {XPathResult} evaluate
953 * @param {string} e - XPath expression string.
954 * @param {Node} n - context node.
955 * @param {XPathNSResolver} nsr - namespace resolver to use when evaluating, or <code>null</code>.
956 * @param {number} rt - return type, see <code>{@link XPathResult}</code>.
957 * @param {XPathResult} r - <code>{@link XPathResult}</code> that maybe reuse, or <code>null</code>. Ignored.
958 * @returns a <code>{@link XPathResult}</code>.
959 */
960if (f || !w.XPathEvaluator) {
961 function XPathEvaluator () {}
962 var e = XPathEvaluator;
963 e.prototype = {
964 createExpression : function (e, nsr) {
965 return new XPathExpression(e, nsr);
966 },
967 createNSResolver : function (n) {
968 return new XPathNSResolver(n);
969 },
970 evaluate : function (e, n, nsr, rt) {
971 return new XPathExpression(e, nsr).evaluate(n, rt);
972 }
973 };
974 e.install = function (o, f) {
975 for (var k in XPathEvaluator.prototype)
976 if (f || !o[k]) o[k] = XPathEvaluator.prototype[k];
977 };
978 w.XPathEvaluator = e;
979 if (w.Document)
980 e.install(w.Document.prototype, f);
981 else
982 e.install(document, f);
983 w.XPath = XPath;
984}
985
986})(window, document, (/WebKit/.test(navigator.userAgent) || /Node\.js/.test(navigator.userAgent))); // force replace?
Note: See TracBrowser for help on using the repository browser.