/* * xpath.js * * An XPath 1.0 library for JavaScript. * * Cameron McCormack * * This work is licensed under the Creative Commons Attribution-ShareAlike * License. To view a copy of this license, visit * * http://creativecommons.org/licenses/by-sa/2.0/ * * or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, * California 94305, USA. * * Revision 20: April 26, 2011 * Fixed a typo resulting in FIRST_ORDERED_NODE_TYPE results being wrong, * thanks to . * * Revision 19: November 29, 2005 * Nodesets now store their nodes in a height balanced tree, increasing * performance for the common case of selecting nodes in document order, * thanks to S閎astien Cramatte . * AVL tree code adapted from Raimund Neumann . * * Revision 18: October 27, 2005 * DOM 3 XPath support. Caveats: * - namespace prefixes aren't resolved in XPathEvaluator.createExpression, * but in XPathExpression.evaluate. * - XPathResult.invalidIteratorState is not implemented. * * Revision 17: October 25, 2005 * Some core XPath function fixes and a patch to avoid crashing certain * versions of MSXML in PathExpr.prototype.getOwnerElement, thanks to * S閎astien Cramatte . * * Revision 16: September 22, 2005 * Workarounds for some IE 5.5 deficiencies. * Fixed problem with prefix node tests on attribute nodes. * * Revision 15: May 21, 2005 * Fixed problem with QName node tests on elements with an xmlns="...". * * Revision 14: May 19, 2005 * Fixed QName node tests on attribute node regression. * * Revision 13: May 3, 2005 * Node tests are case insensitive now if working in an HTML DOM. * * Revision 12: April 26, 2005 * Updated licence. Slight code changes to enable use of Dean * Edwards' script compression, http://dean.edwards.name/packer/ . * * Revision 11: April 23, 2005 * Fixed bug with 'and' and 'or' operators, fix thanks to * Sandy McArthur . * * Revision 10: April 15, 2005 * Added support for a virtual root node, supposedly helpful for * implementing XForms. Fixed problem with QName node tests and * the parent axis. * * Revision 9: March 17, 2005 * Namespace resolver tweaked so using the document node as the context * for namespace lookups is equivalent to using the document element. * * Revision 8: February 13, 2005 * Handle implicit declaration of 'xmlns' namespace prefix. * Fixed bug when comparing nodesets. * Instance data can now be associated with a FunctionResolver, and * workaround for MSXML not supporting 'localName' and 'getElementById', * thanks to Grant Gongaware. * Fix a few problems when the context node is the root node. * * Revision 7: February 11, 2005 * Default namespace resolver fix from Grant Gongaware * . * * Revision 6: February 10, 2005 * Fixed bug in 'number' function. * * Revision 5: February 9, 2005 * Fixed bug where text nodes not getting converted to string values. * * Revision 4: January 21, 2005 * Bug in 'name' function, fix thanks to Bill Edney. * Fixed incorrect processing of namespace nodes. * Fixed NamespaceResolver to resolve 'xml' namespace. * Implemented union '|' operator. * * Revision 3: January 14, 2005 * Fixed bug with nodeset comparisons, bug lexing < and >. * * Revision 2: October 26, 2004 * QName node test namespace handling fixed. Few other bug fixes. * * Revision 1: August 13, 2004 * Bug fixes from William J. Edney . * Added minimal licence. * * Initial version: June 14, 2004 */ // non-node wrapper var xpath = (typeof exports === 'undefined') ? {} : exports; (function(exports) { "use strict"; // XPathParser /////////////////////////////////////////////////////////////// XPathParser.prototype = new Object(); XPathParser.prototype.constructor = XPathParser; XPathParser.superclass = Object.prototype; function XPathParser() { this.init(); } XPathParser.prototype.init = function() { this.reduceActions = []; this.reduceActions[3] = function(rhs) { return new OrOperation(rhs[0], rhs[2]); }; this.reduceActions[5] = function(rhs) { return new AndOperation(rhs[0], rhs[2]); }; this.reduceActions[7] = function(rhs) { return new EqualsOperation(rhs[0], rhs[2]); }; this.reduceActions[8] = function(rhs) { return new NotEqualOperation(rhs[0], rhs[2]); }; this.reduceActions[10] = function(rhs) { return new LessThanOperation(rhs[0], rhs[2]); }; this.reduceActions[11] = function(rhs) { return new GreaterThanOperation(rhs[0], rhs[2]); }; this.reduceActions[12] = function(rhs) { return new LessThanOrEqualOperation(rhs[0], rhs[2]); }; this.reduceActions[13] = function(rhs) { return new GreaterThanOrEqualOperation(rhs[0], rhs[2]); }; this.reduceActions[15] = function(rhs) { return new PlusOperation(rhs[0], rhs[2]); }; this.reduceActions[16] = function(rhs) { return new MinusOperation(rhs[0], rhs[2]); }; this.reduceActions[18] = function(rhs) { return new MultiplyOperation(rhs[0], rhs[2]); }; this.reduceActions[19] = function(rhs) { return new DivOperation(rhs[0], rhs[2]); }; this.reduceActions[20] = function(rhs) { return new ModOperation(rhs[0], rhs[2]); }; this.reduceActions[22] = function(rhs) { return new UnaryMinusOperation(rhs[1]); }; this.reduceActions[24] = function(rhs) { return new BarOperation(rhs[0], rhs[2]); }; this.reduceActions[25] = function(rhs) { return new PathExpr(undefined, undefined, rhs[0]); }; this.reduceActions[27] = function(rhs) { rhs[0].locationPath = rhs[2]; return rhs[0]; }; this.reduceActions[28] = function(rhs) { rhs[0].locationPath = rhs[2]; rhs[0].locationPath.steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), [])); return rhs[0]; }; this.reduceActions[29] = function(rhs) { return new PathExpr(rhs[0], [], undefined); }; this.reduceActions[30] = function(rhs) { if (Utilities.instance_of(rhs[0], PathExpr)) { if (rhs[0].filterPredicates == undefined) { rhs[0].filterPredicates = []; } rhs[0].filterPredicates.push(rhs[1]); return rhs[0]; } else { return new PathExpr(rhs[0], [rhs[1]], undefined); } }; this.reduceActions[32] = function(rhs) { return rhs[1]; }; this.reduceActions[33] = function(rhs) { return new XString(rhs[0]); }; this.reduceActions[34] = function(rhs) { return new XNumber(rhs[0]); }; this.reduceActions[36] = function(rhs) { return new FunctionCall(rhs[0], []); }; this.reduceActions[37] = function(rhs) { return new FunctionCall(rhs[0], rhs[2]); }; this.reduceActions[38] = function(rhs) { return [ rhs[0] ]; }; this.reduceActions[39] = function(rhs) { rhs[2].unshift(rhs[0]); return rhs[2]; }; this.reduceActions[43] = function(rhs) { return new LocationPath(true, []); }; this.reduceActions[44] = function(rhs) { rhs[1].absolute = true; return rhs[1]; }; this.reduceActions[46] = function(rhs) { return new LocationPath(false, [ rhs[0] ]); }; this.reduceActions[47] = function(rhs) { rhs[0].steps.push(rhs[2]); return rhs[0]; }; this.reduceActions[49] = function(rhs) { return new Step(rhs[0], rhs[1], []); }; this.reduceActions[50] = function(rhs) { return new Step(Step.CHILD, rhs[0], []); }; this.reduceActions[51] = function(rhs) { return new Step(rhs[0], rhs[1], rhs[2]); }; this.reduceActions[52] = function(rhs) { return new Step(Step.CHILD, rhs[0], rhs[1]); }; this.reduceActions[54] = function(rhs) { return [ rhs[0] ]; }; this.reduceActions[55] = function(rhs) { rhs[1].unshift(rhs[0]); return rhs[1]; }; this.reduceActions[56] = function(rhs) { if (rhs[0] == "ancestor") { return Step.ANCESTOR; } else if (rhs[0] == "ancestor-or-self") { return Step.ANCESTORORSELF; } else if (rhs[0] == "attribute") { return Step.ATTRIBUTE; } else if (rhs[0] == "child") { return Step.CHILD; } else if (rhs[0] == "descendant") { return Step.DESCENDANT; } else if (rhs[0] == "descendant-or-self") { return Step.DESCENDANTORSELF; } else if (rhs[0] == "following") { return Step.FOLLOWING; } else if (rhs[0] == "following-sibling") { return Step.FOLLOWINGSIBLING; } else if (rhs[0] == "namespace") { return Step.NAMESPACE; } else if (rhs[0] == "parent") { return Step.PARENT; } else if (rhs[0] == "preceding") { return Step.PRECEDING; } else if (rhs[0] == "preceding-sibling") { return Step.PRECEDINGSIBLING; } else if (rhs[0] == "self") { return Step.SELF; } return -1; }; this.reduceActions[57] = function(rhs) { return Step.ATTRIBUTE; }; this.reduceActions[59] = function(rhs) { if (rhs[0] == "comment") { return new NodeTest(NodeTest.COMMENT, undefined); } else if (rhs[0] == "text") { return new NodeTest(NodeTest.TEXT, undefined); } else if (rhs[0] == "processing-instruction") { return new NodeTest(NodeTest.PI, undefined); } else if (rhs[0] == "node") { return new NodeTest(NodeTest.NODE, undefined); } return new NodeTest(-1, undefined); }; this.reduceActions[60] = function(rhs) { return new NodeTest(NodeTest.PI, rhs[2]); }; this.reduceActions[61] = function(rhs) { return rhs[1]; }; this.reduceActions[63] = function(rhs) { rhs[1].absolute = true; rhs[1].steps.unshift(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), [])); return rhs[1]; }; this.reduceActions[64] = function(rhs) { rhs[0].steps.push(new Step(Step.DESCENDANTORSELF, new NodeTest(NodeTest.NODE, undefined), [])); rhs[0].steps.push(rhs[2]); return rhs[0]; }; this.reduceActions[65] = function(rhs) { return new Step(Step.SELF, new NodeTest(NodeTest.NODE, undefined), []); }; this.reduceActions[66] = function(rhs) { return new Step(Step.PARENT, new NodeTest(NodeTest.NODE, undefined), []); }; this.reduceActions[67] = function(rhs) { return new VariableReference(rhs[1]); }; this.reduceActions[68] = function(rhs) { return new NodeTest(NodeTest.NAMETESTANY, undefined); }; this.reduceActions[69] = function(rhs) { var prefix = rhs[0].substring(0, rhs[0].indexOf(":")); return new NodeTest(NodeTest.NAMETESTPREFIXANY, prefix); }; this.reduceActions[70] = function(rhs) { return new NodeTest(NodeTest.NAMETESTQNAME, rhs[0]); }; }; XPathParser.actionTable = [ " s s sssssssss s ss s ss", " s ", "r rrrrrrrrr rrrrrrr rr r ", " rrrrr ", " s s sssssssss s ss s ss", "rs rrrrrrrr s sssssrrrrrr rrs rs ", " s s sssssssss s ss s ss", " s ", " s ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", " s ", " s ", " s s sssss s s ", "r rrrrrrrrr rrrrrrr rr r ", "a ", "r s rr r ", "r sr rr r ", "r s rr s rr r ", "r rssrr rss rr r ", "r rrrrr rrrss rr r ", "r rrrrrsss rrrrr rr r ", "r rrrrrrrr rrrrr rr r ", "r rrrrrrrr rrrrrs rr r ", "r rrrrrrrr rrrrrr rr r ", "r rrrrrrrr rrrrrr rr r ", "r srrrrrrrr rrrrrrs rr sr ", "r srrrrrrrr rrrrrrs rr r ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrr rrrrrr rr r ", "r rrrrrrrr rrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr r ", " sssss ", "r rrrrrrrrr rrrrrrr rr sr ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", " s ", "r srrrrrrrr rrrrrrs rr r ", "r rrrrrrrr rrrrr rr r ", " s ", " s ", " rrrrr ", " s s sssssssss s sss s ss", "r srrrrrrrr rrrrrrs rr r ", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss s ss s ss", " s s sssssssss ss s ss", " s s sssssssss s ss s ss", " s s sssss s s ", " s s sssss s s ", "r rrrrrrrrr rrrrrrr rr rr ", " s s sssss s s ", " s s sssss s s ", "r rrrrrrrrr rrrrrrr rr sr ", "r rrrrrrrrr rrrrrrr rr sr ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr rr ", " s ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", " rr ", " s ", " rs ", "r sr rr r ", "r s rr s rr r ", "r rssrr rss rr r ", "r rssrr rss rr r ", "r rrrrr rrrss rr r ", "r rrrrr rrrss rr r ", "r rrrrr rrrss rr r ", "r rrrrr rrrss rr r ", "r rrrrrsss rrrrr rr r ", "r rrrrrsss rrrrr rr r ", "r rrrrrrrr rrrrr rr r ", "r rrrrrrrr rrrrr rr r ", "r rrrrrrrr rrrrr rr r ", "r rrrrrrrr rrrrrr rr r ", " r ", " s ", "r srrrrrrrr rrrrrrs rr r ", "r srrrrrrrr rrrrrrs rr r ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr r ", "r rrrrrrrrr rrrrrrr rr rr ", "r rrrrrrrrr rrrrrrr rr rr ", " s s sssssssss s ss s ss", "r rrrrrrrrr rrrrrrr rr rr ", " r " ]; XPathParser.actionTableNumber = [ " 1 0 /.-,+*)(' & %$ # \"!", " J ", "a aaaaaaaaa aaaaaaa aa a ", " YYYYY ", " 1 0 /.-,+*)(' & %$ # \"!", "K1 KKKKKKKK . +*)('KKKKKK KK# K\" ", " 1 0 /.-,+*)(' & %$ # \"!", " N ", " O ", "e eeeeeeeee eeeeeee ee ee ", "f fffffffff fffffff ff ff ", "d ddddddddd ddddddd dd dd ", "B BBBBBBBBB BBBBBBB BB BB ", "A AAAAAAAAA AAAAAAA AA AA ", " P ", " Q ", " 1 . +*)(' # \" ", "b bbbbbbbbb bbbbbbb bb b ", " ", "! S !! ! ", "\" T\" \"\" \" ", "$ V $$ U $$ $ ", "& &ZY&& &XW && & ", ") ))))) )))\\[ )) ) ", ". ....._^] ..... .. . ", "1 11111111 11111 11 1 ", "5 55555555 55555` 55 5 ", "7 77777777 777777 77 7 ", "9 99999999 999999 99 9 ", ": c:::::::: ::::::b :: a: ", "I fIIIIIIII IIIIIIe II I ", "= ========= ======= == == ", "? ????????? ??????? ?? ?? ", "C CCCCCCCCC CCCCCCC CC CC ", "J JJJJJJJJ JJJJJJ JJ J ", "M MMMMMMMM MMMMMM MM M ", "N NNNNNNNNN NNNNNNN NN N ", "P PPPPPPPPP PPPPPPP PP P ", " +*)(' ", "R RRRRRRRRR RRRRRRR RR aR ", "U UUUUUUUUU UUUUUUU UU U ", "Z ZZZZZZZZZ ZZZZZZZ ZZ ZZ ", "c ccccccccc ccccccc cc cc ", " j ", "L fLLLLLLLL LLLLLLe LL L ", "6 66666666 66666 66 6 ", " k ", " l ", " XXXXX ", " 1 0 /.-,+*)(' & %$m # \"!", "_ f________ ______e __ _ ", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 0 /.-,+*)(' %$ # \"!", " 1 0 /.-,+*)(' & %$ # \"!", " 1 . +*)(' # \" ", " 1 . +*)(' # \" ", "> >>>>>>>>> >>>>>>> >> >> ", " 1 . +*)(' # \" ", " 1 . +*)(' # \" ", "Q QQQQQQQQQ QQQQQQQ QQ aQ ", "V VVVVVVVVV VVVVVVV VV aV ", "T TTTTTTTTT TTTTTTT TT T ", "@ @@@@@@@@@ @@@@@@@ @@ @@ ", " \x87 ", "[ [[[[[[[[[ [[[[[[[ [[ [[ ", "D DDDDDDDDD DDDDDDD DD DD ", " HH ", " \x88 ", " F\x89 ", "# T# ## # ", "% V %% U %% % ", "' 'ZY'' 'XW '' ' ", "( (ZY(( (XW (( ( ", "+ +++++ +++\\[ ++ + ", "* ***** ***\\[ ** * ", "- ----- ---\\[ -- - ", ", ,,,,, ,,,\\[ ,, , ", "0 00000_^] 00000 00 0 ", "/ /////_^] ///// // / ", "2 22222222 22222 22 2 ", "3 33333333 33333 33 3 ", "4 44444444 44444 44 4 ", "8 88888888 888888 88 8 ", " ^ ", " \x8a ", "; f;;;;;;;; ;;;;;;e ;; ; ", "< f<<<<<<<< <<<<<?@ AB CDEFGH IJ ", " ", " ", " ", "L456789:;<=>?@ AB CDEFGH IJ ", " M EFGH IJ ", " N;<=>?@ AB CDEFGH IJ ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " S EFGH IJ ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " e ", " ", " ", " ", " ", " ", " ", " ", " ", " h J ", " i j ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "o456789:;<=>?@ ABpqCDEFGH IJ ", " ", " r6789:;<=>?@ AB CDEFGH IJ ", " s789:;<=>?@ AB CDEFGH IJ ", " t89:;<=>?@ AB CDEFGH IJ ", " u89:;<=>?@ AB CDEFGH IJ ", " v9:;<=>?@ AB CDEFGH IJ ", " w9:;<=>?@ AB CDEFGH IJ ", " x9:;<=>?@ AB CDEFGH IJ ", " y9:;<=>?@ AB CDEFGH IJ ", " z:;<=>?@ AB CDEFGH IJ ", " {:;<=>?@ AB CDEFGH IJ ", " |;<=>?@ AB CDEFGH IJ ", " };<=>?@ AB CDEFGH IJ ", " ~;<=>?@ AB CDEFGH IJ ", " \x7f=>?@ AB CDEFGH IJ ", "\x80456789:;<=>?@ AB CDEFGH IJ\x81", " \x82 EFGH IJ ", " \x83 EFGH IJ ", " ", " \x84 GH IJ ", " \x85 GH IJ ", " i \x86 ", " i \x87 ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "o456789:;<=>?@ AB\x8cqCDEFGH IJ ", " ", " " ]; XPathParser.productions = [ [1, 1, 2], [2, 1, 3], [3, 1, 4], [3, 3, 3, -9, 4], [4, 1, 5], [4, 3, 4, -8, 5], [5, 1, 6], [5, 3, 5, -22, 6], [5, 3, 5, -5, 6], [6, 1, 7], [6, 3, 6, -23, 7], [6, 3, 6, -24, 7], [6, 3, 6, -6, 7], [6, 3, 6, -7, 7], [7, 1, 8], [7, 3, 7, -25, 8], [7, 3, 7, -26, 8], [8, 1, 9], [8, 3, 8, -12, 9], [8, 3, 8, -11, 9], [8, 3, 8, -10, 9], [9, 1, 10], [9, 2, -26, 9], [10, 1, 11], [10, 3, 10, -27, 11], [11, 1, 12], [11, 1, 13], [11, 3, 13, -28, 14], [11, 3, 13, -4, 14], [13, 1, 15], [13, 2, 13, 16], [15, 1, 17], [15, 3, -29, 2, -30], [15, 1, -15], [15, 1, -16], [15, 1, 18], [18, 3, -13, -29, -30], [18, 4, -13, -29, 19, -30], [19, 1, 20], [19, 3, 20, -31, 19], [20, 1, 2], [12, 1, 14], [12, 1, 21], [21, 1, -28], [21, 2, -28, 14], [21, 1, 22], [14, 1, 23], [14, 3, 14, -28, 23], [14, 1, 24], [23, 2, 25, 26], [23, 1, 26], [23, 3, 25, 26, 27], [23, 2, 26, 27], [23, 1, 28], [27, 1, 16], [27, 2, 16, 27], [25, 2, -14, -3], [25, 1, -32], [26, 1, 29], [26, 3, -20, -29, -30], [26, 4, -21, -29, -15, -30], [16, 3, -33, 30, -34], [30, 1, 2], [22, 2, -4, 14], [24, 3, 14, -4, 23], [28, 1, -35], [28, 1, -2], [17, 2, -36, -18], [29, 1, -17], [29, 1, -19], [29, 1, -18] ]; XPathParser.DOUBLEDOT = 2; XPathParser.DOUBLECOLON = 3; XPathParser.DOUBLESLASH = 4; XPathParser.NOTEQUAL = 5; XPathParser.LESSTHANOREQUAL = 6; XPathParser.GREATERTHANOREQUAL = 7; XPathParser.AND = 8; XPathParser.OR = 9; XPathParser.MOD = 10; XPathParser.DIV = 11; XPathParser.MULTIPLYOPERATOR = 12; XPathParser.FUNCTIONNAME = 13; XPathParser.AXISNAME = 14; XPathParser.LITERAL = 15; XPathParser.NUMBER = 16; XPathParser.ASTERISKNAMETEST = 17; XPathParser.QNAME = 18; XPathParser.NCNAMECOLONASTERISK = 19; XPathParser.NODETYPE = 20; XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL = 21; XPathParser.EQUALS = 22; XPathParser.LESSTHAN = 23; XPathParser.GREATERTHAN = 24; XPathParser.PLUS = 25; XPathParser.MINUS = 26; XPathParser.BAR = 27; XPathParser.SLASH = 28; XPathParser.LEFTPARENTHESIS = 29; XPathParser.RIGHTPARENTHESIS = 30; XPathParser.COMMA = 31; XPathParser.AT = 32; XPathParser.LEFTBRACKET = 33; XPathParser.RIGHTBRACKET = 34; XPathParser.DOT = 35; XPathParser.DOLLAR = 36; XPathParser.prototype.tokenize = function(s1) { var types = []; var values = []; var s = s1 + '\0'; var pos = 0; var c = s.charAt(pos++); while (1) { while (c == ' ' || c == '\t' || c == '\r' || c == '\n') { c = s.charAt(pos++); } if (c == '\0' || pos >= s.length) { break; } if (c == '(') { types.push(XPathParser.LEFTPARENTHESIS); values.push(c); c = s.charAt(pos++); continue; } if (c == ')') { types.push(XPathParser.RIGHTPARENTHESIS); values.push(c); c = s.charAt(pos++); continue; } if (c == '[') { types.push(XPathParser.LEFTBRACKET); values.push(c); c = s.charAt(pos++); continue; } if (c == ']') { types.push(XPathParser.RIGHTBRACKET); values.push(c); c = s.charAt(pos++); continue; } if (c == '@') { types.push(XPathParser.AT); values.push(c); c = s.charAt(pos++); continue; } if (c == ',') { types.push(XPathParser.COMMA); values.push(c); c = s.charAt(pos++); continue; } if (c == '|') { types.push(XPathParser.BAR); values.push(c); c = s.charAt(pos++); continue; } if (c == '+') { types.push(XPathParser.PLUS); values.push(c); c = s.charAt(pos++); continue; } if (c == '-') { types.push(XPathParser.MINUS); values.push(c); c = s.charAt(pos++); continue; } if (c == '=') { types.push(XPathParser.EQUALS); values.push(c); c = s.charAt(pos++); continue; } if (c == '$') { types.push(XPathParser.DOLLAR); values.push(c); c = s.charAt(pos++); continue; } if (c == '.') { c = s.charAt(pos++); if (c == '.') { types.push(XPathParser.DOUBLEDOT); values.push(".."); c = s.charAt(pos++); continue; } if (c >= '0' && c <= '9') { var number = "." + c; c = s.charAt(pos++); while (c >= '0' && c <= '9') { number += c; c = s.charAt(pos++); } types.push(XPathParser.NUMBER); values.push(number); continue; } types.push(XPathParser.DOT); values.push('.'); continue; } if (c == '\'' || c == '"') { var delimiter = c; var literal = ""; while (pos < s.length && (c = s.charAt(pos)) !== delimiter) { literal += c; pos += 1; } if (c !== delimiter) { throw XPathException.fromMessage("Unterminated string literal: " + delimiter + literal); } pos += 1; types.push(XPathParser.LITERAL); values.push(literal); c = s.charAt(pos++); continue; } if (c >= '0' && c <= '9') { var number = c; c = s.charAt(pos++); while (c >= '0' && c <= '9') { number += c; c = s.charAt(pos++); } if (c == '.') { if (s.charAt(pos) >= '0' && s.charAt(pos) <= '9') { number += c; number += s.charAt(pos++); c = s.charAt(pos++); while (c >= '0' && c <= '9') { number += c; c = s.charAt(pos++); } } } types.push(XPathParser.NUMBER); values.push(number); continue; } if (c == '*') { if (types.length > 0) { var last = types[types.length - 1]; if (last != XPathParser.AT && last != XPathParser.DOUBLECOLON && last != XPathParser.LEFTPARENTHESIS && last != XPathParser.LEFTBRACKET && last != XPathParser.AND && last != XPathParser.OR && last != XPathParser.MOD && last != XPathParser.DIV && last != XPathParser.MULTIPLYOPERATOR && last != XPathParser.SLASH && last != XPathParser.DOUBLESLASH && last != XPathParser.BAR && last != XPathParser.PLUS && last != XPathParser.MINUS && last != XPathParser.EQUALS && last != XPathParser.NOTEQUAL && last != XPathParser.LESSTHAN && last != XPathParser.LESSTHANOREQUAL && last != XPathParser.GREATERTHAN && last != XPathParser.GREATERTHANOREQUAL) { types.push(XPathParser.MULTIPLYOPERATOR); values.push(c); c = s.charAt(pos++); continue; } } types.push(XPathParser.ASTERISKNAMETEST); values.push(c); c = s.charAt(pos++); continue; } if (c == ':') { if (s.charAt(pos) == ':') { types.push(XPathParser.DOUBLECOLON); values.push("::"); pos++; c = s.charAt(pos++); continue; } } if (c == '/') { c = s.charAt(pos++); if (c == '/') { types.push(XPathParser.DOUBLESLASH); values.push("//"); c = s.charAt(pos++); continue; } types.push(XPathParser.SLASH); values.push('/'); continue; } if (c == '!') { if (s.charAt(pos) == '=') { types.push(XPathParser.NOTEQUAL); values.push("!="); pos++; c = s.charAt(pos++); continue; } } if (c == '<') { if (s.charAt(pos) == '=') { types.push(XPathParser.LESSTHANOREQUAL); values.push("<="); pos++; c = s.charAt(pos++); continue; } types.push(XPathParser.LESSTHAN); values.push('<'); c = s.charAt(pos++); continue; } if (c == '>') { if (s.charAt(pos) == '=') { types.push(XPathParser.GREATERTHANOREQUAL); values.push(">="); pos++; c = s.charAt(pos++); continue; } types.push(XPathParser.GREATERTHAN); values.push('>'); c = s.charAt(pos++); continue; } if (c == '_' || Utilities.isLetter(c.charCodeAt(0))) { var name = c; c = s.charAt(pos++); while (Utilities.isNCNameChar(c.charCodeAt(0))) { name += c; c = s.charAt(pos++); } if (types.length > 0) { var last = types[types.length - 1]; if (last != XPathParser.AT && last != XPathParser.DOUBLECOLON && last != XPathParser.LEFTPARENTHESIS && last != XPathParser.LEFTBRACKET && last != XPathParser.AND && last != XPathParser.OR && last != XPathParser.MOD && last != XPathParser.DIV && last != XPathParser.MULTIPLYOPERATOR && last != XPathParser.SLASH && last != XPathParser.DOUBLESLASH && last != XPathParser.BAR && last != XPathParser.PLUS && last != XPathParser.MINUS && last != XPathParser.EQUALS && last != XPathParser.NOTEQUAL && last != XPathParser.LESSTHAN && last != XPathParser.LESSTHANOREQUAL && last != XPathParser.GREATERTHAN && last != XPathParser.GREATERTHANOREQUAL) { if (name == "and") { types.push(XPathParser.AND); values.push(name); continue; } if (name == "or") { types.push(XPathParser.OR); values.push(name); continue; } if (name == "mod") { types.push(XPathParser.MOD); values.push(name); continue; } if (name == "div") { types.push(XPathParser.DIV); values.push(name); continue; } } } if (c == ':') { if (s.charAt(pos) == '*') { types.push(XPathParser.NCNAMECOLONASTERISK); values.push(name + ":*"); pos++; c = s.charAt(pos++); continue; } if (s.charAt(pos) == '_' || Utilities.isLetter(s.charCodeAt(pos))) { name += ':'; c = s.charAt(pos++); while (Utilities.isNCNameChar(c.charCodeAt(0))) { name += c; c = s.charAt(pos++); } if (c == '(') { types.push(XPathParser.FUNCTIONNAME); values.push(name); continue; } types.push(XPathParser.QNAME); values.push(name); continue; } if (s.charAt(pos) == ':') { types.push(XPathParser.AXISNAME); values.push(name); continue; } } if (c == '(') { if (name == "comment" || name == "text" || name == "node") { types.push(XPathParser.NODETYPE); values.push(name); continue; } if (name == "processing-instruction") { if (s.charAt(pos) == ')') { types.push(XPathParser.NODETYPE); } else { types.push(XPathParser.PROCESSINGINSTRUCTIONWITHLITERAL); } values.push(name); continue; } types.push(XPathParser.FUNCTIONNAME); values.push(name); continue; } types.push(XPathParser.QNAME); values.push(name); continue; } throw new Error("Unexpected character " + c); } types.push(1); values.push("[EOF]"); return [types, values]; }; XPathParser.SHIFT = 's'; XPathParser.REDUCE = 'r'; XPathParser.ACCEPT = 'a'; XPathParser.prototype.parse = function(s) { var types; var values; var res = this.tokenize(s); if (res == undefined) { return undefined; } types = res[0]; values = res[1]; var tokenPos = 0; var state = []; var tokenType = []; var tokenValue = []; var s; var a; var t; state.push(0); tokenType.push(1); tokenValue.push("_S"); a = types[tokenPos]; t = values[tokenPos++]; while (1) { s = state[state.length - 1]; switch (XPathParser.actionTable[s].charAt(a - 1)) { case XPathParser.SHIFT: tokenType.push(-a); tokenValue.push(t); state.push(XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32); a = types[tokenPos]; t = values[tokenPos++]; break; case XPathParser.REDUCE: var num = XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][1]; var rhs = []; for (var i = 0; i < num; i++) { tokenType.pop(); rhs.unshift(tokenValue.pop()); state.pop(); } var s_ = state[state.length - 1]; tokenType.push(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0]); if (this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32] == undefined) { tokenValue.push(rhs[0]); } else { tokenValue.push(this.reduceActions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32](rhs)); } state.push(XPathParser.gotoTable[s_].charCodeAt(XPathParser.productions[XPathParser.actionTableNumber[s].charCodeAt(a - 1) - 32][0] - 2) - 33); break; case XPathParser.ACCEPT: return new XPath(tokenValue.pop()); default: throw new Error("XPath parse error"); } } }; // XPath ///////////////////////////////////////////////////////////////////// XPath.prototype = new Object(); XPath.prototype.constructor = XPath; XPath.superclass = Object.prototype; function XPath(e) { this.expression = e; } XPath.prototype.toString = function() { return this.expression.toString(); }; XPath.prototype.evaluate = function(c) { c.contextNode = c.expressionContextNode; c.contextSize = 1; c.contextPosition = 1; c.caseInsensitive = false; if (c.contextNode != null) { var doc = c.contextNode; if (doc.nodeType != 9 /*Node.DOCUMENT_NODE*/) { doc = doc.ownerDocument; } try { c.caseInsensitive = doc.implementation.hasFeature("HTML", "2.0"); } catch (e) { c.caseInsensitive = true; } } return this.expression.evaluate(c); }; XPath.XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace"; XPath.XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/"; // Expression //////////////////////////////////////////////////////////////// Expression.prototype = new Object(); Expression.prototype.constructor = Expression; Expression.superclass = Object.prototype; function Expression() { } Expression.prototype.init = function() { }; Expression.prototype.toString = function() { return ""; }; Expression.prototype.evaluate = function(c) { throw new Error("Could not evaluate expression."); }; // UnaryOperation //////////////////////////////////////////////////////////// UnaryOperation.prototype = new Expression(); UnaryOperation.prototype.constructor = UnaryOperation; UnaryOperation.superclass = Expression.prototype; function UnaryOperation(rhs) { if (arguments.length > 0) { this.init(rhs); } } UnaryOperation.prototype.init = function(rhs) { this.rhs = rhs; }; // UnaryMinusOperation /////////////////////////////////////////////////////// UnaryMinusOperation.prototype = new UnaryOperation(); UnaryMinusOperation.prototype.constructor = UnaryMinusOperation; UnaryMinusOperation.superclass = UnaryOperation.prototype; function UnaryMinusOperation(rhs) { if (arguments.length > 0) { this.init(rhs); } } UnaryMinusOperation.prototype.init = function(rhs) { UnaryMinusOperation.superclass.init.call(this, rhs); }; UnaryMinusOperation.prototype.evaluate = function(c) { return this.rhs.evaluate(c).number().negate(); }; UnaryMinusOperation.prototype.toString = function() { return "-" + this.rhs.toString(); }; // BinaryOperation /////////////////////////////////////////////////////////// BinaryOperation.prototype = new Expression(); BinaryOperation.prototype.constructor = BinaryOperation; BinaryOperation.superclass = Expression.prototype; function BinaryOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } BinaryOperation.prototype.init = function(lhs, rhs) { this.lhs = lhs; this.rhs = rhs; }; // OrOperation /////////////////////////////////////////////////////////////// OrOperation.prototype = new BinaryOperation(); OrOperation.prototype.constructor = OrOperation; OrOperation.superclass = BinaryOperation.prototype; function OrOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } OrOperation.prototype.init = function(lhs, rhs) { OrOperation.superclass.init.call(this, lhs, rhs); }; OrOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " or " + this.rhs.toString() + ")"; }; OrOperation.prototype.evaluate = function(c) { var b = this.lhs.evaluate(c).bool(); if (b.booleanValue()) { return b; } return this.rhs.evaluate(c).bool(); }; // AndOperation ////////////////////////////////////////////////////////////// AndOperation.prototype = new BinaryOperation(); AndOperation.prototype.constructor = AndOperation; AndOperation.superclass = BinaryOperation.prototype; function AndOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } AndOperation.prototype.init = function(lhs, rhs) { AndOperation.superclass.init.call(this, lhs, rhs); }; AndOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " and " + this.rhs.toString() + ")"; }; AndOperation.prototype.evaluate = function(c) { var b = this.lhs.evaluate(c).bool(); if (!b.booleanValue()) { return b; } return this.rhs.evaluate(c).bool(); }; // EqualsOperation /////////////////////////////////////////////////////////// EqualsOperation.prototype = new BinaryOperation(); EqualsOperation.prototype.constructor = EqualsOperation; EqualsOperation.superclass = BinaryOperation.prototype; function EqualsOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } EqualsOperation.prototype.init = function(lhs, rhs) { EqualsOperation.superclass.init.call(this, lhs, rhs); }; EqualsOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " = " + this.rhs.toString() + ")"; }; EqualsOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).equals(this.rhs.evaluate(c)); }; // NotEqualOperation ///////////////////////////////////////////////////////// NotEqualOperation.prototype = new BinaryOperation(); NotEqualOperation.prototype.constructor = NotEqualOperation; NotEqualOperation.superclass = BinaryOperation.prototype; function NotEqualOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } NotEqualOperation.prototype.init = function(lhs, rhs) { NotEqualOperation.superclass.init.call(this, lhs, rhs); }; NotEqualOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " != " + this.rhs.toString() + ")"; }; NotEqualOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).notequal(this.rhs.evaluate(c)); }; // LessThanOperation ///////////////////////////////////////////////////////// LessThanOperation.prototype = new BinaryOperation(); LessThanOperation.prototype.constructor = LessThanOperation; LessThanOperation.superclass = BinaryOperation.prototype; function LessThanOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } LessThanOperation.prototype.init = function(lhs, rhs) { LessThanOperation.superclass.init.call(this, lhs, rhs); }; LessThanOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).lessthan(this.rhs.evaluate(c)); }; LessThanOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " < " + this.rhs.toString() + ")"; }; // GreaterThanOperation ////////////////////////////////////////////////////// GreaterThanOperation.prototype = new BinaryOperation(); GreaterThanOperation.prototype.constructor = GreaterThanOperation; GreaterThanOperation.superclass = BinaryOperation.prototype; function GreaterThanOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } GreaterThanOperation.prototype.init = function(lhs, rhs) { GreaterThanOperation.superclass.init.call(this, lhs, rhs); }; GreaterThanOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).greaterthan(this.rhs.evaluate(c)); }; GreaterThanOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " > " + this.rhs.toString() + ")"; }; // LessThanOrEqualOperation ////////////////////////////////////////////////// LessThanOrEqualOperation.prototype = new BinaryOperation(); LessThanOrEqualOperation.prototype.constructor = LessThanOrEqualOperation; LessThanOrEqualOperation.superclass = BinaryOperation.prototype; function LessThanOrEqualOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } LessThanOrEqualOperation.prototype.init = function(lhs, rhs) { LessThanOrEqualOperation.superclass.init.call(this, lhs, rhs); }; LessThanOrEqualOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).lessthanorequal(this.rhs.evaluate(c)); }; LessThanOrEqualOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " <= " + this.rhs.toString() + ")"; }; // GreaterThanOrEqualOperation /////////////////////////////////////////////// GreaterThanOrEqualOperation.prototype = new BinaryOperation(); GreaterThanOrEqualOperation.prototype.constructor = GreaterThanOrEqualOperation; GreaterThanOrEqualOperation.superclass = BinaryOperation.prototype; function GreaterThanOrEqualOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } GreaterThanOrEqualOperation.prototype.init = function(lhs, rhs) { GreaterThanOrEqualOperation.superclass.init.call(this, lhs, rhs); }; GreaterThanOrEqualOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).greaterthanorequal(this.rhs.evaluate(c)); }; GreaterThanOrEqualOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " >= " + this.rhs.toString() + ")"; }; // PlusOperation ///////////////////////////////////////////////////////////// PlusOperation.prototype = new BinaryOperation(); PlusOperation.prototype.constructor = PlusOperation; PlusOperation.superclass = BinaryOperation.prototype; function PlusOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } PlusOperation.prototype.init = function(lhs, rhs) { PlusOperation.superclass.init.call(this, lhs, rhs); }; PlusOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).number().plus(this.rhs.evaluate(c).number()); }; PlusOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " + " + this.rhs.toString() + ")"; }; // MinusOperation //////////////////////////////////////////////////////////// MinusOperation.prototype = new BinaryOperation(); MinusOperation.prototype.constructor = MinusOperation; MinusOperation.superclass = BinaryOperation.prototype; function MinusOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } MinusOperation.prototype.init = function(lhs, rhs) { MinusOperation.superclass.init.call(this, lhs, rhs); }; MinusOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).number().minus(this.rhs.evaluate(c).number()); }; MinusOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " - " + this.rhs.toString() + ")"; }; // MultiplyOperation ///////////////////////////////////////////////////////// MultiplyOperation.prototype = new BinaryOperation(); MultiplyOperation.prototype.constructor = MultiplyOperation; MultiplyOperation.superclass = BinaryOperation.prototype; function MultiplyOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } MultiplyOperation.prototype.init = function(lhs, rhs) { MultiplyOperation.superclass.init.call(this, lhs, rhs); }; MultiplyOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).number().multiply(this.rhs.evaluate(c).number()); }; MultiplyOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " * " + this.rhs.toString() + ")"; }; // DivOperation ////////////////////////////////////////////////////////////// DivOperation.prototype = new BinaryOperation(); DivOperation.prototype.constructor = DivOperation; DivOperation.superclass = BinaryOperation.prototype; function DivOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } DivOperation.prototype.init = function(lhs, rhs) { DivOperation.superclass.init.call(this, lhs, rhs); }; DivOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).number().div(this.rhs.evaluate(c).number()); }; DivOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " div " + this.rhs.toString() + ")"; }; // ModOperation ////////////////////////////////////////////////////////////// ModOperation.prototype = new BinaryOperation(); ModOperation.prototype.constructor = ModOperation; ModOperation.superclass = BinaryOperation.prototype; function ModOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } ModOperation.prototype.init = function(lhs, rhs) { ModOperation.superclass.init.call(this, lhs, rhs); }; ModOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).number().mod(this.rhs.evaluate(c).number()); }; ModOperation.prototype.toString = function() { return "(" + this.lhs.toString() + " mod " + this.rhs.toString() + ")"; }; // BarOperation ////////////////////////////////////////////////////////////// BarOperation.prototype = new BinaryOperation(); BarOperation.prototype.constructor = BarOperation; BarOperation.superclass = BinaryOperation.prototype; function BarOperation(lhs, rhs) { if (arguments.length > 0) { this.init(lhs, rhs); } } BarOperation.prototype.init = function(lhs, rhs) { BarOperation.superclass.init.call(this, lhs, rhs); }; BarOperation.prototype.evaluate = function(c) { return this.lhs.evaluate(c).nodeset().union(this.rhs.evaluate(c).nodeset()); }; BarOperation.prototype.toString = function() { return this.lhs.toString() + " | " + this.rhs.toString(); }; // PathExpr ////////////////////////////////////////////////////////////////// PathExpr.prototype = new Expression(); PathExpr.prototype.constructor = PathExpr; PathExpr.superclass = Expression.prototype; function PathExpr(filter, filterPreds, locpath) { if (arguments.length > 0) { this.init(filter, filterPreds, locpath); } } PathExpr.prototype.init = function(filter, filterPreds, locpath) { PathExpr.superclass.init.call(this); this.filter = filter; this.filterPredicates = filterPreds; this.locationPath = locpath; }; /** * Returns the topmost node of the tree containing node */ function findRoot(node) { while (node && node.parentNode) { node = node.parentNode; } return node; } PathExpr.prototype.evaluate = function(c) { var nodes; var xpc = new XPathContext(); xpc.variableResolver = c.variableResolver; xpc.functionResolver = c.functionResolver; xpc.namespaceResolver = c.namespaceResolver; xpc.expressionContextNode = c.expressionContextNode; xpc.virtualRoot = c.virtualRoot; xpc.caseInsensitive = c.caseInsensitive; if (this.filter == null) { nodes = [ c.contextNode ]; } else { var ns = this.filter.evaluate(c); if (!Utilities.instance_of(ns, XNodeSet)) { if (this.filterPredicates != null && this.filterPredicates.length > 0 || this.locationPath != null) { throw new Error("Path expression filter must evaluate to a nodset if predicates or location path are used"); } return ns; } nodes = ns.toUnsortedArray(); if (this.filterPredicates != null) { // apply each of the predicates in turn for (var j = 0; j < this.filterPredicates.length; j++) { var pred = this.filterPredicates[j]; var newNodes = []; xpc.contextSize = nodes.length; for (xpc.contextPosition = 1; xpc.contextPosition <= xpc.contextSize; xpc.contextPosition++) { xpc.contextNode = nodes[xpc.contextPosition - 1]; if (this.predicateMatches(pred, xpc)) { newNodes.push(xpc.contextNode); } } nodes = newNodes; } } } if (this.locationPath != null) { if (this.locationPath.absolute) { if (nodes[0].nodeType != 9 /*Node.DOCUMENT_NODE*/) { if (xpc.virtualRoot != null) { nodes = [ xpc.virtualRoot ]; } else { if (nodes[0].ownerDocument == null) { // IE 5.5 doesn't have ownerDocument? var n = nodes[0]; while (n.parentNode != null) { n = n.parentNode; } nodes = [ n ]; } else { nodes = [ nodes[0].ownerDocument ]; } } } else { nodes = [ nodes[0] ]; } } for (var i = 0; i < this.locationPath.steps.length; i++) { var step = this.locationPath.steps[i]; var newNodes = []; for (var j = 0; j < nodes.length; j++) { xpc.contextNode = nodes[j]; switch (step.axis) { case Step.ANCESTOR: // look at all the ancestor nodes if (xpc.contextNode === xpc.virtualRoot) { break; } var m; if (xpc.contextNode.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) { m = this.getOwnerElement(xpc.contextNode); } else { m = xpc.contextNode.parentNode; } while (m != null) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } if (m === xpc.virtualRoot) { break; } m = m.parentNode; } break; case Step.ANCESTORORSELF: // look at all the ancestor nodes and the current node for (var m = xpc.contextNode; m != null; m = m.nodeType == 2 /*Node.ATTRIBUTE_NODE*/ ? this.getOwnerElement(m) : m.parentNode) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } if (m === xpc.virtualRoot) { break; } } break; case Step.ATTRIBUTE: // look at the attributes var nnm = xpc.contextNode.attributes; if (nnm != null) { for (var k = 0; k < nnm.length; k++) { var m = nnm.item(k); if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } } } break; case Step.CHILD: // look at all child elements for (var m = xpc.contextNode.firstChild; m != null; m = m.nextSibling) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } } break; case Step.DESCENDANT: // look at all descendant nodes var st = [ xpc.contextNode.firstChild ]; while (st.length > 0) { for (var m = st.pop(); m != null; ) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } if (m.firstChild != null) { st.push(m.nextSibling); m = m.firstChild; } else { m = m.nextSibling; } } } break; case Step.DESCENDANTORSELF: // look at self if (step.nodeTest.matches(xpc.contextNode, xpc)) { newNodes.push(xpc.contextNode); } // look at all descendant nodes var st = [ xpc.contextNode.firstChild ]; while (st.length > 0) { for (var m = st.pop(); m != null; ) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } if (m.firstChild != null) { st.push(m.nextSibling); m = m.firstChild; } else { m = m.nextSibling; } } } break; case Step.FOLLOWING: if (xpc.contextNode === xpc.virtualRoot) { break; } var st = []; if (xpc.contextNode.firstChild != null) { st.unshift(xpc.contextNode.firstChild); } else { st.unshift(xpc.contextNode.nextSibling); } for (var m = xpc.contextNode.parentNode; m != null && m.nodeType != 9 /*Node.DOCUMENT_NODE*/ && m !== xpc.virtualRoot; m = m.parentNode) { st.unshift(m.nextSibling); } do { for (var m = st.pop(); m != null; ) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } if (m.firstChild != null) { st.push(m.nextSibling); m = m.firstChild; } else { m = m.nextSibling; } } } while (st.length > 0); break; case Step.FOLLOWINGSIBLING: if (xpc.contextNode === xpc.virtualRoot) { break; } for (var m = xpc.contextNode.nextSibling; m != null; m = m.nextSibling) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } } break; case Step.NAMESPACE: var n = {}; if (xpc.contextNode.nodeType == 1 /*Node.ELEMENT_NODE*/) { n["xml"] = XPath.XML_NAMESPACE_URI; n["xmlns"] = XPath.XMLNS_NAMESPACE_URI; for (var m = xpc.contextNode; m != null && m.nodeType == 1 /*Node.ELEMENT_NODE*/; m = m.parentNode) { for (var k = 0; k < m.attributes.length; k++) { var attr = m.attributes.item(k); var nm = String(attr.name); if (nm == "xmlns") { if (n[""] == undefined) { n[""] = attr.value; } } else if (nm.length > 6 && nm.substring(0, 6) == "xmlns:") { var pre = nm.substring(6, nm.length); if (n[pre] == undefined) { n[pre] = attr.value; } } } } for (var pre in n) { var nsn = new XPathNamespace(pre, n[pre], xpc.contextNode); if (step.nodeTest.matches(nsn, xpc)) { newNodes.push(nsn); } } } break; case Step.PARENT: m = null; if (xpc.contextNode !== xpc.virtualRoot) { if (xpc.contextNode.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) { m = this.getOwnerElement(xpc.contextNode); } else { m = xpc.contextNode.parentNode; } } if (m != null && step.nodeTest.matches(m, xpc)) { newNodes.push(m); } break; case Step.PRECEDING: var st; if (xpc.virtualRoot != null) { st = [ xpc.virtualRoot ]; } else { // cannot rely on .ownerDocument because the node may be in a document fragment st = [findRoot(xpc.contextNode)]; } outer: while (st.length > 0) { for (var m = st.pop(); m != null; ) { if (m == xpc.contextNode) { break outer; } if (step.nodeTest.matches(m, xpc)) { newNodes.unshift(m); } if (m.firstChild != null) { st.push(m.nextSibling); m = m.firstChild; } else { m = m.nextSibling; } } } break; case Step.PRECEDINGSIBLING: if (xpc.contextNode === xpc.virtualRoot) { break; } for (var m = xpc.contextNode.previousSibling; m != null; m = m.previousSibling) { if (step.nodeTest.matches(m, xpc)) { newNodes.push(m); } } break; case Step.SELF: if (step.nodeTest.matches(xpc.contextNode, xpc)) { newNodes.push(xpc.contextNode); } break; default: } } nodes = newNodes; // apply each of the predicates in turn for (var j = 0; j < step.predicates.length; j++) { var pred = step.predicates[j]; var newNodes = []; xpc.contextSize = nodes.length; for (xpc.contextPosition = 1; xpc.contextPosition <= xpc.contextSize; xpc.contextPosition++) { xpc.contextNode = nodes[xpc.contextPosition - 1]; if (this.predicateMatches(pred, xpc)) { newNodes.push(xpc.contextNode); } else { } } nodes = newNodes; } } } var ns = new XNodeSet(); ns.addArray(nodes); return ns; }; PathExpr.prototype.predicateMatches = function(pred, c) { var res = pred.evaluate(c); if (Utilities.instance_of(res, XNumber)) { return c.contextPosition == res.numberValue(); } return res.booleanValue(); }; PathExpr.prototype.toString = function() { if (this.filter != undefined) { var s = this.filter.toString(); if (Utilities.instance_of(this.filter, XString)) { s = "'" + s + "'"; } if (this.filterPredicates != undefined) { for (var i = 0; i < this.filterPredicates.length; i++) { s = s + "[" + this.filterPredicates[i].toString() + "]"; } } if (this.locationPath != undefined) { if (!this.locationPath.absolute) { s += "/"; } s += this.locationPath.toString(); } return s; } return this.locationPath.toString(); }; PathExpr.prototype.getOwnerElement = function(n) { // DOM 2 has ownerElement if (n.ownerElement) { return n.ownerElement; } // DOM 1 Internet Explorer can use selectSingleNode (ironically) try { if (n.selectSingleNode) { return n.selectSingleNode(".."); } } catch (e) { } // Other DOM 1 implementations must use this egregious search var doc = n.nodeType == 9 /*Node.DOCUMENT_NODE*/ ? n : n.ownerDocument; var elts = doc.getElementsByTagName("*"); for (var i = 0; i < elts.length; i++) { var elt = elts.item(i); var nnm = elt.attributes; for (var j = 0; j < nnm.length; j++) { var an = nnm.item(j); if (an === n) { return elt; } } } return null; }; // LocationPath ////////////////////////////////////////////////////////////// LocationPath.prototype = new Object(); LocationPath.prototype.constructor = LocationPath; LocationPath.superclass = Object.prototype; function LocationPath(abs, steps) { if (arguments.length > 0) { this.init(abs, steps); } } LocationPath.prototype.init = function(abs, steps) { this.absolute = abs; this.steps = steps; }; LocationPath.prototype.toString = function() { var s; if (this.absolute) { s = "/"; } else { s = ""; } for (var i = 0; i < this.steps.length; i++) { if (i != 0) { s += "/"; } s += this.steps[i].toString(); } return s; }; // Step ////////////////////////////////////////////////////////////////////// Step.prototype = new Object(); Step.prototype.constructor = Step; Step.superclass = Object.prototype; function Step(axis, nodetest, preds) { if (arguments.length > 0) { this.init(axis, nodetest, preds); } } Step.prototype.init = function(axis, nodetest, preds) { this.axis = axis; this.nodeTest = nodetest; this.predicates = preds; }; Step.prototype.toString = function() { var s; switch (this.axis) { case Step.ANCESTOR: s = "ancestor"; break; case Step.ANCESTORORSELF: s = "ancestor-or-self"; break; case Step.ATTRIBUTE: s = "attribute"; break; case Step.CHILD: s = "child"; break; case Step.DESCENDANT: s = "descendant"; break; case Step.DESCENDANTORSELF: s = "descendant-or-self"; break; case Step.FOLLOWING: s = "following"; break; case Step.FOLLOWINGSIBLING: s = "following-sibling"; break; case Step.NAMESPACE: s = "namespace"; break; case Step.PARENT: s = "parent"; break; case Step.PRECEDING: s = "preceding"; break; case Step.PRECEDINGSIBLING: s = "preceding-sibling"; break; case Step.SELF: s = "self"; break; } s += "::"; s += this.nodeTest.toString(); for (var i = 0; i < this.predicates.length; i++) { s += "[" + this.predicates[i].toString() + "]"; } return s; }; Step.ANCESTOR = 0; Step.ANCESTORORSELF = 1; Step.ATTRIBUTE = 2; Step.CHILD = 3; Step.DESCENDANT = 4; Step.DESCENDANTORSELF = 5; Step.FOLLOWING = 6; Step.FOLLOWINGSIBLING = 7; Step.NAMESPACE = 8; Step.PARENT = 9; Step.PRECEDING = 10; Step.PRECEDINGSIBLING = 11; Step.SELF = 12; // NodeTest ////////////////////////////////////////////////////////////////// NodeTest.prototype = new Object(); NodeTest.prototype.constructor = NodeTest; NodeTest.superclass = Object.prototype; function NodeTest(type, value) { if (arguments.length > 0) { this.init(type, value); } } NodeTest.prototype.init = function(type, value) { this.type = type; this.value = value; }; NodeTest.prototype.toString = function() { switch (this.type) { case NodeTest.NAMETESTANY: return "*"; case NodeTest.NAMETESTPREFIXANY: return this.value + ":*"; case NodeTest.NAMETESTRESOLVEDANY: return "{" + this.value + "}*"; case NodeTest.NAMETESTQNAME: return this.value; case NodeTest.NAMETESTRESOLVEDNAME: return "{" + this.namespaceURI + "}" + this.value; case NodeTest.COMMENT: return "comment()"; case NodeTest.TEXT: return "text()"; case NodeTest.PI: if (this.value != undefined) { return "processing-instruction(\"" + this.value + "\")"; } return "processing-instruction()"; case NodeTest.NODE: return "node()"; } return ""; }; NodeTest.prototype.matches = function (n, xpc) { var nType = n.nodeType; switch (this.type) { case NodeTest.NAMETESTANY: if (nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/ || nType === XPathNamespace.XPATH_NAMESPACE_NODE) { return true; } return false; case NodeTest.NAMETESTPREFIXANY: if (nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/) { var ns = xpc.namespaceResolver.getNamespace(this.value, xpc.expressionContextNode); if (ns == null) { throw new Error("Cannot resolve QName " + this.value); } return ns === (n.namespaceURI || ''); } return false; case NodeTest.NAMETESTQNAME: if (nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/ || nType === XPathNamespace.XPATH_NAMESPACE_NODE) { var test = Utilities.resolveQName(this.value, xpc.namespaceResolver, xpc.expressionContextNode, false); if (test[0] == null) { throw new Error("Cannot resolve QName " + this.value); } test[0] = String(test[0]) || null; test[1] = String(test[1]); var node = [ String(n.namespaceURI || '') || null, // localName will be null if the node was created with DOM1 createElement() String(n.localName || n.nodeName) ]; if (xpc.caseInsensitive) { return test[0] === node[0] && test[1].toLowerCase() === node[1].toLowerCase(); } return test[0] === node[0] && test[1] === node[1]; } return false; case NodeTest.COMMENT: return nType === 8 /*Node.COMMENT_NODE*/; case NodeTest.TEXT: return nType === 3 /*Node.TEXT_NODE*/ || nType == 4 /*Node.CDATA_SECTION_NODE*/; case NodeTest.PI: return nType === 7 /*Node.PROCESSING_INSTRUCTION_NODE*/ && (this.value == null || n.nodeName == this.value); case NodeTest.NODE: return nType === 9 /*Node.DOCUMENT_NODE*/ || nType === 1 /*Node.ELEMENT_NODE*/ || nType === 2 /*Node.ATTRIBUTE_NODE*/ || nType === 3 /*Node.TEXT_NODE*/ || nType === 4 /*Node.CDATA_SECTION_NODE*/ || nType === 8 /*Node.COMMENT_NODE*/ || nType === 7 /*Node.PROCESSING_INSTRUCTION_NODE*/; } return false; }; NodeTest.NAMETESTANY = 0; NodeTest.NAMETESTPREFIXANY = 1; NodeTest.NAMETESTQNAME = 2; NodeTest.COMMENT = 3; NodeTest.TEXT = 4; NodeTest.PI = 5; NodeTest.NODE = 6; // VariableReference ///////////////////////////////////////////////////////// VariableReference.prototype = new Expression(); VariableReference.prototype.constructor = VariableReference; VariableReference.superclass = Expression.prototype; function VariableReference(v) { if (arguments.length > 0) { this.init(v); } } VariableReference.prototype.init = function(v) { this.variable = v; }; VariableReference.prototype.toString = function() { return "$" + this.variable; }; VariableReference.prototype.evaluate = function(c) { var parts = Utilities.resolveQName(this.variable, c.namespaceResolver, c.contextNode, false); if (parts[0] == null) { throw new Error("Cannot resolve QName " + fn); } var result = c.variableResolver.getVariable(parts[1], parts[0]); if (!result) { throw XPathException.fromMessage("Undeclared variable: " + this.toString()); } return result; }; // FunctionCall ////////////////////////////////////////////////////////////// FunctionCall.prototype = new Expression(); FunctionCall.prototype.constructor = FunctionCall; FunctionCall.superclass = Expression.prototype; function FunctionCall(fn, args) { if (arguments.length > 0) { this.init(fn, args); } } FunctionCall.prototype.init = function(fn, args) { this.functionName = fn; this.arguments = args; }; FunctionCall.prototype.toString = function() { var s = this.functionName + "("; for (var i = 0; i < this.arguments.length; i++) { if (i > 0) { s += ", "; } s += this.arguments[i].toString(); } return s + ")"; }; FunctionCall.prototype.evaluate = function(c) { var f = FunctionResolver.getFunctionFromContext(this.functionName, c); if (!f) { throw new Error("Unknown function " + this.functionName); } var a = [c].concat(this.arguments); return f.apply(c.functionResolver.thisArg, a); }; // XString /////////////////////////////////////////////////////////////////// XString.prototype = new Expression(); XString.prototype.constructor = XString; XString.superclass = Expression.prototype; function XString(s) { if (arguments.length > 0) { this.init(s); } } XString.prototype.init = function(s) { this.str = String(s); }; XString.prototype.toString = function() { return this.str; }; XString.prototype.evaluate = function(c) { return this; }; XString.prototype.string = function() { return this; }; XString.prototype.number = function() { return new XNumber(this.str); }; XString.prototype.bool = function() { return new XBoolean(this.str); }; XString.prototype.nodeset = function() { throw new Error("Cannot convert string to nodeset"); }; XString.prototype.stringValue = function() { return this.str; }; XString.prototype.numberValue = function() { return this.number().numberValue(); }; XString.prototype.booleanValue = function() { return this.bool().booleanValue(); }; XString.prototype.equals = function(r) { if (Utilities.instance_of(r, XBoolean)) { return this.bool().equals(r); } if (Utilities.instance_of(r, XNumber)) { return this.number().equals(r); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithString(this, Operators.equals); } return new XBoolean(this.str == r.str); }; XString.prototype.notequal = function(r) { if (Utilities.instance_of(r, XBoolean)) { return this.bool().notequal(r); } if (Utilities.instance_of(r, XNumber)) { return this.number().notequal(r); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithString(this, Operators.notequal); } return new XBoolean(this.str != r.str); }; XString.prototype.lessthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.greaterthanorequal); } return this.number().lessthan(r.number()); }; XString.prototype.greaterthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.lessthanorequal); } return this.number().greaterthan(r.number()); }; XString.prototype.lessthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.greaterthan); } return this.number().lessthanorequal(r.number()); }; XString.prototype.greaterthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.lessthan); } return this.number().greaterthanorequal(r.number()); }; // XNumber /////////////////////////////////////////////////////////////////// XNumber.prototype = new Expression(); XNumber.prototype.constructor = XNumber; XNumber.superclass = Expression.prototype; function XNumber(n) { if (arguments.length > 0) { this.init(n); } } XNumber.prototype.init = function(n) { this.num = typeof n === "string" ? this.parse(n) : Number(n); }; XNumber.prototype.numberFormat = /^\s*-?[0-9]*\.?[0-9]+\s*$/; XNumber.prototype.parse = function(s) { // XPath representation of numbers is more restrictive than what Number() or parseFloat() allow return this.numberFormat.test(s) ? parseFloat(s) : Number.NaN; }; XNumber.prototype.toString = function() { return this.num; }; XNumber.prototype.evaluate = function(c) { return this; }; XNumber.prototype.string = function() { return new XString(this.num); }; XNumber.prototype.number = function() { return this; }; XNumber.prototype.bool = function() { return new XBoolean(this.num); }; XNumber.prototype.nodeset = function() { throw new Error("Cannot convert number to nodeset"); }; XNumber.prototype.stringValue = function() { return this.string().stringValue(); }; XNumber.prototype.numberValue = function() { return this.num; }; XNumber.prototype.booleanValue = function() { return this.bool().booleanValue(); }; XNumber.prototype.negate = function() { return new XNumber(-this.num); }; XNumber.prototype.equals = function(r) { if (Utilities.instance_of(r, XBoolean)) { return this.bool().equals(r); } if (Utilities.instance_of(r, XString)) { return this.equals(r.number()); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.equals); } return new XBoolean(this.num == r.num); }; XNumber.prototype.notequal = function(r) { if (Utilities.instance_of(r, XBoolean)) { return this.bool().notequal(r); } if (Utilities.instance_of(r, XString)) { return this.notequal(r.number()); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.notequal); } return new XBoolean(this.num != r.num); }; XNumber.prototype.lessthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.greaterthanorequal); } if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) { return this.lessthan(r.number()); } return new XBoolean(this.num < r.num); }; XNumber.prototype.greaterthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.lessthanorequal); } if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) { return this.greaterthan(r.number()); } return new XBoolean(this.num > r.num); }; XNumber.prototype.lessthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.greaterthan); } if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) { return this.lessthanorequal(r.number()); } return new XBoolean(this.num <= r.num); }; XNumber.prototype.greaterthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this, Operators.lessthan); } if (Utilities.instance_of(r, XBoolean) || Utilities.instance_of(r, XString)) { return this.greaterthanorequal(r.number()); } return new XBoolean(this.num >= r.num); }; XNumber.prototype.plus = function(r) { return new XNumber(this.num + r.num); }; XNumber.prototype.minus = function(r) { return new XNumber(this.num - r.num); }; XNumber.prototype.multiply = function(r) { return new XNumber(this.num * r.num); }; XNumber.prototype.div = function(r) { return new XNumber(this.num / r.num); }; XNumber.prototype.mod = function(r) { return new XNumber(this.num % r.num); }; // XBoolean ////////////////////////////////////////////////////////////////// XBoolean.prototype = new Expression(); XBoolean.prototype.constructor = XBoolean; XBoolean.superclass = Expression.prototype; function XBoolean(b) { if (arguments.length > 0) { this.init(b); } } XBoolean.prototype.init = function(b) { this.b = Boolean(b); }; XBoolean.prototype.toString = function() { return this.b.toString(); }; XBoolean.prototype.evaluate = function(c) { return this; }; XBoolean.prototype.string = function() { return new XString(this.b); }; XBoolean.prototype.number = function() { return new XNumber(this.b); }; XBoolean.prototype.bool = function() { return this; }; XBoolean.prototype.nodeset = function() { throw new Error("Cannot convert boolean to nodeset"); }; XBoolean.prototype.stringValue = function() { return this.string().stringValue(); }; XBoolean.prototype.numberValue = function() { return this.num().numberValue(); }; XBoolean.prototype.booleanValue = function() { return this.b; }; XBoolean.prototype.not = function() { return new XBoolean(!this.b); }; XBoolean.prototype.equals = function(r) { if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) { return this.equals(r.bool()); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithBoolean(this, Operators.equals); } return new XBoolean(this.b == r.b); }; XBoolean.prototype.notequal = function(r) { if (Utilities.instance_of(r, XString) || Utilities.instance_of(r, XNumber)) { return this.notequal(r.bool()); } if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithBoolean(this, Operators.notequal); } return new XBoolean(this.b != r.b); }; XBoolean.prototype.lessthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.greaterthanorequal); } return this.number().lessthan(r.number()); }; XBoolean.prototype.greaterthan = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.lessthanorequal); } return this.number().greaterthan(r.number()); }; XBoolean.prototype.lessthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.greaterthan); } return this.number().lessthanorequal(r.number()); }; XBoolean.prototype.greaterthanorequal = function(r) { if (Utilities.instance_of(r, XNodeSet)) { return r.compareWithNumber(this.number(), Operators.lessthan); } return this.number().greaterthanorequal(r.number()); }; // AVLTree /////////////////////////////////////////////////////////////////// AVLTree.prototype = new Object(); AVLTree.prototype.constructor = AVLTree; AVLTree.superclass = Object.prototype; function AVLTree(n) { this.init(n); } AVLTree.prototype.init = function(n) { this.left = null; this.right = null; this.node = n; this.depth = 1; }; AVLTree.prototype.balance = function() { var ldepth = this.left == null ? 0 : this.left.depth; var rdepth = this.right == null ? 0 : this.right.depth; if (ldepth > rdepth + 1) { // LR or LL rotation var lldepth = this.left.left == null ? 0 : this.left.left.depth; var lrdepth = this.left.right == null ? 0 : this.left.right.depth; if (lldepth < lrdepth) { // LR rotation consists of a RR rotation of the left child this.left.rotateRR(); // plus a LL rotation of this node, which happens anyway } this.rotateLL(); } else if (ldepth + 1 < rdepth) { // RR or RL rorarion var rrdepth = this.right.right == null ? 0 : this.right.right.depth; var rldepth = this.right.left == null ? 0 : this.right.left.depth; if (rldepth > rrdepth) { // RR rotation consists of a LL rotation of the right child this.right.rotateLL(); // plus a RR rotation of this node, which happens anyway } this.rotateRR(); } }; AVLTree.prototype.rotateLL = function() { // the left side is too long => rotate from the left (_not_ leftwards) var nodeBefore = this.node; var rightBefore = this.right; this.node = this.left.node; this.right = this.left; this.left = this.left.left; this.right.left = this.right.right; this.right.right = rightBefore; this.right.node = nodeBefore; this.right.updateInNewLocation(); this.updateInNewLocation(); }; AVLTree.prototype.rotateRR = function() { // the right side is too long => rotate from the right (_not_ rightwards) var nodeBefore = this.node; var leftBefore = this.left; this.node = this.right.node; this.left = this.right; this.right = this.right.right; this.left.right = this.left.left; this.left.left = leftBefore; this.left.node = nodeBefore; this.left.updateInNewLocation(); this.updateInNewLocation(); }; AVLTree.prototype.updateInNewLocation = function() { this.getDepthFromChildren(); }; AVLTree.prototype.getDepthFromChildren = function() { this.depth = this.node == null ? 0 : 1; if (this.left != null) { this.depth = this.left.depth + 1; } if (this.right != null && this.depth <= this.right.depth) { this.depth = this.right.depth + 1; } }; function nodeOrder(n1, n2) { if (n1 === n2) { return 0; } if (n1.compareDocumentPosition) { var cpos = n1.compareDocumentPosition(n2); if (cpos & 0x01) { // not in the same document; return an arbitrary result (is there a better way to do this) return 1; } if (cpos & 0x0A) { // n2 precedes or contains n1 return 1; } if (cpos & 0x14) { // n2 follows or is contained by n1 return -1; } return 0; } var d1 = 0, d2 = 0; for (var m1 = n1; m1 != null; m1 = m1.parentNode || m1.ownerElement) { d1++; } for (var m2 = n2; m2 != null; m2 = m2.parentNode || m2.ownerElement) { d2++; } // step up to same depth if (d1 > d2) { while (d1 > d2) { n1 = n1.parentNode || n1.ownerElement; d1--; } if (n1 === n2) { return 1; } } else if (d2 > d1) { while (d2 > d1) { n2 = n2.parentNode || n2.ownerElement; d2--; } if (n1 === n2) { return -1; } } var n1Par = n1.parentNode || n1.ownerElement, n2Par = n2.parentNode || n2.ownerElement; // find common parent while (n1Par !== n2Par) { n1 = n1Par; n2 = n2Par; n1Par = n1.parentNode || n1.ownerElement; n2Par = n2.parentNode || n2.ownerElement; } var n1isAttr = Utilities.isAttribute(n1); var n2isAttr = Utilities.isAttribute(n2); if (n1isAttr && !n2isAttr) { return -1; } if (!n1isAttr && n2isAttr) { return 1; } if(n1Par) { var cn = n1isAttr ? n1Par.attributes : n1Par.childNodes, len = cn.length; for (var i = 0; i < len; i += 1) { var n = cn[i]; if (n === n1) { return -1; } if (n === n2) { return 1; } } } throw new Error('Unexpected: could not determine node order'); } AVLTree.prototype.add = function(n) { if (n === this.node) { return false; } var o = nodeOrder(n, this.node); var ret = false; if (o == -1) { if (this.left == null) { this.left = new AVLTree(n); ret = true; } else { ret = this.left.add(n); if (ret) { this.balance(); } } } else if (o == 1) { if (this.right == null) { this.right = new AVLTree(n); ret = true; } else { ret = this.right.add(n); if (ret) { this.balance(); } } } if (ret) { this.getDepthFromChildren(); } return ret; }; // XNodeSet ////////////////////////////////////////////////////////////////// XNodeSet.prototype = new Expression(); XNodeSet.prototype.constructor = XNodeSet; XNodeSet.superclass = Expression.prototype; function XNodeSet() { this.init(); } XNodeSet.prototype.init = function() { this.tree = null; this.nodes = []; this.size = 0; }; XNodeSet.prototype.toString = function() { var p = this.first(); if (p == null) { return ""; } return this.stringForNode(p); }; XNodeSet.prototype.evaluate = function(c) { return this; }; XNodeSet.prototype.string = function() { return new XString(this.toString()); }; XNodeSet.prototype.stringValue = function() { return this.toString(); }; XNodeSet.prototype.number = function() { return new XNumber(this.string()); }; XNodeSet.prototype.numberValue = function() { return Number(this.string()); }; XNodeSet.prototype.bool = function() { return new XBoolean(this.booleanValue()); }; XNodeSet.prototype.booleanValue = function() { return !!this.size; }; XNodeSet.prototype.nodeset = function() { return this; }; XNodeSet.prototype.stringForNode = function(n) { if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/ || n.nodeType == 1 /*Node.ELEMENT_NODE */ || n.nodeType === 11 /*Node.DOCUMENT_FRAGMENT*/) { return this.stringForContainerNode(n); } if (n.nodeType === 2 /* Node.ATTRIBUTE_NODE */) { return n.value || n.nodeValue; } if (n.isNamespaceNode) { return n.namespace; } return n.nodeValue; }; XNodeSet.prototype.stringForContainerNode = function(n) { var s = ""; for (var n2 = n.firstChild; n2 != null; n2 = n2.nextSibling) { var nt = n2.nodeType; // Element, Text, CDATA, Document, Document Fragment if (nt === 1 || nt === 3 || nt === 4 || nt === 9 || nt === 11) { s += this.stringForNode(n2); } } return s; }; XNodeSet.prototype.buildTree = function () { if (!this.tree && this.nodes.length) { this.tree = new AVLTree(this.nodes[0]); for (var i = 1; i < this.nodes.length; i += 1) { this.tree.add(this.nodes[i]); } } return this.tree; }; XNodeSet.prototype.first = function() { var p = this.buildTree(); if (p == null) { return null; } while (p.left != null) { p = p.left; } return p.node; }; XNodeSet.prototype.add = function(n) { for (var i = 0; i < this.nodes.length; i += 1) { if (n === this.nodes[i]) { return; } } this.tree = null; this.nodes.push(n); this.size += 1; }; XNodeSet.prototype.addArray = function(ns) { for (var i = 0; i < ns.length; i += 1) { this.add(ns[i]); } }; /** * Returns an array of the node set's contents in document order */ XNodeSet.prototype.toArray = function() { var a = []; this.toArrayRec(this.buildTree(), a); return a; }; XNodeSet.prototype.toArrayRec = function(t, a) { if (t != null) { this.toArrayRec(t.left, a); a.push(t.node); this.toArrayRec(t.right, a); } }; /** * Returns an array of the node set's contents in arbitrary order */ XNodeSet.prototype.toUnsortedArray = function () { return this.nodes.slice(); }; XNodeSet.prototype.compareWithString = function(r, o) { var a = this.toUnsortedArray(); for (var i = 0; i < a.length; i++) { var n = a[i]; var l = new XString(this.stringForNode(n)); var res = o(l, r); if (res.booleanValue()) { return res; } } return new XBoolean(false); }; XNodeSet.prototype.compareWithNumber = function(r, o) { var a = this.toUnsortedArray(); for (var i = 0; i < a.length; i++) { var n = a[i]; var l = new XNumber(this.stringForNode(n)); var res = o(l, r); if (res.booleanValue()) { return res; } } return new XBoolean(false); }; XNodeSet.prototype.compareWithBoolean = function(r, o) { return o(this.bool(), r); }; XNodeSet.prototype.compareWithNodeSet = function(r, o) { var a = this.toUnsortedArray(); for (var i = 0; i < a.length; i++) { var n = a[i]; var l = new XString(this.stringForNode(n)); var b = r.toUnsortedArray(); for (var j = 0; j < b.length; j++) { var n2 = b[j]; var r = new XString(this.stringForNode(n2)); var res = o(l, r); if (res.booleanValue()) { return res; } } } return new XBoolean(false); }; XNodeSet.prototype.equals = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithString(r, Operators.equals); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.equals); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.equals); } return this.compareWithNodeSet(r, Operators.equals); }; XNodeSet.prototype.notequal = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithString(r, Operators.notequal); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.notequal); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.notequal); } return this.compareWithNodeSet(r, Operators.notequal); }; XNodeSet.prototype.lessthan = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithNumber(r.number(), Operators.lessthan); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.lessthan); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.lessthan); } return this.compareWithNodeSet(r, Operators.lessthan); }; XNodeSet.prototype.greaterthan = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithNumber(r.number(), Operators.greaterthan); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.greaterthan); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.greaterthan); } return this.compareWithNodeSet(r, Operators.greaterthan); }; XNodeSet.prototype.lessthanorequal = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithNumber(r.number(), Operators.lessthanorequal); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.lessthanorequal); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.lessthanorequal); } return this.compareWithNodeSet(r, Operators.lessthanorequal); }; XNodeSet.prototype.greaterthanorequal = function(r) { if (Utilities.instance_of(r, XString)) { return this.compareWithNumber(r.number(), Operators.greaterthanorequal); } if (Utilities.instance_of(r, XNumber)) { return this.compareWithNumber(r, Operators.greaterthanorequal); } if (Utilities.instance_of(r, XBoolean)) { return this.compareWithBoolean(r, Operators.greaterthanorequal); } return this.compareWithNodeSet(r, Operators.greaterthanorequal); }; XNodeSet.prototype.union = function(r) { var ns = new XNodeSet(); ns.addArray(this.toUnsortedArray()); ns.addArray(r.toUnsortedArray()); return ns; }; // XPathNamespace //////////////////////////////////////////////////////////// XPathNamespace.prototype = new Object(); XPathNamespace.prototype.constructor = XPathNamespace; XPathNamespace.superclass = Object.prototype; function XPathNamespace(pre, ns, p) { this.isXPathNamespace = true; this.ownerDocument = p.ownerDocument; this.nodeName = "#namespace"; this.prefix = pre; this.localName = pre; this.namespaceURI = ns; this.nodeValue = ns; this.ownerElement = p; this.nodeType = XPathNamespace.XPATH_NAMESPACE_NODE; } XPathNamespace.prototype.toString = function() { return "{ \"" + this.prefix + "\", \"" + this.namespaceURI + "\" }"; }; // Operators ///////////////////////////////////////////////////////////////// var Operators = new Object(); Operators.equals = function(l, r) { return l.equals(r); }; Operators.notequal = function(l, r) { return l.notequal(r); }; Operators.lessthan = function(l, r) { return l.lessthan(r); }; Operators.greaterthan = function(l, r) { return l.greaterthan(r); }; Operators.lessthanorequal = function(l, r) { return l.lessthanorequal(r); }; Operators.greaterthanorequal = function(l, r) { return l.greaterthanorequal(r); }; // XPathContext ////////////////////////////////////////////////////////////// XPathContext.prototype = new Object(); XPathContext.prototype.constructor = XPathContext; XPathContext.superclass = Object.prototype; function XPathContext(vr, nr, fr) { this.variableResolver = vr != null ? vr : new VariableResolver(); this.namespaceResolver = nr != null ? nr : new NamespaceResolver(); this.functionResolver = fr != null ? fr : new FunctionResolver(); } // VariableResolver ////////////////////////////////////////////////////////// VariableResolver.prototype = new Object(); VariableResolver.prototype.constructor = VariableResolver; VariableResolver.superclass = Object.prototype; function VariableResolver() { } VariableResolver.prototype.getVariable = function(ln, ns) { return null; }; // FunctionResolver ////////////////////////////////////////////////////////// FunctionResolver.prototype = new Object(); FunctionResolver.prototype.constructor = FunctionResolver; FunctionResolver.superclass = Object.prototype; function FunctionResolver(thisArg) { this.thisArg = thisArg != null ? thisArg : Functions; this.functions = new Object(); this.addStandardFunctions(); } FunctionResolver.prototype.addStandardFunctions = function() { this.functions["{}last"] = Functions.last; this.functions["{}position"] = Functions.position; this.functions["{}count"] = Functions.count; this.functions["{}id"] = Functions.id; this.functions["{}local-name"] = Functions.localName; this.functions["{}namespace-uri"] = Functions.namespaceURI; this.functions["{}name"] = Functions.name; this.functions["{}string"] = Functions.string; this.functions["{}concat"] = Functions.concat; this.functions["{}starts-with"] = Functions.startsWith; this.functions["{}contains"] = Functions.contains; this.functions["{}substring-before"] = Functions.substringBefore; this.functions["{}substring-after"] = Functions.substringAfter; this.functions["{}substring"] = Functions.substring; this.functions["{}string-length"] = Functions.stringLength; this.functions["{}normalize-space"] = Functions.normalizeSpace; this.functions["{}translate"] = Functions.translate; this.functions["{}boolean"] = Functions.boolean_; this.functions["{}not"] = Functions.not; this.functions["{}true"] = Functions.true_; this.functions["{}false"] = Functions.false_; this.functions["{}lang"] = Functions.lang; this.functions["{}number"] = Functions.number; this.functions["{}sum"] = Functions.sum; this.functions["{}floor"] = Functions.floor; this.functions["{}ceiling"] = Functions.ceiling; this.functions["{}round"] = Functions.round; }; FunctionResolver.prototype.addFunction = function(ns, ln, f) { this.functions["{" + ns + "}" + ln] = f; }; FunctionResolver.getFunctionFromContext = function(qName, context) { var parts = Utilities.resolveQName(qName, context.namespaceResolver, context.contextNode, false); if (parts[0] === null) { throw new Error("Cannot resolve QName " + name); } return context.functionResolver.getFunction(parts[1], parts[0]); }; FunctionResolver.prototype.getFunction = function(localName, namespace) { return this.functions["{" + namespace + "}" + localName]; }; // NamespaceResolver ///////////////////////////////////////////////////////// NamespaceResolver.prototype = new Object(); NamespaceResolver.prototype.constructor = NamespaceResolver; NamespaceResolver.superclass = Object.prototype; function NamespaceResolver() { } NamespaceResolver.prototype.getNamespace = function(prefix, n) { if (prefix == "xml") { return XPath.XML_NAMESPACE_URI; } else if (prefix == "xmlns") { return XPath.XMLNS_NAMESPACE_URI; } if (n.nodeType == 9 /*Node.DOCUMENT_NODE*/) { n = n.documentElement; } else if (n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) { n = PathExpr.prototype.getOwnerElement(n); } else if (n.nodeType != 1 /*Node.ELEMENT_NODE*/) { n = n.parentNode; } while (n != null && n.nodeType == 1 /*Node.ELEMENT_NODE*/) { var nnm = n.attributes; for (var i = 0; i < nnm.length; i++) { var a = nnm.item(i); var aname = a.name || a.nodeName; if ((aname === "xmlns" && prefix === "") || aname === "xmlns:" + prefix) { return String(a.value || a.nodeValue); } } n = n.parentNode; } return null; }; // Functions ///////////////////////////////////////////////////////////////// var Functions = new Object(); Functions.last = function() { var c = arguments[0]; if (arguments.length != 1) { throw new Error("Function last expects ()"); } return new XNumber(c.contextSize); }; Functions.position = function() { var c = arguments[0]; if (arguments.length != 1) { throw new Error("Function position expects ()"); } return new XNumber(c.contextPosition); }; Functions.count = function() { var c = arguments[0]; var ns; if (arguments.length != 2 || !Utilities.instance_of(ns = arguments[1].evaluate(c), XNodeSet)) { throw new Error("Function count expects (node-set)"); } return new XNumber(ns.size); }; Functions.id = function() { var c = arguments[0]; var id; if (arguments.length != 2) { throw new Error("Function id expects (object)"); } id = arguments[1].evaluate(c); if (Utilities.instance_of(id, XNodeSet)) { id = id.toArray().join(" "); } else { id = id.stringValue(); } var ids = id.split(/[\x0d\x0a\x09\x20]+/); var count = 0; var ns = new XNodeSet(); var doc = c.contextNode.nodeType == 9 /*Node.DOCUMENT_NODE*/ ? c.contextNode : c.contextNode.ownerDocument; for (var i = 0; i < ids.length; i++) { var n; if (doc.getElementById) { n = doc.getElementById(ids[i]); } else { n = Utilities.getElementById(doc, ids[i]); } if (n != null) { ns.add(n); count++; } } return ns; }; Functions.localName = function() { var c = arguments[0]; var n; if (arguments.length == 1) { n = c.contextNode; } else if (arguments.length == 2) { n = arguments[1].evaluate(c).first(); } else { throw new Error("Function local-name expects (node-set?)"); } if (n == null) { return new XString(""); } return new XString(n.localName || // standard elements and attributes n.baseName || // IE n.target || // processing instructions n.nodeName || // DOM1 elements ""); // fallback }; Functions.namespaceURI = function() { var c = arguments[0]; var n; if (arguments.length == 1) { n = c.contextNode; } else if (arguments.length == 2) { n = arguments[1].evaluate(c).first(); } else { throw new Error("Function namespace-uri expects (node-set?)"); } if (n == null) { return new XString(""); } return new XString(n.namespaceURI); }; Functions.name = function() { var c = arguments[0]; var n; if (arguments.length == 1) { n = c.contextNode; } else if (arguments.length == 2) { n = arguments[1].evaluate(c).first(); } else { throw new Error("Function name expects (node-set?)"); } if (n == null) { return new XString(""); } if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) { return new XString(n.nodeName); } else if (n.nodeType == 2 /*Node.ATTRIBUTE_NODE*/) { return new XString(n.name || n.nodeName); } else if (n.nodeType === 7 /*Node.PROCESSING_INSTRUCTION_NODE*/) { return new XString(n.target || n.nodeName); } else if (n.localName == null) { return new XString(""); } else { return new XString(n.localName); } }; Functions.string = function() { var c = arguments[0]; if (arguments.length == 1) { return new XString(XNodeSet.prototype.stringForNode(c.contextNode)); } else if (arguments.length == 2) { return arguments[1].evaluate(c).string(); } throw new Error("Function string expects (object?)"); }; Functions.concat = function() { var c = arguments[0]; if (arguments.length < 3) { throw new Error("Function concat expects (string, string, string*)"); } var s = ""; for (var i = 1; i < arguments.length; i++) { s += arguments[i].evaluate(c).stringValue(); } return new XString(s); }; Functions.startsWith = function() { var c = arguments[0]; if (arguments.length != 3) { throw new Error("Function startsWith expects (string, string)"); } var s1 = arguments[1].evaluate(c).stringValue(); var s2 = arguments[2].evaluate(c).stringValue(); return new XBoolean(s1.substring(0, s2.length) == s2); }; Functions.contains = function() { var c = arguments[0]; if (arguments.length != 3) { throw new Error("Function contains expects (string, string)"); } var s1 = arguments[1].evaluate(c).stringValue(); var s2 = arguments[2].evaluate(c).stringValue(); return new XBoolean(s1.indexOf(s2) !== -1); }; Functions.substringBefore = function() { var c = arguments[0]; if (arguments.length != 3) { throw new Error("Function substring-before expects (string, string)"); } var s1 = arguments[1].evaluate(c).stringValue(); var s2 = arguments[2].evaluate(c).stringValue(); return new XString(s1.substring(0, s1.indexOf(s2))); }; Functions.substringAfter = function() { var c = arguments[0]; if (arguments.length != 3) { throw new Error("Function substring-after expects (string, string)"); } var s1 = arguments[1].evaluate(c).stringValue(); var s2 = arguments[2].evaluate(c).stringValue(); if (s2.length == 0) { return new XString(s1); } var i = s1.indexOf(s2); if (i == -1) { return new XString(""); } return new XString(s1.substring(i + s2.length)); }; Functions.substring = function() { var c = arguments[0]; if (!(arguments.length == 3 || arguments.length == 4)) { throw new Error("Function substring expects (string, number, number?)"); } var s = arguments[1].evaluate(c).stringValue(); var n1 = Math.round(arguments[2].evaluate(c).numberValue()) - 1; var n2 = arguments.length == 4 ? n1 + Math.round(arguments[3].evaluate(c).numberValue()) : undefined; return new XString(s.substring(n1, n2)); }; Functions.stringLength = function() { var c = arguments[0]; var s; if (arguments.length == 1) { s = XNodeSet.prototype.stringForNode(c.contextNode); } else if (arguments.length == 2) { s = arguments[1].evaluate(c).stringValue(); } else { throw new Error("Function string-length expects (string?)"); } return new XNumber(s.length); }; Functions.normalizeSpace = function() { var c = arguments[0]; var s; if (arguments.length == 1) { s = XNodeSet.prototype.stringForNode(c.contextNode); } else if (arguments.length == 2) { s = arguments[1].evaluate(c).stringValue(); } else { throw new Error("Function normalize-space expects (string?)"); } var i = 0; var j = s.length - 1; while (Utilities.isSpace(s.charCodeAt(j))) { j--; } var t = ""; while (i <= j && Utilities.isSpace(s.charCodeAt(i))) { i++; } while (i <= j) { if (Utilities.isSpace(s.charCodeAt(i))) { t += " "; while (i <= j && Utilities.isSpace(s.charCodeAt(i))) { i++; } } else { t += s.charAt(i); i++; } } return new XString(t); }; Functions.translate = function() { var c = arguments[0]; if (arguments.length != 4) { throw new Error("Function translate expects (string, string, string)"); } var s1 = arguments[1].evaluate(c).stringValue(); var s2 = arguments[2].evaluate(c).stringValue(); var s3 = arguments[3].evaluate(c).stringValue(); var map = []; for (var i = 0; i < s2.length; i++) { var j = s2.charCodeAt(i); if (map[j] == undefined) { var k = i > s3.length ? "" : s3.charAt(i); map[j] = k; } } var t = ""; for (var i = 0; i < s1.length; i++) { var c = s1.charCodeAt(i); var r = map[c]; if (r == undefined) { t += s1.charAt(i); } else { t += r; } } return new XString(t); }; Functions.boolean_ = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function boolean expects (object)"); } return arguments[1].evaluate(c).bool(); }; Functions.not = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function not expects (object)"); } return arguments[1].evaluate(c).bool().not(); }; Functions.true_ = function() { if (arguments.length != 1) { throw new Error("Function true expects ()"); } return new XBoolean(true); }; Functions.false_ = function() { if (arguments.length != 1) { throw new Error("Function false expects ()"); } return new XBoolean(false); }; Functions.lang = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function lang expects (string)"); } var lang; for (var n = c.contextNode; n != null && n.nodeType != 9 /*Node.DOCUMENT_NODE*/; n = n.parentNode) { var a = n.getAttributeNS(XPath.XML_NAMESPACE_URI, "lang"); if (a != null) { lang = String(a); break; } } if (lang == null) { return new XBoolean(false); } var s = arguments[1].evaluate(c).stringValue(); return new XBoolean(lang.substring(0, s.length) == s && (lang.length == s.length || lang.charAt(s.length) == '-')); }; Functions.number = function() { var c = arguments[0]; if (!(arguments.length == 1 || arguments.length == 2)) { throw new Error("Function number expects (object?)"); } if (arguments.length == 1) { return new XNumber(XNodeSet.prototype.stringForNode(c.contextNode)); } return arguments[1].evaluate(c).number(); }; Functions.sum = function() { var c = arguments[0]; var ns; if (arguments.length != 2 || !Utilities.instance_of((ns = arguments[1].evaluate(c)), XNodeSet)) { throw new Error("Function sum expects (node-set)"); } ns = ns.toUnsortedArray(); var n = 0; for (var i = 0; i < ns.length; i++) { n += new XNumber(XNodeSet.prototype.stringForNode(ns[i])).numberValue(); } return new XNumber(n); }; Functions.floor = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function floor expects (number)"); } return new XNumber(Math.floor(arguments[1].evaluate(c).numberValue())); }; Functions.ceiling = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function ceiling expects (number)"); } return new XNumber(Math.ceil(arguments[1].evaluate(c).numberValue())); }; Functions.round = function() { var c = arguments[0]; if (arguments.length != 2) { throw new Error("Function round expects (number)"); } return new XNumber(Math.round(arguments[1].evaluate(c).numberValue())); }; // Utilities ///////////////////////////////////////////////////////////////// var Utilities = new Object(); Utilities.isAttribute = function (val) { return val && (val.nodeType === 2 || val.ownerElement); } Utilities.splitQName = function(qn) { var i = qn.indexOf(":"); if (i == -1) { return [ null, qn ]; } return [ qn.substring(0, i), qn.substring(i + 1) ]; }; Utilities.resolveQName = function(qn, nr, n, useDefault) { var parts = Utilities.splitQName(qn); if (parts[0] != null) { parts[0] = nr.getNamespace(parts[0], n); } else { if (useDefault) { parts[0] = nr.getNamespace("", n); if (parts[0] == null) { parts[0] = ""; } } else { parts[0] = ""; } } return parts; }; Utilities.isSpace = function(c) { return c == 0x9 || c == 0xd || c == 0xa || c == 0x20; }; Utilities.isLetter = function(c) { return c >= 0x0041 && c <= 0x005A || c >= 0x0061 && c <= 0x007A || c >= 0x00C0 && c <= 0x00D6 || c >= 0x00D8 && c <= 0x00F6 || c >= 0x00F8 && c <= 0x00FF || c >= 0x0100 && c <= 0x0131 || c >= 0x0134 && c <= 0x013E || c >= 0x0141 && c <= 0x0148 || c >= 0x014A && c <= 0x017E || c >= 0x0180 && c <= 0x01C3 || c >= 0x01CD && c <= 0x01F0 || c >= 0x01F4 && c <= 0x01F5 || c >= 0x01FA && c <= 0x0217 || c >= 0x0250 && c <= 0x02A8 || c >= 0x02BB && c <= 0x02C1 || c == 0x0386 || c >= 0x0388 && c <= 0x038A || c == 0x038C || c >= 0x038E && c <= 0x03A1 || c >= 0x03A3 && c <= 0x03CE || c >= 0x03D0 && c <= 0x03D6 || c == 0x03DA || c == 0x03DC || c == 0x03DE || c == 0x03E0 || c >= 0x03E2 && c <= 0x03F3 || c >= 0x0401 && c <= 0x040C || c >= 0x040E && c <= 0x044F || c >= 0x0451 && c <= 0x045C || c >= 0x045E && c <= 0x0481 || c >= 0x0490 && c <= 0x04C4 || c >= 0x04C7 && c <= 0x04C8 || c >= 0x04CB && c <= 0x04CC || c >= 0x04D0 && c <= 0x04EB || c >= 0x04EE && c <= 0x04F5 || c >= 0x04F8 && c <= 0x04F9 || c >= 0x0531 && c <= 0x0556 || c == 0x0559 || c >= 0x0561 && c <= 0x0586 || c >= 0x05D0 && c <= 0x05EA || c >= 0x05F0 && c <= 0x05F2 || c >= 0x0621 && c <= 0x063A || c >= 0x0641 && c <= 0x064A || c >= 0x0671 && c <= 0x06B7 || c >= 0x06BA && c <= 0x06BE || c >= 0x06C0 && c <= 0x06CE || c >= 0x06D0 && c <= 0x06D3 || c == 0x06D5 || c >= 0x06E5 && c <= 0x06E6 || c >= 0x0905 && c <= 0x0939 || c == 0x093D || c >= 0x0958 && c <= 0x0961 || c >= 0x0985 && c <= 0x098C || c >= 0x098F && c <= 0x0990 || c >= 0x0993 && c <= 0x09A8 || c >= 0x09AA && c <= 0x09B0 || c == 0x09B2 || c >= 0x09B6 && c <= 0x09B9 || c >= 0x09DC && c <= 0x09DD || c >= 0x09DF && c <= 0x09E1 || c >= 0x09F0 && c <= 0x09F1 || c >= 0x0A05 && c <= 0x0A0A || c >= 0x0A0F && c <= 0x0A10 || c >= 0x0A13 && c <= 0x0A28 || c >= 0x0A2A && c <= 0x0A30 || c >= 0x0A32 && c <= 0x0A33 || c >= 0x0A35 && c <= 0x0A36 || c >= 0x0A38 && c <= 0x0A39 || c >= 0x0A59 && c <= 0x0A5C || c == 0x0A5E || c >= 0x0A72 && c <= 0x0A74 || c >= 0x0A85 && c <= 0x0A8B || c == 0x0A8D || c >= 0x0A8F && c <= 0x0A91 || c >= 0x0A93 && c <= 0x0AA8 || c >= 0x0AAA && c <= 0x0AB0 || c >= 0x0AB2 && c <= 0x0AB3 || c >= 0x0AB5 && c <= 0x0AB9 || c == 0x0ABD || c == 0x0AE0 || c >= 0x0B05 && c <= 0x0B0C || c >= 0x0B0F && c <= 0x0B10 || c >= 0x0B13 && c <= 0x0B28 || c >= 0x0B2A && c <= 0x0B30 || c >= 0x0B32 && c <= 0x0B33 || c >= 0x0B36 && c <= 0x0B39 || c == 0x0B3D || c >= 0x0B5C && c <= 0x0B5D || c >= 0x0B5F && c <= 0x0B61 || c >= 0x0B85 && c <= 0x0B8A || c >= 0x0B8E && c <= 0x0B90 || c >= 0x0B92 && c <= 0x0B95 || c >= 0x0B99 && c <= 0x0B9A || c == 0x0B9C || c >= 0x0B9E && c <= 0x0B9F || c >= 0x0BA3 && c <= 0x0BA4 || c >= 0x0BA8 && c <= 0x0BAA || c >= 0x0BAE && c <= 0x0BB5 || c >= 0x0BB7 && c <= 0x0BB9 || c >= 0x0C05 && c <= 0x0C0C || c >= 0x0C0E && c <= 0x0C10 || c >= 0x0C12 && c <= 0x0C28 || c >= 0x0C2A && c <= 0x0C33 || c >= 0x0C35 && c <= 0x0C39 || c >= 0x0C60 && c <= 0x0C61 || c >= 0x0C85 && c <= 0x0C8C || c >= 0x0C8E && c <= 0x0C90 || c >= 0x0C92 && c <= 0x0CA8 || c >= 0x0CAA && c <= 0x0CB3 || c >= 0x0CB5 && c <= 0x0CB9 || c == 0x0CDE || c >= 0x0CE0 && c <= 0x0CE1 || c >= 0x0D05 && c <= 0x0D0C || c >= 0x0D0E && c <= 0x0D10 || c >= 0x0D12 && c <= 0x0D28 || c >= 0x0D2A && c <= 0x0D39 || c >= 0x0D60 && c <= 0x0D61 || c >= 0x0E01 && c <= 0x0E2E || c == 0x0E30 || c >= 0x0E32 && c <= 0x0E33 || c >= 0x0E40 && c <= 0x0E45 || c >= 0x0E81 && c <= 0x0E82 || c == 0x0E84 || c >= 0x0E87 && c <= 0x0E88 || c == 0x0E8A || c == 0x0E8D || c >= 0x0E94 && c <= 0x0E97 || c >= 0x0E99 && c <= 0x0E9F || c >= 0x0EA1 && c <= 0x0EA3 || c == 0x0EA5 || c == 0x0EA7 || c >= 0x0EAA && c <= 0x0EAB || c >= 0x0EAD && c <= 0x0EAE || c == 0x0EB0 || c >= 0x0EB2 && c <= 0x0EB3 || c == 0x0EBD || c >= 0x0EC0 && c <= 0x0EC4 || c >= 0x0F40 && c <= 0x0F47 || c >= 0x0F49 && c <= 0x0F69 || c >= 0x10A0 && c <= 0x10C5 || c >= 0x10D0 && c <= 0x10F6 || c == 0x1100 || c >= 0x1102 && c <= 0x1103 || c >= 0x1105 && c <= 0x1107 || c == 0x1109 || c >= 0x110B && c <= 0x110C || c >= 0x110E && c <= 0x1112 || c == 0x113C || c == 0x113E || c == 0x1140 || c == 0x114C || c == 0x114E || c == 0x1150 || c >= 0x1154 && c <= 0x1155 || c == 0x1159 || c >= 0x115F && c <= 0x1161 || c == 0x1163 || c == 0x1165 || c == 0x1167 || c == 0x1169 || c >= 0x116D && c <= 0x116E || c >= 0x1172 && c <= 0x1173 || c == 0x1175 || c == 0x119E || c == 0x11A8 || c == 0x11AB || c >= 0x11AE && c <= 0x11AF || c >= 0x11B7 && c <= 0x11B8 || c == 0x11BA || c >= 0x11BC && c <= 0x11C2 || c == 0x11EB || c == 0x11F0 || c == 0x11F9 || c >= 0x1E00 && c <= 0x1E9B || c >= 0x1EA0 && c <= 0x1EF9 || c >= 0x1F00 && c <= 0x1F15 || c >= 0x1F18 && c <= 0x1F1D || c >= 0x1F20 && c <= 0x1F45 || c >= 0x1F48 && c <= 0x1F4D || c >= 0x1F50 && c <= 0x1F57 || c == 0x1F59 || c == 0x1F5B || c == 0x1F5D || c >= 0x1F5F && c <= 0x1F7D || c >= 0x1F80 && c <= 0x1FB4 || c >= 0x1FB6 && c <= 0x1FBC || c == 0x1FBE || c >= 0x1FC2 && c <= 0x1FC4 || c >= 0x1FC6 && c <= 0x1FCC || c >= 0x1FD0 && c <= 0x1FD3 || c >= 0x1FD6 && c <= 0x1FDB || c >= 0x1FE0 && c <= 0x1FEC || c >= 0x1FF2 && c <= 0x1FF4 || c >= 0x1FF6 && c <= 0x1FFC || c == 0x2126 || c >= 0x212A && c <= 0x212B || c == 0x212E || c >= 0x2180 && c <= 0x2182 || c >= 0x3041 && c <= 0x3094 || c >= 0x30A1 && c <= 0x30FA || c >= 0x3105 && c <= 0x312C || c >= 0xAC00 && c <= 0xD7A3 || c >= 0x4E00 && c <= 0x9FA5 || c == 0x3007 || c >= 0x3021 && c <= 0x3029; }; Utilities.isNCNameChar = function(c) { return c >= 0x0030 && c <= 0x0039 || c >= 0x0660 && c <= 0x0669 || c >= 0x06F0 && c <= 0x06F9 || c >= 0x0966 && c <= 0x096F || c >= 0x09E6 && c <= 0x09EF || c >= 0x0A66 && c <= 0x0A6F || c >= 0x0AE6 && c <= 0x0AEF || c >= 0x0B66 && c <= 0x0B6F || c >= 0x0BE7 && c <= 0x0BEF || c >= 0x0C66 && c <= 0x0C6F || c >= 0x0CE6 && c <= 0x0CEF || c >= 0x0D66 && c <= 0x0D6F || c >= 0x0E50 && c <= 0x0E59 || c >= 0x0ED0 && c <= 0x0ED9 || c >= 0x0F20 && c <= 0x0F29 || c == 0x002E || c == 0x002D || c == 0x005F || Utilities.isLetter(c) || c >= 0x0300 && c <= 0x0345 || c >= 0x0360 && c <= 0x0361 || c >= 0x0483 && c <= 0x0486 || c >= 0x0591 && c <= 0x05A1 || c >= 0x05A3 && c <= 0x05B9 || c >= 0x05BB && c <= 0x05BD || c == 0x05BF || c >= 0x05C1 && c <= 0x05C2 || c == 0x05C4 || c >= 0x064B && c <= 0x0652 || c == 0x0670 || c >= 0x06D6 && c <= 0x06DC || c >= 0x06DD && c <= 0x06DF || c >= 0x06E0 && c <= 0x06E4 || c >= 0x06E7 && c <= 0x06E8 || c >= 0x06EA && c <= 0x06ED || c >= 0x0901 && c <= 0x0903 || c == 0x093C || c >= 0x093E && c <= 0x094C || c == 0x094D || c >= 0x0951 && c <= 0x0954 || c >= 0x0962 && c <= 0x0963 || c >= 0x0981 && c <= 0x0983 || c == 0x09BC || c == 0x09BE || c == 0x09BF || c >= 0x09C0 && c <= 0x09C4 || c >= 0x09C7 && c <= 0x09C8 || c >= 0x09CB && c <= 0x09CD || c == 0x09D7 || c >= 0x09E2 && c <= 0x09E3 || c == 0x0A02 || c == 0x0A3C || c == 0x0A3E || c == 0x0A3F || c >= 0x0A40 && c <= 0x0A42 || c >= 0x0A47 && c <= 0x0A48 || c >= 0x0A4B && c <= 0x0A4D || c >= 0x0A70 && c <= 0x0A71 || c >= 0x0A81 && c <= 0x0A83 || c == 0x0ABC || c >= 0x0ABE && c <= 0x0AC5 || c >= 0x0AC7 && c <= 0x0AC9 || c >= 0x0ACB && c <= 0x0ACD || c >= 0x0B01 && c <= 0x0B03 || c == 0x0B3C || c >= 0x0B3E && c <= 0x0B43 || c >= 0x0B47 && c <= 0x0B48 || c >= 0x0B4B && c <= 0x0B4D || c >= 0x0B56 && c <= 0x0B57 || c >= 0x0B82 && c <= 0x0B83 || c >= 0x0BBE && c <= 0x0BC2 || c >= 0x0BC6 && c <= 0x0BC8 || c >= 0x0BCA && c <= 0x0BCD || c == 0x0BD7 || c >= 0x0C01 && c <= 0x0C03 || c >= 0x0C3E && c <= 0x0C44 || c >= 0x0C46 && c <= 0x0C48 || c >= 0x0C4A && c <= 0x0C4D || c >= 0x0C55 && c <= 0x0C56 || c >= 0x0C82 && c <= 0x0C83 || c >= 0x0CBE && c <= 0x0CC4 || c >= 0x0CC6 && c <= 0x0CC8 || c >= 0x0CCA && c <= 0x0CCD || c >= 0x0CD5 && c <= 0x0CD6 || c >= 0x0D02 && c <= 0x0D03 || c >= 0x0D3E && c <= 0x0D43 || c >= 0x0D46 && c <= 0x0D48 || c >= 0x0D4A && c <= 0x0D4D || c == 0x0D57 || c == 0x0E31 || c >= 0x0E34 && c <= 0x0E3A || c >= 0x0E47 && c <= 0x0E4E || c == 0x0EB1 || c >= 0x0EB4 && c <= 0x0EB9 || c >= 0x0EBB && c <= 0x0EBC || c >= 0x0EC8 && c <= 0x0ECD || c >= 0x0F18 && c <= 0x0F19 || c == 0x0F35 || c == 0x0F37 || c == 0x0F39 || c == 0x0F3E || c == 0x0F3F || c >= 0x0F71 && c <= 0x0F84 || c >= 0x0F86 && c <= 0x0F8B || c >= 0x0F90 && c <= 0x0F95 || c == 0x0F97 || c >= 0x0F99 && c <= 0x0FAD || c >= 0x0FB1 && c <= 0x0FB7 || c == 0x0FB9 || c >= 0x20D0 && c <= 0x20DC || c == 0x20E1 || c >= 0x302A && c <= 0x302F || c == 0x3099 || c == 0x309A || c == 0x00B7 || c == 0x02D0 || c == 0x02D1 || c == 0x0387 || c == 0x0640 || c == 0x0E46 || c == 0x0EC6 || c == 0x3005 || c >= 0x3031 && c <= 0x3035 || c >= 0x309D && c <= 0x309E || c >= 0x30FC && c <= 0x30FE; }; Utilities.coalesceText = function(n) { for (var m = n.firstChild; m != null; m = m.nextSibling) { if (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) { var s = m.nodeValue; var first = m; m = m.nextSibling; while (m != null && (m.nodeType == 3 /*Node.TEXT_NODE*/ || m.nodeType == 4 /*Node.CDATA_SECTION_NODE*/)) { s += m.nodeValue; var del = m; m = m.nextSibling; del.parentNode.removeChild(del); } if (first.nodeType == 4 /*Node.CDATA_SECTION_NODE*/) { var p = first.parentNode; if (first.nextSibling == null) { p.removeChild(first); p.appendChild(p.ownerDocument.createTextNode(s)); } else { var next = first.nextSibling; p.removeChild(first); p.insertBefore(p.ownerDocument.createTextNode(s), next); } } else { first.nodeValue = s; } if (m == null) { break; } } else if (m.nodeType == 1 /*Node.ELEMENT_NODE*/) { Utilities.coalesceText(m); } } }; Utilities.instance_of = function(o, c) { while (o != null) { if (o.constructor === c) { return true; } if (o === Object) { return false; } o = o.constructor.superclass; } return false; }; Utilities.getElementById = function(n, id) { // Note that this does not check the DTD to check for actual // attributes of type ID, so this may be a bit wrong. if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) { if (n.getAttribute("id") == id || n.getAttributeNS(null, "id") == id) { return n; } } for (var m = n.firstChild; m != null; m = m.nextSibling) { var res = Utilities.getElementById(m, id); if (res != null) { return res; } } return null; }; // XPathException //////////////////////////////////////////////////////////// var XPathException = (function () { function getMessage(code, exception) { var msg = exception ? ": " + exception.toString() : ""; switch (code) { case XPathException.INVALID_EXPRESSION_ERR: return "Invalid expression" + msg; case XPathException.TYPE_ERR: return "Type error" + msg; } return null; } function XPathException(code, error, message) { var err = Error.call(this, getMessage(code, error) || message); err.code = code; err.exception = error; return err; } XPathException.prototype = Object.create(Error.prototype); XPathException.prototype.constructor = XPathException; XPathException.superclass = Error; XPathException.prototype.toString = function() { return this.message; }; XPathException.fromMessage = function(message, error) { return new XPathException(null, error, message); }; XPathException.INVALID_EXPRESSION_ERR = 51; XPathException.TYPE_ERR = 52; return XPathException; })(); // XPathExpression /////////////////////////////////////////////////////////// XPathExpression.prototype = {}; XPathExpression.prototype.constructor = XPathExpression; XPathExpression.superclass = Object.prototype; function XPathExpression(e, r, p) { this.xpath = p.parse(e); this.context = new XPathContext(); this.context.namespaceResolver = new XPathNSResolverWrapper(r); } XPathExpression.prototype.evaluate = function(n, t, res) { this.context.expressionContextNode = n; var result = this.xpath.evaluate(this.context); return new XPathResult(result, t); } // XPathNSResolverWrapper //////////////////////////////////////////////////// XPathNSResolverWrapper.prototype = {}; XPathNSResolverWrapper.prototype.constructor = XPathNSResolverWrapper; XPathNSResolverWrapper.superclass = Object.prototype; function XPathNSResolverWrapper(r) { this.xpathNSResolver = r; } XPathNSResolverWrapper.prototype.getNamespace = function(prefix, n) { if (this.xpathNSResolver == null) { return null; } return this.xpathNSResolver.lookupNamespaceURI(prefix); }; // NodeXPathNSResolver /////////////////////////////////////////////////////// NodeXPathNSResolver.prototype = {}; NodeXPathNSResolver.prototype.constructor = NodeXPathNSResolver; NodeXPathNSResolver.superclass = Object.prototype; function NodeXPathNSResolver(n) { this.node = n; this.namespaceResolver = new NamespaceResolver(); } NodeXPathNSResolver.prototype.lookupNamespaceURI = function(prefix) { return this.namespaceResolver.getNamespace(prefix, this.node); }; // XPathResult /////////////////////////////////////////////////////////////// XPathResult.prototype = {}; XPathResult.prototype.constructor = XPathResult; XPathResult.superclass = Object.prototype; function XPathResult(v, t) { if (t == XPathResult.ANY_TYPE) { if (v.constructor === XString) { t = XPathResult.STRING_TYPE; } else if (v.constructor === XNumber) { t = XPathResult.NUMBER_TYPE; } else if (v.constructor === XBoolean) { t = XPathResult.BOOLEAN_TYPE; } else if (v.constructor === XNodeSet) { t = XPathResult.UNORDERED_NODE_ITERATOR_TYPE; } } this.resultType = t; switch (t) { case XPathResult.NUMBER_TYPE: this.numberValue = v.numberValue(); return; case XPathResult.STRING_TYPE: this.stringValue = v.stringValue(); return; case XPathResult.BOOLEAN_TYPE: this.booleanValue = v.booleanValue(); return; case XPathResult.ANY_UNORDERED_NODE_TYPE: case XPathResult.FIRST_ORDERED_NODE_TYPE: if (v.constructor === XNodeSet) { this.singleNodeValue = v.first(); return; } break; case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: case XPathResult.ORDERED_NODE_ITERATOR_TYPE: if (v.constructor === XNodeSet) { this.invalidIteratorState = false; this.nodes = v.toArray(); this.iteratorIndex = 0; return; } break; case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: if (v.constructor === XNodeSet) { this.nodes = v.toArray(); this.snapshotLength = this.nodes.length; return; } break; } throw new XPathException(XPathException.TYPE_ERR); }; XPathResult.prototype.iterateNext = function() { if (this.resultType != XPathResult.UNORDERED_NODE_ITERATOR_TYPE && this.resultType != XPathResult.ORDERED_NODE_ITERATOR_TYPE) { throw new XPathException(XPathException.TYPE_ERR); } return this.nodes[this.iteratorIndex++]; }; XPathResult.prototype.snapshotItem = function(i) { if (this.resultType != XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE && this.resultType != XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) { throw new XPathException(XPathException.TYPE_ERR); } return this.nodes[i]; }; XPathResult.ANY_TYPE = 0; XPathResult.NUMBER_TYPE = 1; XPathResult.STRING_TYPE = 2; XPathResult.BOOLEAN_TYPE = 3; XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4; XPathResult.ORDERED_NODE_ITERATOR_TYPE = 5; XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE = 6; XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7; XPathResult.ANY_UNORDERED_NODE_TYPE = 8; XPathResult.FIRST_ORDERED_NODE_TYPE = 9; // DOM 3 XPath support /////////////////////////////////////////////////////// function installDOM3XPathSupport(doc, p) { doc.createExpression = function(e, r) { try { return new XPathExpression(e, r, p); } catch (e) { throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, e); } }; doc.createNSResolver = function(n) { return new NodeXPathNSResolver(n); }; doc.evaluate = function(e, cn, r, t, res) { if (t < 0 || t > 9) { throw { code: 0, toString: function() { return "Request type not supported"; } }; } return doc.createExpression(e, r, p).evaluate(cn, t, res); }; }; // --------------------------------------------------------------------------- // Install DOM 3 XPath support for the current document. try { var shouldInstall = true; try { if (document.implementation && document.implementation.hasFeature && document.implementation.hasFeature("XPath", null)) { shouldInstall = false; } } catch (e) { } if (shouldInstall) { installDOM3XPathSupport(document, new XPathParser()); } } catch (e) { } // --------------------------------------------------------------------------- // exports for node.js installDOM3XPathSupport(exports, new XPathParser()); (function() { var parser = new XPathParser(); var defaultNSResolver = new NamespaceResolver(); var defaultFunctionResolver = new FunctionResolver(); var defaultVariableResolver = new VariableResolver(); function makeNSResolverFromFunction(func) { return { getNamespace: function (prefix, node) { var ns = func(prefix, node); return ns || defaultNSResolver.getNamespace(prefix, node); } }; } function makeNSResolverFromObject(obj) { return makeNSResolverFromFunction(obj.getNamespace.bind(obj)); } function makeNSResolverFromMap(map) { return makeNSResolverFromFunction(function (prefix) { return map[prefix]; }); } function makeNSResolver(resolver) { if (resolver && typeof resolver.getNamespace === "function") { return makeNSResolverFromObject(resolver); } if (typeof resolver === "function") { return makeNSResolverFromFunction(resolver); } // assume prefix -> uri mapping if (typeof resolver === "object") { return makeNSResolverFromMap(resolver); } return defaultNSResolver; } /** Converts native JavaScript types to their XPath library equivalent */ function convertValue(value) { if (value === null || typeof value === "undefined" || value instanceof XString || value instanceof XBoolean || value instanceof XNumber || value instanceof XNodeSet) { return value; } switch (typeof value) { case "string": return new XString(value); case "boolean": return new XBoolean(value); case "number": return new XNumber(value); } // assume node(s) var ns = new XNodeSet(); ns.addArray([].concat(value)); return ns; } function makeEvaluator(func) { return function (context) { var args = Array.prototype.slice.call(arguments, 1).map(function (arg) { return arg.evaluate(context); }); var result = func.apply(this, [].concat(context, args)); return convertValue(result); }; } function makeFunctionResolverFromFunction(func) { return { getFunction: function (name, namespace) { var found = func(name, namespace); if (found) { return makeEvaluator(found); } return defaultFunctionResolver.getFunction(name, namespace); } }; } function makeFunctionResolverFromObject(obj) { return makeFunctionResolverFromFunction(obj.getFunction.bind(obj)); } function makeFunctionResolverFromMap(map) { return makeFunctionResolverFromFunction(function (name) { return map[name]; }); } function makeFunctionResolver(resolver) { if (resolver && typeof resolver.getFunction === "function") { return makeFunctionResolverFromObject(resolver); } if (typeof resolver === "function") { return makeFunctionResolverFromFunction(resolver); } // assume map if (typeof resolver === "object") { return makeFunctionResolverFromMap(resolver); } return defaultFunctionResolver; } function makeVariableResolverFromFunction(func) { return { getVariable: function (name, namespace) { var value = func(name, namespace); return convertValue(value); } }; } function makeVariableResolver(resolver) { if (resolver) { if (typeof resolver.getVariable === "function") { return makeVariableResolverFromFunction(resolver.getVariable.bind(resolver)); } if (typeof resolver === "function") { return makeVariableResolverFromFunction(resolver); } // assume map if (typeof resolver === "object") { return makeVariableResolverFromFunction(function (name) { return resolver[name]; }); } } return defaultVariableResolver; } function makeContext(options) { var context = new XPathContext(); if (options) { context.namespaceResolver = makeNSResolver(options.namespaces); context.functionResolver = makeFunctionResolver(options.functions); context.variableResolver = makeVariableResolver(options.variables); context.expressionContextNode = options.node; } else { context.namespaceResolver = defaultNSResolver; } return context; } function evaluate(parsedExpression, options) { var context = makeContext(options); return parsedExpression.evaluate(context); } var evaluatorPrototype = { evaluate: function (options) { return evaluate(this.expression, options); } ,evaluateNumber: function (options) { return this.evaluate(options).numberValue(); } ,evaluateString: function (options) { return this.evaluate(options).stringValue(); } ,evaluateBoolean: function (options) { return this.evaluate(options).booleanValue(); } ,evaluateNodeSet: function (options) { return this.evaluate(options).nodeset(); } ,select: function (options) { return this.evaluateNodeSet(options).toArray() } ,select1: function (options) { return this.select(options)[0]; } }; function parse(xpath) { var parsed = parser.parse(xpath); return Object.create(evaluatorPrototype, { expression: { value: parsed } }); } exports.parse = parse; })(); exports.XPath = XPath; exports.XPathParser = XPathParser; exports.XPathResult = XPathResult; exports.Step = Step; exports.NodeTest = NodeTest; exports.BarOperation = BarOperation; exports.NamespaceResolver = NamespaceResolver; exports.FunctionResolver = FunctionResolver; exports.VariableResolver = VariableResolver; exports.Utilities = Utilities; exports.XPathContext = XPathContext; exports.XNodeSet = XNodeSet; exports.XBoolean = XBoolean; exports.XString = XString; exports.XNumber = XNumber; // helper exports.select = function(e, doc, single) { return exports.selectWithResolver(e, doc, null, single); }; exports.useNamespaces = function(mappings) { var resolver = { mappings: mappings || {}, lookupNamespaceURI: function(prefix) { return this.mappings[prefix]; } }; return function(e, doc, single) { return exports.selectWithResolver(e, doc, resolver, single); }; }; exports.selectWithResolver = function(e, doc, resolver, single) { var expression = new XPathExpression(e, resolver, new XPathParser()); var type = XPathResult.ANY_TYPE; var result = expression.evaluate(doc, type, null); if (result.resultType == XPathResult.STRING_TYPE) { result = result.stringValue; } else if (result.resultType == XPathResult.NUMBER_TYPE) { result = result.numberValue; } else if (result.resultType == XPathResult.BOOLEAN_TYPE) { result = result.booleanValue; } else { result = result.nodes; if (single) { result = result[0]; } } return result; }; exports.select1 = function(e, doc) { return exports.select(e, doc, true); }; // end non-node wrapper })(xpath);