Ver código fonte

Merge pull request #20 from Mikescher/feature_xpath

Added operations 'XPath expression' and 'CSS selector'
n1474335 8 anos atrás
pai
commit
650fd9a940

+ 2 - 1
Gruntfile.js

@@ -130,7 +130,8 @@ module.exports = function(grunt) {
         "src/js/lib/vkbeautify.js",
         "src/js/lib/Sortable.js",
         "src/js/lib/bootstrap-colorpicker.js",
-
+        "src/js/lib/xpath.js",
+        
         // Custom libraries
         "src/js/lib/canvas_components.js",
 

+ 2 - 0
src/js/config/Categories.js

@@ -189,6 +189,8 @@ const Categories = [
             "Extract file paths",
             "Extract dates",
             "Regular expression",
+            "XPath expression",
+            "CSS selector",
         ]
     },
     {

+ 36 - 0
src/js/config/OperationConfig.js

@@ -1938,6 +1938,42 @@ const OperationConfig = {
             },
         ]
     },
+    "XPath expression": {
+        description: "Extract information from an xml document with an XPath query",
+        run: Extract.run_xpath,
+        input_type: "string",
+        output_type: "string",
+        args: [
+            {
+                name: "XPath",
+                type: "string",
+                value: Extract.XPATH_INITIAL
+            },
+            {
+                name: "Result delimiter",
+                type: "binary_short_string",
+                value: Extract.XPATH_DELIMITER
+            }
+        ]
+    },
+    "CSS selector": {
+        description: "Extract information from an HTML document with an CSS selector",
+        run: Extract.run_css_query,
+        input_type: "string",
+        output_type: "string",
+        args: [
+            {
+                name: "CSS selector",
+                type: "string",
+                value: Extract.SELECTOR_INITIAL
+            },
+            {
+                name: "Delimiter",
+                type: "binary_short_string",
+                value: Extract.CSS_QUERY_DELIMITER
+            },
+        ]
+    },
     "From UNIX Timestamp": {
         description: "Converts a UNIX timestamp to a datetime string.<br><br>e.g. <code>978346800</code> becomes <code>Mon 1 January 2001 11:00:00 UTC</code>",
         run: DateTime.run_from_unix_timestamp,

+ 8466 - 0
src/js/lib/xpath.js

@@ -0,0 +1,8466 @@
+(function(){/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+//	Javascript objects
+var cString		= window.String,
+	cBoolean	= window.Boolean,
+	cNumber		= window.Number,
+	cObject		= window.Object,
+	cArray		= window.Array,
+	cRegExp		= window.RegExp,
+	cDate		= window.Date,
+	cFunction	= window.Function,
+	cMath		= window.Math,
+// Error Objects
+	cError		= window.Error,
+	cSyntaxError= window.SyntaxError,
+	cTypeError	= window.TypeError,
+//	misc
+	fIsNaN		= window.isNaN,
+	fIsFinite	= window.isFinite,
+	nNaN		= window.NaN,
+	nInfinity	= window.Infinity,
+	// Functions
+	fWindow_btoa	= window.btoa,
+	fWindow_atob	= window.atob,
+	fWindow_parseInt= window.parseInt,
+	fString_trim	=(function() {
+		return cString.prototype.trim ? function(sValue) {return cString(sValue).trim();} : function(sValue) {
+			return cString(sValue).replace(/^\s+|\s+$/g, '');
+		};
+	})(),
+	fArray_indexOf	=(function() {
+		return cArray.prototype.indexOf ? function(aValue, vItem) {return aValue.indexOf(vItem);} : function(aValue, vItem) {
+			for (var nIndex = 0, nLength = aValue.length; nIndex < nLength; nIndex++)
+				if (aValue[nIndex] === vItem)
+					return nIndex;
+			return -1;
+		};
+	})();
+
+var sNS_XSD	= "http://www.w3.org/2001/XMLSchema",
+	sNS_XPF	= "http://www.w3.org/2005/xpath-functions",
+	sNS_XNS	= "http://www.w3.org/2000/xmlns/",
+	sNS_XML	= "http://www.w3.org/XML/1998/namespace";
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cException(sCode
+
+	) {
+
+	this.code		= sCode;
+	this.message	=
+
+					  oException_messages[sCode];
+};
+
+cException.prototype	= new cError;
+
+// "http://www.w3.org/2005/xqt-errors"
+
+var oException_messages	= {};
+oException_messages["XPDY0002"]	= "Evaluation of an expression relies on some part of the dynamic context that has not been assigned a value.";
+oException_messages["XPST0003"]	= "Expression is not a valid instance of the grammar";
+oException_messages["XPTY0004"]	= "Type is not appropriate for the context in which the expression occurs";
+oException_messages["XPST0008"]	= "Expression refers to an element name, attribute name, schema type name, namespace prefix, or variable name that is not defined in the static context";
+oException_messages["XPST0010"]	= "Axis not supported";
+oException_messages["XPST0017"]	= "Expanded QName and number of arguments in a function call do not match the name and arity of a function signature";
+oException_messages["XPTY0018"]	= "The result of the last step in a path expression contains both nodes and atomic values";
+oException_messages["XPTY0019"]	= "The result of a step (other than the last step) in a path expression contains an atomic value.";
+oException_messages["XPTY0020"]	= "In an axis step, the context item is not a node.";
+oException_messages["XPST0051"]	= "It is a static error if a QName that is used as an AtomicType in a SequenceType is not defined in the in-scope schema types as an atomic type.";
+oException_messages["XPST0081"]	= "A QName used in an expression contains a namespace prefix that cannot be expanded into a namespace URI by using the statically known namespaces.";
+//
+oException_messages["FORG0001"]	= "Invalid value for cast/constructor.";
+oException_messages["FORG0003"]	= "fn:zero-or-one called with a sequence containing more than one item.";
+oException_messages["FORG0004"]	= "fn:one-or-more called with a sequence containing no items.";
+oException_messages["FORG0005"]	= "fn:exactly-one called with a sequence containing zero or more than one item.";
+oException_messages["FORG0006"]	= "Invalid argument type.";
+//
+oException_messages["FODC0001"]	= "No context document.";
+//
+oException_messages["FORX0001"]	= "Invalid regular expression flags.";
+//
+oException_messages["FOCA0002"]	= "Invalid lexical value.";
+//
+oException_messages["FOCH0002"]	= "Unsupported collation.";
+
+oException_messages["FONS0004"]	= "No namespace found for prefix.";
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cLexer(sValue) {
+	var aMatch	= sValue.match(/\$?(?:(?![0-9-])(?:\w[\w.-]*|\*):)?(?![0-9-])(?:\w[\w.-]*|\*)|\(:|:\)|\/\/|\.\.|::|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?|\.\d+(?:[eE][+-]?\d+)?|"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*'|<<|>>|[!<>]=|(?![0-9-])[\w-]+:\*|\s+|./g);
+	if (aMatch) {
+		var nStack	= 0;
+		for (var nIndex = 0, nLength = aMatch.length; nIndex < nLength; nIndex++)
+			if (aMatch[nIndex] == '(:')
+				nStack++;
+			else
+			if (aMatch[nIndex] == ':)' && nStack)
+				nStack--;
+			else
+			if (!nStack && !/^\s/.test(aMatch[nIndex]))
+				this[this.length++]	= aMatch[nIndex];
+		if (nStack)
+			throw new cException("XPST0003"
+
+			);
+	}
+};
+
+cLexer.prototype.index		= 0;
+cLexer.prototype.length	= 0;
+
+cLexer.prototype.reset	= function() {
+	this.index	= 0;
+};
+
+cLexer.prototype.peek	= function(nOffset) {
+	return this[this.index +(nOffset || 0)] || '';
+};
+
+cLexer.prototype.next	= function(nOffset) {
+	return(this.index+= nOffset || 1) < this.length;
+};
+
+cLexer.prototype.back	= function(nOffset) {
+	return(this.index-= nOffset || 1) > 0;
+};
+
+cLexer.prototype.eof	= function() {
+	return this.index >= this.length;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cDOMAdapter() {
+
+};
+
+// Custom members
+cDOMAdapter.prototype.isNode		= function(oNode) {
+	return oNode &&!!oNode.nodeType;
+};
+
+cDOMAdapter.prototype.getProperty	= function(oNode, sName) {
+	return oNode[sName];
+};
+
+// Standard members
+cDOMAdapter.prototype.isSameNode	= function(oNode, oNode2) {
+	return oNode == oNode2;
+};
+
+cDOMAdapter.prototype.compareDocumentPosition	= function(oNode, oNode2) {
+	return oNode.compareDocumentPosition(oNode2);
+};
+
+cDOMAdapter.prototype.lookupNamespaceURI	= function(oNode, sPrefix) {
+	return oNode.lookupNamespaceURI(sPrefix);
+};
+
+// Document object members
+cDOMAdapter.prototype.getElementById	= function(oNode, sId) {
+	return oNode.getElementById(sId);
+};
+
+// Element/Document object members
+cDOMAdapter.prototype.getElementsByTagNameNS	= function(oNode, sNameSpaceURI, sLocalName) {
+	return oNode.getElementsByTagNameNS(sNameSpaceURI, sLocalName);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cDynamicContext(oStaticContext, vItem, oScope, oDOMAdapter) {
+	//
+	this.staticContext	= oStaticContext;
+	//
+	this.item		= vItem;
+	//
+	this.scope		= oScope || {};
+	this.stack		= {};
+	//
+	this.DOMAdapter	= oDOMAdapter || new cDOMAdapter;
+	//
+	var oDate	= new cDate,
+		nOffset	= oDate.getTimezoneOffset();
+	this.dateTime	= new cXSDateTime(oDate.getFullYear(), oDate.getMonth() + 1, oDate.getDate(), oDate.getHours(), oDate.getMinutes(), oDate.getSeconds() + oDate.getMilliseconds() / 1000, -nOffset);
+	this.timezone	= new cXSDayTimeDuration(0, cMath.abs(~~(nOffset / 60)), cMath.abs(nOffset % 60), 0, nOffset > 0);
+};
+
+cDynamicContext.prototype.item		= null;
+cDynamicContext.prototype.position	= 0;
+cDynamicContext.prototype.size		= 0;
+//
+cDynamicContext.prototype.scope		= null;
+cDynamicContext.prototype.stack		= null;	// Variables stack
+//
+cDynamicContext.prototype.dateTime	= null;
+cDynamicContext.prototype.timezone	= null;
+//
+cDynamicContext.prototype.staticContext	= null;
+
+// Stack management
+cDynamicContext.prototype.pushVariable	= function(sName, vValue) {
+	if (!this.stack.hasOwnProperty(sName))
+		this.stack[sName]	= [];
+	this.stack[sName].push(this.scope[sName]);
+	this.scope[sName] = vValue;
+};
+
+cDynamicContext.prototype.popVariable	= function(sName) {
+	if (this.stack.hasOwnProperty(sName)) {
+		this.scope[sName] = this.stack[sName].pop();
+		if (!this.stack[sName].length) {
+			delete this.stack[sName];
+			if (typeof this.scope[sName] == "undefined")
+				delete this.scope[sName];
+		}
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStaticContext() {
+	this.dataTypes	= {};
+	this.documents	= {};
+	this.functions	= {};
+	this.collations	= {};
+	this.collections= {};
+};
+
+cStaticContext.prototype.baseURI	= null;
+//
+cStaticContext.prototype.dataTypes	= null;
+cStaticContext.prototype.documents	= null;
+//
+cStaticContext.prototype.functions	= null;
+cStaticContext.prototype.defaultFunctionNamespace	= null;
+//
+cStaticContext.prototype.collations	= null;
+cStaticContext.prototype.defaultCollationName		= sNS_XPF + "/collation/codepoint";
+//
+cStaticContext.prototype.collections	= null;
+//
+cStaticContext.prototype.namespaceResolver	= null;
+cStaticContext.prototype.defaultElementNamespace	= null;
+
+//
+var rStaticContext_uri	= /^(?:\{([^\}]+)\})?(.+)$/;
+//
+cStaticContext.prototype.setDataType		= function(sUri, fFunction) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		if (aMatch[1] != sNS_XSD)
+			this.dataTypes[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getDataType		= function(sUri) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		return aMatch[1] == sNS_XSD ? hStaticContext_dataTypes[aMatch[2]] : this.dataTypes[sUri];
+};
+
+cStaticContext.prototype.setDocument		= function(sUri, fFunction) {
+	this.documents[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getDocument		= function(sUri) {
+	return this.documents[sUri];
+};
+
+cStaticContext.prototype.setFunction		= function(sUri, fFunction) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		if (aMatch[1] != sNS_XPF)
+			this.functions[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getFunction		= function(sUri) {
+	var aMatch	= sUri.match(rStaticContext_uri);
+	if (aMatch)
+		return aMatch[1] == sNS_XPF ? hStaticContext_functions[aMatch[2]] : this.functions[sUri];
+};
+
+cStaticContext.prototype.setCollation		= function(sUri, fFunction) {
+	this.collations[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getCollation		= function(sUri) {
+	return this.collations[sUri];
+};
+
+cStaticContext.prototype.setCollection	= function(sUri, fFunction) {
+	this.collections[sUri]	= fFunction;
+};
+
+cStaticContext.prototype.getCollection	= function(sUri) {
+	return this.collections[sUri];
+};
+
+cStaticContext.prototype.getURIForPrefix	= function(sPrefix) {
+	var oResolver	= this.namespaceResolver,
+		fResolver	= oResolver && oResolver.lookupNamespaceURI ? oResolver.lookupNamespaceURI : oResolver,
+		sNameSpaceURI;
+	if (fResolver instanceof cFunction && (sNameSpaceURI = fResolver.call(oResolver, sPrefix)))
+		return sNameSpaceURI;
+	if (sPrefix == 'fn')
+		return sNS_XPF;
+	if (sPrefix == 'xs')
+		return sNS_XSD;
+	if (sPrefix == "xml")
+		return sNS_XML;
+	if (sPrefix == "xmlns")
+		return sNS_XNS;
+	//
+	throw new cException("XPST0081"
+
+	);
+};
+
+// Static members
+//Converts non-null JavaScript object to XML Schema object
+cStaticContext.js2xs	= function(vItem) {
+	// Convert types from JavaScript to XPath 2.0
+	if (typeof vItem == "boolean")
+		vItem	= new cXSBoolean(vItem);
+	else
+	if (typeof vItem == "number")
+		vItem	=(fIsNaN(vItem) ||!fIsFinite(vItem)) ? new cXSDouble(vItem) : fNumericLiteral_parseValue(cString(vItem));
+	else
+		vItem	= new cXSString(cString(vItem));
+	//
+	return vItem;
+};
+
+// Converts non-null XML Schema object to JavaScript object
+cStaticContext.xs2js	= function(vItem) {
+	if (vItem instanceof cXSBoolean)
+		vItem	= vItem.valueOf();
+	else
+	if (fXSAnyAtomicType_isNumeric(vItem))
+		vItem	= vItem.valueOf();
+	else
+		vItem	= vItem.toString();
+	//
+	return vItem;
+};
+
+// System functions with signatures, operators and types
+var hStaticContext_functions	= {},
+	hStaticContext_signatures	= {},
+	hStaticContext_dataTypes	= {},
+	hStaticContext_operators	= {};
+
+function fStaticContext_defineSystemFunction(sName, aParameters, fFunction) {
+	// Register function
+	hStaticContext_functions[sName]	= fFunction;
+	// Register signature
+	hStaticContext_signatures[sName]	= aParameters;
+};
+
+function fStaticContext_defineSystemDataType(sName, fFunction) {
+	// Register dataType
+	hStaticContext_dataTypes[sName]	= fFunction;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExpression(sExpression, oStaticContext) {
+	var oLexer	= new cLexer(sExpression),
+		oExpr	= fExpr_parse(oLexer, oStaticContext);
+	//
+	if (!oLexer.eof())
+		throw new cException("XPST0003"
+
+		);
+	//
+	if (!oExpr)
+		throw new cException("XPST0003"
+
+		);
+	this.internalExpression	= oExpr;
+};
+
+cExpression.prototype.internalExpression	= null;
+
+// Public methods
+cExpression.prototype.evaluate	= function(oContext) {
+	return this.internalExpression.evaluate(oContext);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStringCollator() {
+
+};
+
+cStringCollator.prototype.equals	= function(sValue1, sValue2) {
+	throw "Not implemented";
+};
+
+cStringCollator.prototype.compare	= function(sValue1, sValue2) {
+	throw "Not implemented";
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSConstants(){};
+
+// XML Schema 1.0 Datatypes
+cXSConstants.ANYSIMPLETYPE_DT		= 1;
+cXSConstants.STRING_DT				= 2;
+cXSConstants.BOOLEAN_DT				= 3;
+cXSConstants.DECIMAL_DT				= 4;
+cXSConstants.FLOAT_DT				= 5;
+cXSConstants.DOUBLE_DT				= 6;
+cXSConstants.DURATION_DT			= 7;
+cXSConstants.DATETIME_DT			= 8;
+cXSConstants.TIME_DT				= 9;
+cXSConstants.DATE_DT				= 10;
+cXSConstants.GYEARMONTH_DT			= 11;
+cXSConstants.GYEAR_DT				= 12;
+cXSConstants.GMONTHDAY_DT			= 13;
+cXSConstants.GDAY_DT				= 14;
+cXSConstants.GMONTH_DT				= 15;
+cXSConstants.HEXBINARY_DT			= 16;
+cXSConstants.BASE64BINARY_DT		= 17;
+cXSConstants.ANYURI_DT				= 18;
+cXSConstants.QNAME_DT				= 19;
+cXSConstants.NOTATION_DT			= 20;
+cXSConstants.NORMALIZEDSTRING_DT	= 21;
+cXSConstants.TOKEN_DT				= 22;
+cXSConstants.LANGUAGE_DT			= 23;
+cXSConstants.NMTOKEN_DT				= 24;
+cXSConstants.NAME_DT				= 25;
+cXSConstants.NCNAME_DT				= 26;
+cXSConstants.ID_DT					= 27;
+cXSConstants.IDREF_DT				= 28;
+cXSConstants.ENTITY_DT				= 29;
+cXSConstants.INTEGER_DT				= 30;
+cXSConstants.NONPOSITIVEINTEGER_DT	= 31;
+cXSConstants.NEGATIVEINTEGER_DT		= 32;
+cXSConstants.LONG_DT				= 33;
+cXSConstants.INT_DT					= 34;
+cXSConstants.SHORT_DT				= 35;
+cXSConstants.BYTE_DT				= 36;
+cXSConstants.NONNEGATIVEINTEGER_DT	= 37;
+cXSConstants.UNSIGNEDLONG_DT		= 38;
+cXSConstants.UNSIGNEDINT_DT			= 39;
+cXSConstants.UNSIGNEDSHORT_DT		= 40;
+cXSConstants.UNSIGNEDBYTE_DT		= 41;
+cXSConstants.POSITIVEINTEGER_DT		= 42;
+cXSConstants.LISTOFUNION_DT			= 43;
+cXSConstants.LIST_DT				= 44;
+cXSConstants.UNAVAILABLE_DT			= 45;
+
+// XML Schema 1.1 Datatypes
+cXSConstants.DATETIMESTAMP_DT		= 46;
+cXSConstants.DAYMONTHDURATION_DT	= 47;
+cXSConstants.DAYTIMEDURATION_DT		= 48;
+cXSConstants.PRECISIONDECIMAL_DT	= 49;
+cXSConstants.ANYATOMICTYPE_DT		= 50;
+cXSConstants.ANYTYPE_DT				= 51;
+
+//
+cXSConstants.XT_YEARMONTHDURATION_DT=-1;
+cXSConstants.XT_UNTYPEDATOMIC_DT	=-2;
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExpr() {
+	this.items	= [];
+};
+
+cExpr.prototype.items	= null;
+
+// Static members
+function fExpr_parse (oLexer, oStaticContext) {
+	var oItem;
+	if (oLexer.eof() ||!(oItem = fExprSingle_parse(oLexer, oStaticContext)))
+		return;
+
+	// Create expression
+	var oExpr	= new cExpr;
+	oExpr.items.push(oItem);
+	while (oLexer.peek() == ',') {
+		oLexer.next();
+		if (oLexer.eof() ||!(oItem = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oExpr.items.push(oItem);
+	}
+	return oExpr;
+};
+
+// Public members
+cExpr.prototype.evaluate	= function(oContext) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = this.items.length; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators["concatenate"].call(oContext, oSequence, this.items[nIndex].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cExprSingle() {
+
+};
+
+// Static members
+function fExprSingle_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fIfExpr_parse(oLexer, oStaticContext)
+			|| fForExpr_parse(oLexer, oStaticContext)
+			|| fQuantifiedExpr_parse(oLexer, oStaticContext)
+			|| fOrExpr_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cForExpr() {
+	this.bindings	= [];
+	this.returnExpr	= null;
+};
+
+cForExpr.prototype.bindings		= null;
+cForExpr.prototype.returnExpr	= null;
+
+// Static members
+function fForExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == "for" && oLexer.peek(1).substr(0, 1) == '$') {
+		oLexer.next();
+
+		var oForExpr	= new cForExpr,
+			oExpr;
+		do {
+			oForExpr.bindings.push(fSimpleForBinding_parse(oLexer, oStaticContext));
+		}
+		while (oLexer.peek() == ',' && oLexer.next());
+
+		if (oLexer.peek() != "return")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oForExpr.returnExpr	= oExpr;
+		return oForExpr;
+	}
+};
+
+// Public members
+// for $x in X, $y in Y, $z in Z return $x + $y + $z
+// for $x in X return for $y in Y return for $z in Z return $x + $y + $z
+cForExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= [];
+	(function(oSelf, nBinding) {
+		var oBinding	= oSelf.bindings[nBinding++],
+			oSequence1	= oBinding.inExpr.evaluate(oContext),
+			sUri	= (oBinding.namespaceURI ? '{' + oBinding.namespaceURI + '}' : '') + oBinding.localName;
+		for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			oContext.pushVariable(sUri, oSequence1[nIndex]);
+			if (nBinding < oSelf.bindings.length)
+				arguments.callee(oSelf, nBinding);
+			else
+				oSequence	= oSequence.concat(oSelf.returnExpr.evaluate(oContext));
+			oContext.popVariable(sUri);
+		}
+	})(this, 0);
+
+	return oSequence;
+};
+
+//
+function cSimpleForBinding(sPrefix, sLocalName, sNameSpaceURI, oInExpr) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.inExpr		= oInExpr;
+};
+
+cSimpleForBinding.prototype.prefix			= null;
+cSimpleForBinding.prototype.localName		= null;
+cSimpleForBinding.prototype.namespaceURI	= null;
+cSimpleForBinding.prototype.inExpr		= null;
+
+function fSimpleForBinding_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+	if (!aMatch)
+		throw new cException("XPST0003"
+
+		);
+
+	if (aMatch[1] == '*' || aMatch[2] == '*')
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	if (oLexer.peek() != "in")
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cSimpleForBinding(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null, oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cIfExpr(oCondExpr, oThenExpr, oElseExpr) {
+	this.condExpr	= oCondExpr;
+	this.thenExpr		= oThenExpr;
+	this.elseExpr		= oElseExpr;
+};
+
+cIfExpr.prototype.condExpr	= null;
+cIfExpr.prototype.thenExpr	= null;
+cIfExpr.prototype.elseExpr	= null;
+
+// Static members
+function fIfExpr_parse (oLexer, oStaticContext) {
+	var oCondExpr,
+		oThenExpr,
+		oElseExpr;
+	if (oLexer.peek() == "if" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		//
+		if (oLexer.eof() ||!(oCondExpr = fExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.peek() != "then")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oThenExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		if (oLexer.peek() != "else")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oElseExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		return new cIfExpr(oCondExpr, oThenExpr, oElseExpr);
+	}
+};
+
+// Public members
+cIfExpr.prototype.evaluate	= function (oContext) {
+	return this[fFunction_sequence_toEBV(this.condExpr.evaluate(oContext), oContext) ? "thenExpr" : "elseExpr"].evaluate(oContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cQuantifiedExpr(sQuantifier) {
+	this.quantifier		= sQuantifier;
+	this.bindings		= [];
+	this.satisfiesExpr	= null;
+};
+
+cQuantifiedExpr.prototype.bindings		= null;
+cQuantifiedExpr.prototype.quantifier	= null;
+cQuantifiedExpr.prototype.satisfiesExpr	= null;
+
+// Static members
+function fQuantifiedExpr_parse (oLexer, oStaticContext) {
+	var sQuantifier	= oLexer.peek();
+	if ((sQuantifier == "some" || sQuantifier == "every") && oLexer.peek(1).substr(0, 1) == '$') {
+		oLexer.next();
+
+		var oQuantifiedExpr	= new cQuantifiedExpr(sQuantifier),
+			oExpr;
+		do {
+			oQuantifiedExpr.bindings.push(fSimpleQuantifiedBinding_parse(oLexer, oStaticContext));
+		}
+		while (oLexer.peek() == ',' && oLexer.next());
+
+		if (oLexer.peek() != "satisfies")
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oQuantifiedExpr.satisfiesExpr	= oExpr;
+		return oQuantifiedExpr;
+	}
+};
+
+// Public members
+cQuantifiedExpr.prototype.evaluate	= function (oContext) {
+	// TODO: re-factor
+	var bEvery	= this.quantifier == "every",
+		bResult	= bEvery ? true : false;
+	(function(oSelf, nBinding) {
+		var oBinding	= oSelf.bindings[nBinding++],
+			oSequence1	= oBinding.inExpr.evaluate(oContext),
+			sUri	= (oBinding.namespaceURI ? '{' + oBinding.namespaceURI + '}' : '') + oBinding.localName;
+		for (var nIndex = 0, nLength = oSequence1.length; (nIndex < nLength) && (bEvery ? bResult :!bResult); nIndex++) {
+			oContext.pushVariable(sUri, oSequence1[nIndex]);
+			if (nBinding < oSelf.bindings.length)
+				arguments.callee(oSelf, nBinding);
+			else
+				bResult	= fFunction_sequence_toEBV(oSelf.satisfiesExpr.evaluate(oContext), oContext);
+			oContext.popVariable(sUri);
+		}
+	})(this, 0);
+
+	return [new cXSBoolean(bResult)];
+};
+
+
+
+//
+function cSimpleQuantifiedBinding(sPrefix, sLocalName, sNameSpaceURI, oInExpr) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.inExpr		= oInExpr;
+};
+
+cSimpleQuantifiedBinding.prototype.prefix		= null;
+cSimpleQuantifiedBinding.prototype.localName	= null;
+cSimpleQuantifiedBinding.prototype.namespaceURI	= null;
+cSimpleQuantifiedBinding.prototype.inExpr	= null;
+
+function fSimpleQuantifiedBinding_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+	if (!aMatch)
+		throw new cException("XPST0003"
+
+		);
+
+	if (aMatch[1] == '*' || aMatch[2] == '*')
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	if (oLexer.peek() != "in")
+		throw new cException("XPST0003"
+
+		);
+
+	oLexer.next();
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cSimpleQuantifiedBinding(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null, oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cComparisonExpr(oLeft, oRight, sOperator) {
+	this.left	= oLeft;
+	this.right	= oRight;
+	this.operator	= sOperator;
+};
+
+cComparisonExpr.prototype.left	= null;
+cComparisonExpr.prototype.right	= null;
+cComparisonExpr.prototype.operator	= null;
+
+// Static members
+function fComparisonExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oRight;
+	if (oLexer.eof() ||!(oExpr = fRangeExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hComparisonExpr_operators))
+		return oExpr;
+
+	// Comparison expression
+	var sOperator	= oLexer.peek();
+	oLexer.next();
+	if (oLexer.eof() ||!(oRight = fRangeExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cComparisonExpr(oExpr, oRight, sOperator);
+};
+
+// Public members
+cComparisonExpr.prototype.evaluate	= function (oContext) {
+	var oResult	= hComparisonExpr_operators[this.operator](this, oContext);
+	return oResult == null ? [] : [oResult];
+};
+
+// General comparison
+function fComparisonExpr_GeneralComp(oExpr, oContext) {
+	var oLeft	= fFunction_sequence_atomize(oExpr.left.evaluate(oContext), oContext);
+	if (!oLeft.length)
+		return new cXSBoolean(false);
+
+	var oRight	= fFunction_sequence_atomize(oExpr.right.evaluate(oContext), oContext);
+	if (!oRight.length)
+		return new cXSBoolean(false);
+
+	var bResult	= false;
+	for (var nLeftIndex = 0, nLeftLength = oLeft.length, bLeft, vLeft; (nLeftIndex < nLeftLength) &&!bResult; nLeftIndex++) {
+		for (var nRightIndex = 0, nRightLength = oRight.length, bRight, vRight; (nRightIndex < nRightLength) &&!bResult; nRightIndex++) {
+
+			vLeft	= oLeft[nLeftIndex];
+			vRight	= oRight[nRightIndex];
+
+			bLeft	= vLeft instanceof cXSUntypedAtomic;
+			bRight	= vRight instanceof cXSUntypedAtomic;
+
+			if (bLeft && bRight) {
+				// cast xs:untypedAtomic to xs:string
+				vLeft	= cXSString.cast(vLeft);
+				vRight	= cXSString.cast(vRight);
+			}
+			else {
+				//
+				if (bLeft) {
+					// Special: durations
+					if (vRight instanceof cXSDayTimeDuration)
+						vLeft	= cXSDayTimeDuration.cast(vLeft);
+					else
+					if (vRight instanceof cXSYearMonthDuration)
+						vLeft	= cXSYearMonthDuration.cast(vLeft);
+					else
+					//
+					if (vRight.primitiveKind)
+						vLeft	= hStaticContext_dataTypes[vRight.primitiveKind].cast(vLeft);
+				}
+				else
+				if (bRight) {
+					// Special: durations
+					if (vLeft instanceof cXSDayTimeDuration)
+						vRight	= cXSDayTimeDuration.cast(vRight);
+					else
+					if (vLeft instanceof cXSYearMonthDuration)
+						vRight	= cXSYearMonthDuration.cast(vRight);
+					else
+					//
+					if (vLeft.primitiveKind)
+						vRight	= hStaticContext_dataTypes[vLeft.primitiveKind].cast(vRight);
+				}
+
+				// cast xs:anyURI to xs:string
+				if (vLeft instanceof cXSAnyURI)
+					vLeft	= cXSString.cast(vLeft);
+				if (vRight instanceof cXSAnyURI)
+					vRight	= cXSString.cast(vRight);
+			}
+
+			bResult	= hComparisonExpr_ValueComp_operators[hComparisonExpr_GeneralComp_map[oExpr.operator]](vLeft, vRight, oContext).valueOf();
+		}
+	}
+	return new cXSBoolean(bResult);
+};
+
+var hComparisonExpr_GeneralComp_map	= {
+	'=':	'eq',
+	'!=':	'ne',
+	'>':	'gt',
+	'<':	'lt',
+	'>=':	'ge',
+	'<=':	'le'
+};
+
+// Value comparison
+function fComparisonExpr_ValueComp(oExpr, oContext) {
+	var oLeft	= fFunction_sequence_atomize(oExpr.left.evaluate(oContext), oContext);
+	if (!oLeft.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var oRight	= fFunction_sequence_atomize(oExpr.right.evaluate(oContext), oContext);
+	if (!oRight.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+
+	var vLeft	= oLeft[0],
+		vRight	= oRight[0];
+
+	// cast xs:untypedAtomic to xs:string
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSString.cast(vLeft);
+	if (vRight instanceof cXSUntypedAtomic)
+		vRight	= cXSString.cast(vRight);
+
+	// cast xs:anyURI to xs:string
+	if (vLeft instanceof cXSAnyURI)
+		vLeft	= cXSString.cast(vLeft);
+	if (vRight instanceof cXSAnyURI)
+		vRight	= cXSString.cast(vRight);
+
+	//
+	return hComparisonExpr_ValueComp_operators[oExpr.operator](vLeft, vRight, oContext);
+};
+
+//
+var hComparisonExpr_ValueComp_operators	= {};
+hComparisonExpr_ValueComp_operators['eq']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-equal";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-equal";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-equal"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-equal";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-equal";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-equal";
+	}
+	else
+	if (oLeft instanceof cXSDuration) {
+		if (oRight instanceof cXSDuration)
+			sOperator	= "duration-equal";
+	}
+	else
+	if (oLeft instanceof cXSGYearMonth) {
+		if (oRight instanceof cXSGYearMonth)
+			sOperator	= "gYearMonth-equal";
+	}
+	else
+	if (oLeft instanceof cXSGYear) {
+		if (oRight instanceof cXSGYear)
+			sOperator	= "gYear-equal";
+	}
+	else
+	if (oLeft instanceof cXSGMonthDay) {
+		if (oRight instanceof cXSGMonthDay)
+			sOperator	= "gMonthDay-equal";
+	}
+	else
+	if (oLeft instanceof cXSGMonth) {
+		if (oRight instanceof cXSGMonth)
+			sOperator	= "gMonth-equal";
+	}
+	else
+	if (oLeft instanceof cXSGDay) {
+		if (oRight instanceof cXSGDay)
+			sOperator	= "gDay-equal";
+	}
+	// skipped: xs:anyURI (covered by xs:string)
+	else
+	if (oLeft instanceof cXSQName) {
+		if (oRight instanceof cXSQName)
+			sOperator	= "QName-equal";
+	}
+	else
+	if (oLeft instanceof cXSHexBinary) {
+		if (oRight instanceof cXSHexBinary)
+			sOperator	= "hexBinary-equal";
+	}
+	else
+	if (oLeft instanceof cXSBase64Binary) {
+		if (oRight instanceof cXSBase64Binary)
+			sOperator	= "base64Binary-equal";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:NOTATION
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['ne']	= function(oLeft, oRight, oContext) {
+	return new cXSBoolean(!hComparisonExpr_ValueComp_operators['eq'](oLeft, oRight, oContext).valueOf());
+};
+hComparisonExpr_ValueComp_operators['gt']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-greater-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-greater-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['lt']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-less-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-less-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-less-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(0));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-less-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-less-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-less-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['ge']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-less-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-less-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-greater-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(-1));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-less-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-less-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-less-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-less-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return new cXSBoolean(!hStaticContext_operators[sOperator].call(oContext, oLeft, oRight).valueOf());
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+hComparisonExpr_ValueComp_operators['le']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSBoolean) {
+		if (oRight instanceof cXSBoolean)
+			sOperator	= "boolean-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSString) {
+		if (oRight instanceof cXSString)
+			return hStaticContext_operators["numeric-less-than"].call(oContext, hStaticContext_functions["compare"].call(oContext, oLeft, oRight), new cXSInteger(1));
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "date-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "time-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "dateTime-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "yearMonthDuration-greater-than";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "dayTimeDuration-greater-than";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return new cXSBoolean(!hStaticContext_operators[sOperator].call(oContext, oLeft, oRight).valueOf());
+
+	// skipped: xs:anyURI (covered by xs:string)
+	throw new cException("XPTY0004"
+
+	);	// Cannot compare {type1} to {type2}
+};
+
+// Node comparison
+function fComparisonExpr_NodeComp(oExpr, oContext) {
+	var oLeft	= oExpr.left.evaluate(oContext);
+	if (!oLeft.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+	// Assert item type
+	fFunctionCall_assertSequenceItemType(oContext, oLeft, cXTNode
+
+	);
+
+	var oRight	= oExpr.right.evaluate(oContext);
+	if (!oRight.length)
+		return null;
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+	// Assert item type
+	fFunctionCall_assertSequenceItemType(oContext, oRight, cXTNode
+
+	);
+
+	return hComparisonExpr_NodeComp_operators[oExpr.operator](oLeft[0], oRight[0], oContext);
+};
+
+var hComparisonExpr_NodeComp_operators	= {};
+hComparisonExpr_NodeComp_operators['is']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["is-same-node"].call(oContext, oLeft, oRight);
+};
+hComparisonExpr_NodeComp_operators['>>']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["node-after"].call(oContext, oLeft, oRight);
+};
+hComparisonExpr_NodeComp_operators['<<']	= function(oLeft, oRight, oContext) {
+	return hStaticContext_operators["node-before"].call(oContext, oLeft, oRight);
+};
+
+// Operators
+var hComparisonExpr_operators	= {
+	// GeneralComp
+	'=':	fComparisonExpr_GeneralComp,
+	'!=':	fComparisonExpr_GeneralComp,
+	'<':	fComparisonExpr_GeneralComp,
+	'<=':	fComparisonExpr_GeneralComp,
+	'>':	fComparisonExpr_GeneralComp,
+	'>=':	fComparisonExpr_GeneralComp,
+	// ValueComp
+	'eq':	fComparisonExpr_ValueComp,
+	'ne':	fComparisonExpr_ValueComp,
+	'lt':	fComparisonExpr_ValueComp,
+	'le':	fComparisonExpr_ValueComp,
+	'gt':	fComparisonExpr_ValueComp,
+	'ge':	fComparisonExpr_ValueComp,
+	// NodeComp
+	'is':	fComparisonExpr_NodeComp,
+	'>>':	fComparisonExpr_NodeComp,
+	'<<':	fComparisonExpr_NodeComp
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAdditiveExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cAdditiveExpr.prototype.left	= null;
+cAdditiveExpr.prototype.items	= null;
+
+//
+var hAdditiveExpr_operators	= {};
+hAdditiveExpr_operators['+']	= function(oLeft, oRight, oContext) {
+	var sOperator	= '',
+		bReverse	= false;
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-add";
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDuration-to-date";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-date";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSDate) {
+			sOperator	= "add-yearMonthDuration-to-date";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDateTime) {
+			sOperator	= "add-yearMonthDuration-to-dateTime";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDurations";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDate) {
+			sOperator	= "add-dayTimeDuration-to-date";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSTime) {
+			sOperator	= "add-dayTimeDuration-to-time";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDateTime) {
+			sOperator	= "add-dayTimeDuration-to-dateTime";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDurations";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-time";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "add-yearMonthDuration-to-dateTime";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "add-dayTimeDuration-to-dateTime";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, bReverse ? oRight : oLeft, bReverse ? oLeft : oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hAdditiveExpr_operators['-']	= function (oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-subtract";
+	}
+	else
+	if (oLeft instanceof cXSDate) {
+		if (oRight instanceof cXSDate)
+			sOperator	= "subtract-dates";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDuration-from-date";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-date";
+	}
+	else
+	if (oLeft instanceof cXSTime) {
+		if (oRight instanceof cXSTime)
+			sOperator	= "subtract-times";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-time";
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		if (oRight instanceof cXSDateTime)
+			sOperator	= "subtract-dateTimes";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDuration-from-dateTime";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDuration-from-dateTime";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "subtract-yearMonthDurations";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "subtract-dayTimeDurations";
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+function fAdditiveExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fMultiplicativeExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hAdditiveExpr_operators))
+		return oExpr;
+
+	// Additive expression
+	var oAdditiveExpr	= new cAdditiveExpr(oExpr),
+		sOperator;
+	while ((sOperator = oLexer.peek()) in hAdditiveExpr_operators) {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fMultiplicativeExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oAdditiveExpr.items.push([sOperator, oExpr]);
+	}
+	return oAdditiveExpr;
+};
+
+// Public members
+cAdditiveExpr.prototype.evaluate	= function (oContext) {
+	var oLeft	= fFunction_sequence_atomize(this.left.evaluate(oContext), oContext);
+
+	if (!oLeft.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var vLeft	= oLeft[0];
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSDouble.cast(vLeft);	// cast to xs:double
+
+	for (var nIndex = 0, nLength = this.items.length, oRight, vRight; nIndex < nLength; nIndex++) {
+		oRight	= fFunction_sequence_atomize(this.items[nIndex][1].evaluate(oContext), oContext);
+
+		if (!oRight.length)
+			return [];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+		);
+
+		vRight	= oRight[0];
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+		vLeft	= hAdditiveExpr_operators[this.items[nIndex][0]](vLeft, vRight, oContext);
+	}
+	return [vLeft];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cMultiplicativeExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cMultiplicativeExpr.prototype.left	= null;
+cMultiplicativeExpr.prototype.items	= null;
+
+//
+var hMultiplicativeExpr_operators	= {};
+hMultiplicativeExpr_operators['*']		= function (oLeft, oRight, oContext) {
+	var sOperator	= '',
+		bReverse	= false;
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-multiply";
+		else
+		if (oRight instanceof cXSYearMonthDuration) {
+			sOperator	= "multiply-yearMonthDuration";
+			bReverse	= true;
+		}
+		else
+		if (oRight instanceof cXSDayTimeDuration) {
+			sOperator	= "multiply-dayTimeDuration";
+			bReverse	= true;
+		}
+	}
+	else {
+		if (oLeft instanceof cXSYearMonthDuration) {
+			if (fXSAnyAtomicType_isNumeric(oRight))
+				sOperator	= "multiply-yearMonthDuration";
+		}
+		else
+		if (oLeft instanceof cXSDayTimeDuration) {
+			if (fXSAnyAtomicType_isNumeric(oRight))
+				sOperator	= "multiply-dayTimeDuration";
+		}
+	}
+
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, bReverse ? oRight : oLeft, bReverse ? oLeft : oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['div']	= function (oLeft, oRight, oContext) {
+	var sOperator	= '';
+
+	if (fXSAnyAtomicType_isNumeric(oLeft)) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "numeric-divide";
+	}
+	else
+	if (oLeft instanceof cXSYearMonthDuration) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "divide-yearMonthDuration";
+		else
+		if (oRight instanceof cXSYearMonthDuration)
+			sOperator	= "divide-yearMonthDuration-by-yearMonthDuration";
+	}
+	else
+	if (oLeft instanceof cXSDayTimeDuration) {
+		if (fXSAnyAtomicType_isNumeric(oRight))
+			sOperator	= "divide-dayTimeDuration";
+		else
+		if (oRight instanceof cXSDayTimeDuration)
+			sOperator	= "divide-dayTimeDuration-by-dayTimeDuration";
+	}
+	// Call operator function
+	if (sOperator)
+		return hStaticContext_operators[sOperator].call(oContext, oLeft, oRight);
+
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['idiv']	= function (oLeft, oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oLeft) && fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-integer-divide"].call(oContext, oLeft, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hMultiplicativeExpr_operators['mod']	= function (oLeft, oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oLeft) && fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-mod"].call(oContext, oLeft, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+function fMultiplicativeExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fUnionExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!(oLexer.peek() in hMultiplicativeExpr_operators))
+		return oExpr;
+
+	// Additive expression
+	var oMultiplicativeExpr	= new cMultiplicativeExpr(oExpr),
+		sOperator;
+	while ((sOperator = oLexer.peek()) in hMultiplicativeExpr_operators) {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fUnionExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oMultiplicativeExpr.items.push([sOperator, oExpr]);
+	}
+	return oMultiplicativeExpr;
+};
+
+// Public members
+cMultiplicativeExpr.prototype.evaluate	= function (oContext) {
+	var oLeft	= fFunction_sequence_atomize(this.left.evaluate(oContext), oContext);
+
+	//
+	if (!oLeft.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+
+	var vLeft	= oLeft[0];
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSDouble.cast(vLeft);	// cast to xs:double
+
+	for (var nIndex = 0, nLength = this.items.length, oRight, vRight; nIndex < nLength; nIndex++) {
+		oRight	= fFunction_sequence_atomize(this.items[nIndex][1].evaluate(oContext), oContext);
+
+		if (!oRight.length)
+			return [];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+		);
+
+		vRight	= oRight[0];
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+		vLeft	= hMultiplicativeExpr_operators[this.items[nIndex][0]](vLeft, vRight, oContext);
+	}
+	return [vLeft];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cUnaryExpr(sOperator, oExpr) {
+	this.operator	= sOperator;
+	this.expression	= oExpr;
+};
+
+cUnaryExpr.prototype.operator	= null;
+cUnaryExpr.prototype.expression	= null;
+
+//
+var hUnaryExpr_operators	= {};
+hUnaryExpr_operators['-']	= function(oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-unary-minus"].call(oContext, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+hUnaryExpr_operators['+']	= function(oRight, oContext) {
+	if (fXSAnyAtomicType_isNumeric(oRight))
+		return hStaticContext_operators["numeric-unary-plus"].call(oContext, oRight);
+	//
+	throw new cException("XPTY0004"
+
+	);	// Arithmetic operator is not defined for arguments of types ({type1}, {type2})
+};
+
+// Static members
+// UnaryExpr	:= ("-" | "+")* ValueExpr
+function fUnaryExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+	if (!(oLexer.peek() in hUnaryExpr_operators))
+		return fValueExpr_parse(oLexer, oStaticContext);
+
+	// Unary expression
+	var sOperator	= '+',
+		oExpr;
+	while (oLexer.peek() in hUnaryExpr_operators) {
+		if (oLexer.peek() == '-')
+			sOperator	= sOperator == '-' ? '+' : '-';
+		oLexer.next();
+	}
+	if (oLexer.eof() ||!(oExpr = fValueExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cUnaryExpr(sOperator, oExpr);
+};
+
+cUnaryExpr.prototype.evaluate	= function (oContext) {
+	var oRight	= fFunction_sequence_atomize(this.expression.evaluate(oContext), oContext);
+
+	//
+	if (!oRight.length)
+		return [];
+	// Assert cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+
+	var vRight	= oRight[0];
+	if (vRight instanceof cXSUntypedAtomic)
+		vRight	= cXSDouble.cast(vRight);	// cast to xs:double
+
+	return [hUnaryExpr_operators[this.operator](vRight, oContext)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cValueExpr() {
+
+};
+
+// Static members
+function fValueExpr_parse (oLexer, oStaticContext) {
+	return fPathExpr_parse(oLexer, oStaticContext);
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cOrExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cOrExpr.prototype.left	= null;
+cOrExpr.prototype.items	= null;
+
+// Static members
+function fOrExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fAndExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "or")
+		return oExpr;
+
+	// Or expression
+	var oOrExpr	= new cOrExpr(oExpr);
+	while (oLexer.peek() == "or") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fAndExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oOrExpr.items.push(oExpr);
+	}
+	return oOrExpr;
+};
+
+// Public members
+cOrExpr.prototype.evaluate	= function (oContext) {
+	var bValue	= fFunction_sequence_toEBV(this.left.evaluate(oContext), oContext);
+	for (var nIndex = 0, nLength = this.items.length; (nIndex < nLength) && !bValue; nIndex++)
+		bValue	= fFunction_sequence_toEBV(this.items[nIndex].evaluate(oContext), oContext);
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAndExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cAndExpr.prototype.left		= null;
+cAndExpr.prototype.items	= null;
+
+// Static members
+function fAndExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fComparisonExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "and")
+		return oExpr;
+
+	// And expression
+	var oAndExpr	= new cAndExpr(oExpr);
+	while (oLexer.peek() == "and") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fComparisonExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oAndExpr.items.push(oExpr);
+	}
+	return oAndExpr;
+};
+
+// Public members
+cAndExpr.prototype.evaluate	= function (oContext) {
+	var bValue	= fFunction_sequence_toEBV(this.left.evaluate(oContext), oContext);
+	for (var nIndex = 0, nLength = this.items.length; (nIndex < nLength) && bValue; nIndex++)
+		bValue	= fFunction_sequence_toEBV(this.items[nIndex].evaluate(oContext), oContext);
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStepExpr() {
+
+};
+
+cStepExpr.prototype.predicates	= null;
+
+// Static members
+function fStepExpr_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fFilterExpr_parse(oLexer, oStaticContext)
+			|| fAxisStep_parse(oLexer, oStaticContext);
+};
+
+function fStepExpr_parsePredicates (oLexer, oStaticContext, oStep) {
+	var oExpr;
+	// Parse predicates
+	while (oLexer.peek() == '[') {
+		oLexer.next();
+
+		if (oLexer.eof() ||!(oExpr = fExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+
+		oStep.predicates.push(oExpr);
+
+		if (oLexer.peek() != ']')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+	}
+};
+
+// Public members
+cStepExpr.prototype.applyPredicates	= function(oSequence, oContext) {
+	var vContextItem	= oContext.item,
+		nContextPosition= oContext.position,
+		nContextSize	= oContext.size;
+	//
+	for (var nPredicateIndex = 0, oSequence1, nPredicateLength = this.predicates.length; nPredicateIndex < nPredicateLength; nPredicateIndex++) {
+		oSequence1	= oSequence;
+		oSequence	= [];
+		for (var nIndex = 0, oSequence2, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			// Set new context
+			oContext.item		= oSequence1[nIndex];
+			oContext.position	= nIndex + 1;
+			oContext.size		= nLength;
+			//
+			oSequence2	= this.predicates[nPredicateIndex].evaluate(oContext);
+			//
+			if (oSequence2.length == 1 && fXSAnyAtomicType_isNumeric(oSequence2[0])) {
+				if (oSequence2[0].valueOf() == nIndex + 1)
+					oSequence.push(oSequence1[nIndex]);
+			}
+			else
+			if (fFunction_sequence_toEBV(oSequence2, oContext))
+				oSequence.push(oSequence1[nIndex]);
+		}
+	}
+	// Restore context
+	oContext.item		= vContextItem;
+	oContext.position	= nContextPosition;
+	oContext.size		= nContextSize;
+	//
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAxisStep(sAxis, oTest) {
+	this.axis	= sAxis;
+	this.test	= oTest;
+	this.predicates	= [];
+};
+
+cAxisStep.prototype	= new cStepExpr;
+
+cAxisStep.prototype.axis		= null;
+cAxisStep.prototype.test		= null;
+
+//
+var hAxisStep_axises	= {};
+// Forward axis
+hAxisStep_axises["attribute"]			= {};
+hAxisStep_axises["child"]				= {};
+hAxisStep_axises["descendant"]			= {};
+hAxisStep_axises["descendant-or-self"]	= {};
+hAxisStep_axises["following"]			= {};
+hAxisStep_axises["following-sibling"]	= {};
+hAxisStep_axises["self"]				= {};
+// hAxisStep_axises["namespace"]			= {};	// deprecated in 2.0
+// Reverse axis
+hAxisStep_axises["ancestor"]			= {};
+hAxisStep_axises["ancestor-or-self"]	= {};
+hAxisStep_axises["parent"]				= {};
+hAxisStep_axises["preceding"]			= {};
+hAxisStep_axises["preceding-sibling"]	= {};
+
+// Static members
+function fAxisStep_parse (oLexer, oStaticContext) {
+	var sAxis	= oLexer.peek(),
+		oExpr,
+		oStep;
+	if (oLexer.peek(1) == '::') {
+		if (!(sAxis in hAxisStep_axises))
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next(2);
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oStep	= new cAxisStep(sAxis, oExpr);
+	}
+	else
+	if (sAxis == '..') {
+		oLexer.next();
+		oStep	= new cAxisStep("parent", new cKindTest("node"));
+	}
+	else
+	if (sAxis == '@') {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oStep	= new cAxisStep("attribute", oExpr);
+	}
+	else {
+		if (oLexer.eof() ||!(oExpr = fNodeTest_parse(oLexer, oStaticContext)))
+			return;
+		oStep	= new cAxisStep(oExpr instanceof cKindTest && oExpr.name == "attribute" ? "attribute" : "child", oExpr);
+	}
+	//
+	fStepExpr_parsePredicates(oLexer, oStaticContext, oStep);
+
+	return oStep;
+};
+
+// Public members
+cAxisStep.prototype.evaluate	= function (oContext) {
+	var oItem	= oContext.item;
+
+	if (!oContext.DOMAdapter.isNode(oItem))
+		throw new cException("XPTY0020");
+
+	var oSequence	= [],
+		fGetProperty= oContext.DOMAdapter.getProperty,
+		nType		= fGetProperty(oItem, "nodeType");
+
+	switch (this.axis) {
+		// Forward axis
+		case "attribute":
+			if (nType == 1)
+				for (var aAttributes = fGetProperty(oItem, "attributes"), nIndex = 0, nLength = aAttributes.length; nIndex < nLength; nIndex++)
+					oSequence.push(aAttributes[nIndex]);
+			break;
+
+		case "child":
+			for (var oNode = fGetProperty(oItem, "firstChild"); oNode; oNode = fGetProperty(oNode, "nextSibling"))
+				oSequence.push(oNode);
+			break;
+
+		case "descendant-or-self":
+			oSequence.push(oItem);
+			// No break left intentionally
+		case "descendant":
+			fAxisStep_getChildrenForward(fGetProperty(oItem, "firstChild"), oSequence, fGetProperty);
+			break;
+
+		case "following":
+			// TODO: Attribute node context
+			for (var oParent = oItem, oSibling; oParent; oParent = fGetProperty(oParent, "parentNode"))
+				if (oSibling = fGetProperty(oParent, "nextSibling"))
+					fAxisStep_getChildrenForward(oSibling, oSequence, fGetProperty);
+			break;
+
+		case "following-sibling":
+			for (var oNode = oItem; oNode = fGetProperty(oNode, "nextSibling");)
+				oSequence.push(oNode);
+			break;
+
+		case "self":
+			oSequence.push(oItem);
+			break;
+
+		// Reverse axis
+		case "ancestor-or-self":
+			oSequence.push(oItem);
+			// No break left intentionally
+		case "ancestor":
+			for (var oNode = nType == 2 ? fGetProperty(oItem, "ownerElement") : oItem; oNode = fGetProperty(oNode, "parentNode");)
+				oSequence.push(oNode);
+			break;
+
+		case "parent":
+			var oParent	= nType == 2 ? fGetProperty(oItem, "ownerElement") : fGetProperty(oItem, "parentNode");
+			if (oParent)
+				oSequence.push(oParent);
+			break;
+
+		case "preceding":
+			// TODO: Attribute node context
+			for (var oParent = oItem, oSibling; oParent; oParent = fGetProperty(oParent, "parentNode"))
+				if (oSibling = fGetProperty(oParent, "previousSibling"))
+					fAxisStep_getChildrenBackward(oSibling, oSequence, fGetProperty);
+			break;
+
+		case "preceding-sibling":
+			for (var oNode = oItem; oNode = fGetProperty(oNode, "previousSibling");)
+				oSequence.push(oNode);
+			break;
+	}
+
+	// Apply test
+	if (oSequence.length && !(this.test instanceof cKindTest && this.test.name == "node")) {
+		var oSequence1	= oSequence;
+		oSequence	= [];
+		for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++) {
+			if (this.test.test(oSequence1[nIndex], oContext))
+				oSequence.push(oSequence1[nIndex]);
+		}
+	}
+
+	// Apply predicates
+	if (oSequence.length && this.predicates.length)
+		oSequence	= this.applyPredicates(oSequence, oContext);
+
+	// Reverse results if reverse axis
+	switch (this.axis) {
+		case "ancestor":
+		case "ancestor-or-self":
+		case "parent":
+		case "preceding":
+		case "preceding-sibling":
+			oSequence.reverse();
+	}
+
+	return oSequence;
+};
+
+//
+function fAxisStep_getChildrenForward(oNode, oSequence, fGetProperty) {
+	for (var oChild; oNode; oNode = fGetProperty(oNode, "nextSibling")) {
+		oSequence.push(oNode);
+		if (oChild = fGetProperty(oNode, "firstChild"))
+			fAxisStep_getChildrenForward(oChild, oSequence, fGetProperty);
+	}
+};
+
+function fAxisStep_getChildrenBackward(oNode, oSequence, fGetProperty) {
+	for (var oChild; oNode; oNode = fGetProperty(oNode, "previousSibling")) {
+		if (oChild = fGetProperty(oNode, "lastChild"))
+			fAxisStep_getChildrenBackward(oChild, oSequence, fGetProperty);
+		oSequence.push(oNode);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cPathExpr() {
+	this.items	= [];
+};
+
+cPathExpr.prototype.items	= null;
+
+// Static members
+function fPathExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+	var sSingleSlash	= '/',
+		sDoubleSlash	= '/' + '/';
+
+	var oPathExpr	= new cPathExpr(),
+		sSlash	= oLexer.peek(),
+		oExpr;
+	// Parse first step
+	if (sSlash == sDoubleSlash || sSlash == sSingleSlash) {
+		oLexer.next();
+		oPathExpr.items.push(new cFunctionCall(null, "root", sNS_XPF));
+		//
+		if (sSlash == sDoubleSlash)
+			oPathExpr.items.push(new cAxisStep("descendant-or-self", new cKindTest("node")));
+	}
+
+	//
+	if (oLexer.eof() ||!(oExpr = fStepExpr_parse(oLexer, oStaticContext))) {
+		if (sSlash == sSingleSlash)
+			return oPathExpr.items[0];	// '/' expression
+		if (sSlash == sDoubleSlash)
+			throw new cException("XPST0003"
+
+			);
+		return;
+	}
+	oPathExpr.items.push(oExpr);
+
+	// Parse other steps
+	while ((sSlash = oLexer.peek()) == sSingleSlash || sSlash == sDoubleSlash) {
+		if (sSlash == sDoubleSlash)
+			oPathExpr.items.push(new cAxisStep("descendant-or-self", new cKindTest("node")));
+		//
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fStepExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		//
+		oPathExpr.items.push(oExpr);
+	}
+
+	if (oPathExpr.items.length == 1)
+		return oPathExpr.items[0];
+
+	//
+	return oPathExpr;
+};
+
+// Public members
+cPathExpr.prototype.evaluate	= function (oContext) {
+	var vContextItem	= oContext.item;
+	//
+	var oSequence	= [vContextItem];
+	for (var nItemIndex = 0, nItemLength = this.items.length, oSequence1; nItemIndex < nItemLength; nItemIndex++) {
+		oSequence1	= [];
+		for (var nIndex = 0, nLength = oSequence.length; nIndex < nLength; nIndex++) {
+			// Set new context item
+			oContext.item	= oSequence[nIndex];
+			//
+			for (var nRightIndex = 0, oSequence2 = this.items[nItemIndex].evaluate(oContext), nRightLength = oSequence2.length; nRightIndex < nRightLength; nRightIndex++)
+				if ((nItemIndex < nItemLength - 1) && !oContext.DOMAdapter.isNode(oSequence2[nRightIndex]))
+					throw new cException("XPTY0019");
+				else
+				if (fArray_indexOf(oSequence1, oSequence2[nRightIndex]) ==-1)
+					oSequence1.push(oSequence2[nRightIndex]);
+		}
+		oSequence	= oSequence1;
+	};
+	// Restore context item
+	oContext.item	= vContextItem;
+	//
+	return fFunction_sequence_order(oSequence, oContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNodeTest() {
+
+};
+
+// Static members
+function fNodeTest_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fKindTest_parse(oLexer, oStaticContext)
+			|| fNameTest_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cKindTest(sName) {
+	this.name	= sName;
+	this.args	= [];
+};
+
+cKindTest.prototype	= new cNodeTest;
+
+cKindTest.prototype.name	= null;
+cKindTest.prototype.args	= null;
+
+var hKindTest_names	= {};
+//
+hKindTest_names["document-node"]	= {};
+hKindTest_names["element"]			= {};
+hKindTest_names["attribute"]		= {};
+hKindTest_names["processing-instruction"]	= {};
+hKindTest_names["comment"]			= {};
+hKindTest_names["text"]				= {};
+hKindTest_names["node"]				= {};
+//
+hKindTest_names["schema-element"]	= {};
+hKindTest_names["schema-attribute"]	= {};
+
+// Static members
+function fKindTest_parse (oLexer, oStaticContext) {
+	var sName	= oLexer.peek(),
+		oValue;
+	if (oLexer.peek(1) == '(') {
+		//
+		if (!(sName in hKindTest_names))
+			throw new cException("XPST0003"
+
+			);
+
+		//
+		oLexer.next(2);
+		//
+		var oTest	= new cKindTest(sName);
+		if (oLexer.peek() != ')') {
+			if (sName == "document-node") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "element") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "attribute") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "processing-instruction") {
+				oValue = fStringLiteral_parse(oLexer, oStaticContext);
+				if (!oValue) {
+					oValue = new cStringLiteral(new cXSString(oLexer.peek()));
+					oLexer.next();
+				}
+				oTest.args.push(oValue);
+			}
+			else
+			if (sName == "schema-attribute") {
+				// TODO: parse test further
+			}
+			else
+			if (sName == "schema-element") {
+				// TODO: parse test further
+			}
+		}
+		else {
+			if (sName == "schema-attribute")
+				throw new cException("XPST0003"
+
+				);
+			else
+			if (sName == "schema-element")
+				throw new cException("XPST0003"
+
+				);
+		}
+
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+
+		return oTest;
+	}
+};
+
+// Public members
+cKindTest.prototype.test	= function (oNode, oContext) {
+	var fGetProperty	= oContext.DOMAdapter.getProperty,
+		nType	= oContext.DOMAdapter.isNode(oNode) ? fGetProperty(oNode, "nodeType") : 0,
+		sTarget;
+	switch (this.name) {
+		// Node type test
+		case "node":			return !!nType;
+		case "attribute":				if (nType != 2)	return false;	break;
+		case "document-node":	return nType == 9;
+		case "element":			return nType == 1;
+		case "processing-instruction":	if (nType != 7)	return false;	break;
+		case "comment":			return nType == 8;
+		case "text":			return nType == 3 || nType == 4;
+
+		// Schema tests
+		case "schema-attribute":
+			throw "KindTest '" + "schema-attribute" + "' not implemented";
+
+		case "schema-element":
+			throw "KindTest '" + "schema-element" + "' not implemented";
+	}
+
+	// Additional tests
+	if (nType == 2)
+		return fGetProperty(oNode, "prefix") != "xmlns" && fGetProperty(oNode, "localName") != "xmlns";
+	if (nType == 7) {
+		sTarget = fGetProperty(oNode, "target");
+		return this.args.length ? sTarget == this.args[0].value : sTarget != "xml";
+	}
+
+	return true;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNameTest(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cNameTest.prototype	= new cNodeTest;
+
+cNameTest.prototype.prefix			= null;
+cNameTest.prototype.localName		= null;
+cNameTest.prototype.namespaceURI	= null;
+
+// Static members
+var rNameTest	= /^(?:(?![0-9-])(\w[\w.-]*|\*)\:)?(?![0-9-])(\w[\w.-]*|\*)$/;
+function fNameTest_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch) {
+		if (aMatch[1] == '*' && aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cNameTest(aMatch[1] || null, aMatch[2], aMatch[1] ? aMatch[1] == '*' ? '*' : oStaticContext.getURIForPrefix(aMatch[1]) || null : oStaticContext.defaultElementNamespace);
+	}
+};
+
+// Public members
+cNameTest.prototype.test	= function (oNode, oContext) {
+	var fGetProperty	= oContext.DOMAdapter.getProperty,
+		nType	= fGetProperty(oNode, "nodeType");
+	if (nType == 1 || nType == 2) {
+		if (this.localName == '*')
+			return (nType == 1 || (fGetProperty(oNode, "prefix") != "xmlns" && fGetProperty(oNode, "localName") != "xmlns")) && (!this.prefix || fGetProperty(oNode, "namespaceURI") == this.namespaceURI);
+		if (this.localName == fGetProperty(oNode, "localName"))
+			return this.namespaceURI == '*' || (nType == 2 && !this.prefix && !fGetProperty(oNode, "prefix")) || fGetProperty(oNode, "namespaceURI") == this.namespaceURI;
+	}
+	//
+	return false;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cPrimaryExpr() {
+
+};
+
+// Static members
+function fPrimaryExpr_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fContextItemExpr_parse(oLexer, oStaticContext)
+			|| fParenthesizedExpr_parse(oLexer, oStaticContext)
+			|| fFunctionCall_parse(oLexer, oStaticContext)
+			|| fVarRef_parse(oLexer, oStaticContext)
+			|| fLiteral_parse(oLexer, oStaticContext);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cParenthesizedExpr(oExpr) {
+	this.expression	= oExpr;
+};
+
+// Static members
+function fParenthesizedExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == '(') {
+		oLexer.next();
+		// Check if not empty (allowed)
+		var oExpr	= null;
+		if (oLexer.peek() != ')')
+			oExpr	= fExpr_parse(oLexer, oStaticContext);
+
+		//
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+
+		oLexer.next();
+
+		//
+		return new cParenthesizedExpr(oExpr);
+	}
+};
+
+// Public members
+cParenthesizedExpr.prototype.evaluate	= function (oContext) {
+	return this.expression ? this.expression.evaluate(oContext) : [];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cContextItemExpr() {
+
+};
+
+// Static members
+function fContextItemExpr_parse (oLexer, oStaticContext) {
+	if (oLexer.peek() == '.') {
+		oLexer.next();
+		return new cContextItemExpr;
+	}
+};
+
+// Public members
+cContextItemExpr.prototype.evaluate	= function (oContext) {
+	if (oContext.item == null)
+		throw new cException("XPDY0002"
+
+		);
+	//
+	return [oContext.item];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cLiteral() {
+
+};
+
+cLiteral.prototype.value	= null;
+
+// Static members
+function fLiteral_parse (oLexer, oStaticContext) {
+	if (!oLexer.eof())
+		return fNumericLiteral_parse(oLexer, oStaticContext)
+			|| fStringLiteral_parse(oLexer, oStaticContext);
+};
+
+// Public members
+cLiteral.prototype.evaluate	= function (oContext) {
+	return [this.value];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cNumericLiteral(oValue) {
+	this.value	= oValue;
+};
+
+cNumericLiteral.prototype	= new cLiteral;
+
+// Integer | Decimal | Double
+var rNumericLiteral	= /^[+\-]?(?:(?:(\d+)(?:\.(\d*))?)|(?:\.(\d+)))(?:[eE]([+-])?(\d+))?$/;
+function fNumericLiteral_parse (oLexer, oStaticContext) {
+	var sValue	= oLexer.peek(),
+		vValue	= fNumericLiteral_parseValue(sValue);
+	if (vValue) {
+		oLexer.next();
+		return new cNumericLiteral(vValue);
+	}
+};
+
+function fNumericLiteral_parseValue(sValue) {
+	var aMatch	= sValue.match(rNumericLiteral);
+	if (aMatch) {
+		var cType	= cXSInteger;
+		if (aMatch[5])
+			cType	= cXSDouble;
+		else
+		if (aMatch[2] || aMatch[3])
+			cType	= cXSDecimal;
+		return new cType(+sValue);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cStringLiteral(oValue) {
+	this.value	= oValue;
+};
+
+cStringLiteral.prototype	= new cLiteral;
+
+var rStringLiteral	= /^'([^']*(?:''[^']*)*)'|"([^"]*(?:""[^"]*)*)"$/;
+function fStringLiteral_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rStringLiteral);
+	if (aMatch) {
+		oLexer.next();
+		return new cStringLiteral(new cXSString(aMatch[1] ? aMatch[1].replace("''", "'") : aMatch[2] ? aMatch[2].replace('""', '"') : ''));
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cFilterExpr(oPrimary) {
+	this.expression	= oPrimary;
+	this.predicates	= [];
+};
+
+cFilterExpr.prototype	= new cStepExpr;
+
+cFilterExpr.prototype.expression	= null;
+
+// Static members
+function fFilterExpr_parse (oLexer, oStaticContext) {
+	var oExpr;
+	if (oLexer.eof() ||!(oExpr = fPrimaryExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	var oFilterExpr	= new cFilterExpr(oExpr);
+	// Parse predicates
+	fStepExpr_parsePredicates(oLexer, oStaticContext, oFilterExpr);
+
+	// If no predicates found
+	if (oFilterExpr.predicates.length == 0)
+		return oFilterExpr.expression;
+
+	return oFilterExpr;
+};
+
+// Public members
+cFilterExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.expression.evaluate(oContext);
+	if (this.predicates.length && oSequence.length)
+		oSequence	= this.applyPredicates(oSequence, oContext);
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cVarRef(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cVarRef.prototype.prefix		= null;
+cVarRef.prototype.localName		= null;
+cVarRef.prototype.namespaceURI	= null;
+
+// Static members
+function fVarRef_parse (oLexer, oStaticContext) {
+	if (oLexer.peek().substr(0, 1) == '$') {
+		var aMatch	= oLexer.peek().substr(1).match(rNameTest);
+		if (aMatch) {
+			if (aMatch[1] == '*' || aMatch[2] == '*')
+				throw new cException("XPST0003"
+	
+				);
+
+			var oVarRef	= new cVarRef(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null);
+			oLexer.next();
+			return oVarRef;
+		}
+	}
+};
+
+// Public members
+cVarRef.prototype.evaluate	= function (oContext) {
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName;
+	if (oContext.scope.hasOwnProperty(sUri))
+		return [oContext.scope[sUri]];
+	//
+	throw new cException("XPST0008"
+
+	);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cFunctionCall(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+	this.args	= [];
+};
+
+cFunctionCall.prototype.prefix			= null;
+cFunctionCall.prototype.localName		= null;
+cFunctionCall.prototype.namespaceURI	= null;
+cFunctionCall.prototype.args	= null;
+
+// Static members
+function fFunctionCall_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch && oLexer.peek(1) == '(') {
+		// Reserved "functions"
+		if (!aMatch[1] && (aMatch[2] in hKindTest_names))
+			return fAxisStep_parse(oLexer, oStaticContext);
+		// Other functions
+		if (aMatch[1] == '*' || aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		var oFunctionCallExpr	= new cFunctionCall(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) || null : oStaticContext.defaultFunctionNamespace),
+			oExpr;
+		oLexer.next(2);
+		//
+		if (oLexer.peek() != ')') {
+			do {
+				if (oLexer.eof() ||!(oExpr = fExprSingle_parse(oLexer, oStaticContext)))
+					throw new cException("XPST0003"
+
+					);
+				//
+				oFunctionCallExpr.args.push(oExpr);
+			}
+			while (oLexer.peek() == ',' && oLexer.next());
+			//
+			if (oLexer.peek() != ')')
+				throw new cException("XPST0003"
+
+				);
+		}
+		oLexer.next();
+		return oFunctionCallExpr;
+	}
+};
+
+// Public members
+cFunctionCall.prototype.evaluate	= function (oContext) {
+	var aArguments	= [],
+		aParameters,
+		fFunction;
+
+	// Evaluate arguments
+	for (var nIndex = 0, nLength = this.args.length; nIndex < nLength; nIndex++)
+		aArguments.push(this.args[nIndex].evaluate(oContext));
+
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName;
+	// Call function
+	if (this.namespaceURI == sNS_XPF) {
+		if (fFunction = hStaticContext_functions[this.localName]) {
+			// Validate/Cast arguments
+			if (aParameters = hStaticContext_signatures[this.localName])
+				fFunctionCall_prepare(this.localName, aParameters, fFunction, aArguments, oContext);
+			//
+			var vResult	= fFunction.apply(oContext, aArguments);
+			//
+			return vResult == null ? [] : vResult instanceof cArray ? vResult : [vResult];
+		}
+		throw new cException("XPST0017"
+
+		);
+	}
+	else
+	if (this.namespaceURI == sNS_XSD) {
+		if ((fFunction = hStaticContext_dataTypes[this.localName]) && this.localName != "NOTATION" && this.localName != "anyAtomicType") {
+			//
+			fFunctionCall_prepare(this.localName, [[cXSAnyAtomicType, '?']], fFunction, aArguments, oContext);
+			//
+			return aArguments[0] === null ? [] : [fFunction.cast(aArguments[0])];
+		}
+		throw new cException("XPST0017"
+
+		);
+	}
+	else
+	if (fFunction = oContext.staticContext.getFunction(sUri)) {
+		//
+		var vResult	= fFunction.apply(oContext, aArguments);
+		//
+		return vResult == null ? [] : vResult instanceof cArray ? vResult : [vResult];
+	}
+	//
+	throw new cException("XPST0017"
+
+	);
+};
+
+var aFunctionCall_numbers	= ["first", "second", "third", "fourth", "fifth"];
+function fFunctionCall_prepare(sName, aParameters, fFunction, aArguments, oContext) {
+	var oArgument,
+		nArgumentsLength	= aArguments.length,
+		oParameter,
+		nParametersLength	= aParameters.length,
+		nParametersRequired	= 0;
+
+	// Determine amount of parameters required
+	while ((nParametersRequired < aParameters.length) && !aParameters[nParametersRequired][2])
+		nParametersRequired++;
+
+	// Validate arguments length
+	if (nArgumentsLength > nParametersLength)
+		throw new cException("XPST0017"
+
+		);
+	else
+	if (nArgumentsLength < nParametersRequired)
+		throw new cException("XPST0017"
+
+		);
+
+	for (var nIndex = 0; nIndex < nArgumentsLength; nIndex++) {
+		oParameter	= aParameters[nIndex];
+		oArgument	= aArguments[nIndex];
+		// Check sequence cardinality
+		fFunctionCall_assertSequenceCardinality(oContext, oArgument, oParameter[1]
+
+		);
+		// Check sequence items data types consistency
+		fFunctionCall_assertSequenceItemType(oContext, oArgument, oParameter[0]
+
+		);
+		if (oParameter[1] != '+' && oParameter[1] != '*')
+			aArguments[nIndex]	= oArgument.length ? oArgument[0] : null;
+	}
+};
+
+function fFunctionCall_assertSequenceItemType(oContext, oSequence, cItemType
+
+	) {
+	//
+	for (var nIndex = 0, nLength = oSequence.length, nNodeType, vItem; nIndex < nLength; nIndex++) {
+		vItem	= oSequence[nIndex];
+		// Node types
+		if (cItemType == cXTNode || cItemType.prototype instanceof cXTNode) {
+			// Check if is node
+			if (!oContext.DOMAdapter.isNode(vItem))
+				throw new cException("XPTY0004"
+
+				);
+
+			// Check node type
+			if (cItemType != cXTNode) {
+				nNodeType	= oContext.DOMAdapter.getProperty(vItem, "nodeType");
+				if ([null, cXTElement, cXTAttribute, cXTText, cXTText, null, null, cXTProcessingInstruction, cXTComment, cXTDocument, null, null, null][nNodeType] != cItemType)
+					throw new cException("XPTY0004"
+
+					);
+			}
+		}
+		else
+		// Atomic types
+		if (cItemType == cXSAnyAtomicType || cItemType.prototype instanceof cXSAnyAtomicType) {
+			// Atomize item
+			vItem	= fFunction_sequence_atomize([vItem], oContext)[0];
+			// Convert type if necessary
+			if (cItemType != cXSAnyAtomicType) {
+				// Cast item to expected type if it's type is xs:untypedAtomic
+				if (vItem instanceof cXSUntypedAtomic)
+					vItem	= cItemType.cast(vItem);
+				// Cast item to xs:string if it's type is xs:anyURI
+				else
+				if (cItemType == cXSString/* || cItemType.prototype instanceof cXSString*/) {
+					if (vItem instanceof cXSAnyURI)
+						vItem	= cXSString.cast(vItem);
+				}
+				else
+				if (cItemType == cXSDouble/* || cItemType.prototype instanceof cXSDouble*/) {
+					if (fXSAnyAtomicType_isNumeric(vItem))
+						vItem	= cItemType.cast(vItem);
+				}
+			}
+			// Check type
+			if (!(vItem instanceof cItemType))
+				throw new cException("XPTY0004"
+
+				);
+			// Write value back to sequence
+			oSequence[nIndex]	= vItem;
+		}
+	}
+};
+
+function fFunctionCall_assertSequenceCardinality(oContext, oSequence, sCardinality
+
+	) {
+	var nLength	= oSequence.length;
+	// Check cardinality
+	if (sCardinality == '?') {	// =0 or 1
+		if (nLength > 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+	else
+	if (sCardinality == '+') {	// =1+
+		if (nLength < 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+	else
+	if (sCardinality != '*') {	// =1 ('*' =0+)
+		if (nLength != 1)
+			throw new cException("XPTY0004"
+
+			);
+	}
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cIntersectExceptExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cIntersectExceptExpr.prototype.left		= null;
+cIntersectExceptExpr.prototype.items	= null;
+
+// Static members
+function fIntersectExceptExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOperator;
+	if (oLexer.eof() ||!(oExpr = fInstanceofExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!((sOperator = oLexer.peek()) == "intersect" || sOperator == "except"))
+		return oExpr;
+
+	// IntersectExcept expression
+	var oIntersectExceptExpr	= new cIntersectExceptExpr(oExpr);
+	while ((sOperator = oLexer.peek()) == "intersect" || sOperator == "except") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fInstanceofExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oIntersectExceptExpr.items.push([sOperator, oExpr]);
+	}
+	return oIntersectExceptExpr;
+};
+
+// Public members
+cIntersectExceptExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.left.evaluate(oContext);
+	for (var nIndex = 0, nLength = this.items.length, oItem; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators[(oItem = this.items[nIndex])[0]].call(oContext, oSequence, oItem[1].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cRangeExpr(oLeft, oRight) {
+	this.left	= oLeft;
+	this.right	= oRight;
+};
+
+cRangeExpr.prototype.left	= null;
+cRangeExpr.prototype.right	= null;
+
+// Static members
+function fRangeExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oRight;
+	if (oLexer.eof() ||!(oExpr = fAdditiveExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (oLexer.peek() != "to")
+		return oExpr;
+
+	// Range expression
+	oLexer.next();
+	if (oLexer.eof() ||!(oRight = fAdditiveExpr_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+	return new cRangeExpr(oExpr, oRight);
+};
+
+// Public members
+cRangeExpr.prototype.evaluate	= function (oContext) {
+	//
+	var oLeft	= this.left.evaluate(oContext);
+	if (!oLeft.length)
+		return [];
+	//
+
+
+	fFunctionCall_assertSequenceCardinality(oContext, oLeft, '?'
+
+	);
+	fFunctionCall_assertSequenceItemType(oContext, oLeft, cXSInteger
+
+	);
+
+	var oRight	= this.right.evaluate(oContext);
+	if (!oRight.length)
+		return [];
+
+
+
+	fFunctionCall_assertSequenceCardinality(oContext, oRight, '?'
+
+	);
+	fFunctionCall_assertSequenceItemType(oContext, oRight, cXSInteger
+
+	);
+
+	return hStaticContext_operators["to"].call(oContext, oLeft[0], oRight[0]);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cUnionExpr(oExpr) {
+	this.left	= oExpr;
+	this.items	= [];
+};
+
+cUnionExpr.prototype.left	= null;
+cUnionExpr.prototype.items	= null;
+
+// Static members
+function fUnionExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOperator;
+	if (oLexer.eof() ||!(oExpr = fIntersectExceptExpr_parse(oLexer, oStaticContext)))
+		return;
+	if (!((sOperator = oLexer.peek()) == '|' || sOperator == "union"))
+		return oExpr;
+
+	// Union expression
+	var oUnionExpr	= new cUnionExpr(oExpr);
+	while ((sOperator = oLexer.peek()) == '|' || sOperator == "union") {
+		oLexer.next();
+		if (oLexer.eof() ||!(oExpr = fIntersectExceptExpr_parse(oLexer, oStaticContext)))
+			throw new cException("XPST0003"
+
+			);
+		oUnionExpr.items.push(oExpr);
+	}
+	return oUnionExpr;
+};
+
+// Public members
+cUnionExpr.prototype.evaluate	= function (oContext) {
+	var oSequence	= this.left.evaluate(oContext);
+	for (var nIndex = 0, nLength = this.items.length; nIndex < nLength; nIndex++)
+		oSequence	= hStaticContext_operators["union"].call(oContext, oSequence, this.items[nIndex].evaluate(oContext));
+	return oSequence;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cInstanceofExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cInstanceofExpr.prototype.expression	= null;
+cInstanceofExpr.prototype.type			= null;
+
+function fInstanceofExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fTreatExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "instance" && oLexer.peek(1) == "of"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSequenceType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cInstanceofExpr(oExpr, oType);
+};
+
+cInstanceofExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+	// Validate empty-sequence()
+	if (!oItemType)
+		return [new cXSBoolean(!oSequence1.length)];
+	// Validate cardinality
+	if (!oSequence1.length)
+		return [new cXSBoolean(sOccurence == '?' || sOccurence == '*')];
+	if (oSequence1.length != 1)
+		if (!(sOccurence == '+' || sOccurence == '*'))
+			return [new cXSBoolean(false)];
+
+	// Validate type
+	if (!oItemType.test)	// item()
+		return [new cXSBoolean(true)];
+
+	var bValue	= true;
+	for (var nIndex = 0, nLength = oSequence1.length; (nIndex < nLength) && bValue; nIndex++)
+		bValue	= oItemType.test.test(oSequence1[nIndex], oContext);
+	//
+	return [new cXSBoolean(bValue)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cTreatExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cTreatExpr.prototype.expression	= null;
+cTreatExpr.prototype.type		= null;
+
+function fTreatExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fCastableExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "treat" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSequenceType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cTreatExpr(oExpr, oType);
+};
+
+cTreatExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+	// Validate empty-sequence()
+	if (!oItemType) {
+		if (oSequence1.length)
+			throw new cException("XPDY0050"
+
+			);
+		return oSequence1;
+	}
+
+	// Validate cardinality
+	if (!(sOccurence == '?' || sOccurence == '*'))
+		if (!oSequence1.length)
+			throw new cException("XPDY0050"
+
+			);
+
+	if (!(sOccurence == '+' || sOccurence == '*'))
+		if (oSequence1.length != 1)
+			throw new cException("XPDY0050"
+
+			);
+
+	// Validate type
+	if (!oItemType.test)	// item()
+		return oSequence1;
+
+	for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++)
+		if (!oItemType.test.test(oSequence1[nIndex], oContext))
+			throw new cException("XPDY0050"
+
+			);
+
+	//
+	return oSequence1;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cCastableExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cCastableExpr.prototype.expression	= null;
+cCastableExpr.prototype.type		= null;
+
+function fCastableExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fCastExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "castable" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSingleType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cCastableExpr(oExpr, oType);
+};
+
+cCastableExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext),
+		oItemType	= this.type.itemType,
+		sOccurence	= this.type.occurence;
+
+	if (oSequence1.length > 1)
+		return [new cXSBoolean(false)];
+	else
+	if (!oSequence1.length)
+		return [new cXSBoolean(sOccurence == '?')];
+
+	// Try casting
+	try {
+		oItemType.cast(fFunction_sequence_atomize(oSequence1, oContext)[0]);
+	}
+	catch (e) {
+		if (e.code == "XPST0051")
+			throw e;
+		if (e.code == "XPST0017")
+			throw new cException("XPST0080"
+
+			);
+		//
+		return [new cXSBoolean(false)];
+	}
+
+	return [new cXSBoolean(true)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cCastExpr(oExpr, oType) {
+	this.expression	= oExpr;
+	this.type		= oType;
+};
+
+cCastExpr.prototype.expression	= null;
+cCastExpr.prototype.type		= null;
+
+function fCastExpr_parse (oLexer, oStaticContext) {
+	var oExpr,
+		oType;
+	if (oLexer.eof() ||!(oExpr = fUnaryExpr_parse(oLexer, oStaticContext)))
+		return;
+
+	if (!(oLexer.peek() == "cast" && oLexer.peek(1) == "as"))
+		return oExpr;
+
+	oLexer.next(2);
+	if (oLexer.eof() ||!(oType = fSingleType_parse(oLexer, oStaticContext)))
+		throw new cException("XPST0003"
+
+		);
+
+	return new cCastExpr(oExpr, oType);
+};
+
+cCastExpr.prototype.evaluate	= function(oContext) {
+	var oSequence1	= this.expression.evaluate(oContext);
+	// Validate cardinality
+	fFunctionCall_assertSequenceCardinality(oContext, oSequence1, this.type.occurence
+
+	);
+	//
+	if (!oSequence1.length)
+		return [];
+	//
+	return [this.type.itemType.cast(fFunction_sequence_atomize(oSequence1, oContext)[0], oContext)];
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cAtomicType(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix			= sPrefix;
+	this.localName		= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cAtomicType.prototype.prefix		= null;
+cAtomicType.prototype.localName		= null;
+cAtomicType.prototype.namespaceURI	= null;
+
+function fAtomicType_parse (oLexer, oStaticContext) {
+	var aMatch	= oLexer.peek().match(rNameTest);
+	if (aMatch) {
+		if (aMatch[1] == '*' || aMatch[2] == '*')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cAtomicType(aMatch[1] || null, aMatch[2], aMatch[1] ? oStaticContext.getURIForPrefix(aMatch[1]) : null);
+	}
+};
+
+cAtomicType.prototype.test	= function(vItem, oContext) {
+	// Test
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName,
+		cType	= this.namespaceURI == sNS_XSD ? hStaticContext_dataTypes[this.localName] : oContext.staticContext.getDataType(sUri);
+	if (cType)
+		return vItem instanceof cType;
+	//
+	throw new cException("XPST0051"
+
+	);
+};
+
+cAtomicType.prototype.cast	= function(vItem, oContext) {
+	// Cast
+	var sUri	= (this.namespaceURI ? '{' + this.namespaceURI + '}' : '') + this.localName,
+		cType	= this.namespaceURI == sNS_XSD ? hStaticContext_dataTypes[this.localName] : oContext.staticContext.getDataType(sUri);
+	if (cType)
+		return cType.cast(vItem);
+	//
+	throw new cException("XPST0051"
+
+	);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cItemType(oTest) {
+	this.test	= oTest;
+};
+
+cItemType.prototype.test	= null;
+
+function fItemType_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+
+	var oExpr;
+	if (oLexer.peek() == "item" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cItemType;
+	}
+	// Note! Following step should have been before previous as per spec
+	if (oExpr = fKindTest_parse(oLexer, oStaticContext))
+		return new cItemType(oExpr);
+	if (oExpr = fAtomicType_parse(oLexer, oStaticContext))
+		return new cItemType(oExpr);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cSequenceType(oItemType, sOccurence) {
+	this.itemType	= oItemType	|| null;
+	this.occurence	= sOccurence|| null;
+};
+
+cSequenceType.prototype.itemType	= null;
+cSequenceType.prototype.occurence	= null;
+
+function fSequenceType_parse (oLexer, oStaticContext) {
+	if (oLexer.eof())
+		return;
+
+	if (oLexer.peek() == "empty-sequence" && oLexer.peek(1) == '(') {
+		oLexer.next(2);
+		if (oLexer.peek() != ')')
+			throw new cException("XPST0003"
+
+			);
+		oLexer.next();
+		return new cSequenceType;	// empty sequence
+	}
+
+	var oExpr,
+		sOccurence;
+	if (!oLexer.eof() && (oExpr = fItemType_parse(oLexer, oStaticContext))) {
+		sOccurence	= oLexer.peek();
+		if (sOccurence == '?' || sOccurence == '*' || sOccurence == '+')
+			oLexer.next();
+		else
+			sOccurence	= null;
+
+		return new cSequenceType(oExpr, sOccurence);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cSingleType(oItemType, sOccurence) {
+	this.itemType	= oItemType	|| null;
+	this.occurence	= sOccurence|| null;
+};
+
+cSingleType.prototype.itemType	= null;
+cSingleType.prototype.occurence	= null;
+
+function fSingleType_parse (oLexer, oStaticContext) {
+	var oExpr,
+		sOccurence;
+	if (!oLexer.eof() && (oExpr = fAtomicType_parse(oLexer, oStaticContext))) {
+		sOccurence	= oLexer.peek();
+		if (sOccurence == '?')
+			oLexer.next();
+		else
+			sOccurence	= null;
+
+		return new cSingleType(oExpr, sOccurence);
+	}
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyType() {
+
+};
+
+cXSAnyType.prototype.builtInKind	= cXSConstants.ANYTYPE_DT;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnySimpleType() {
+
+};
+
+cXSAnySimpleType.prototype	= new cXSAnyType;
+
+cXSAnySimpleType.prototype.builtInKind	= cXSConstants.ANYSIMPLETYPE_DT;
+cXSAnySimpleType.prototype.primitiveKind= null;
+
+cXSAnySimpleType.PRIMITIVE_ANYURI		= "anyURI";		//18;
+cXSAnySimpleType.PRIMITIVE_BASE64BINARY	= "base64Binary";	// 17;
+cXSAnySimpleType.PRIMITIVE_BOOLEAN		= "boolean";	// 3;
+cXSAnySimpleType.PRIMITIVE_DATE			= "date";		// 10;
+cXSAnySimpleType.PRIMITIVE_DATETIME		= "dateTime";	// 8;
+cXSAnySimpleType.PRIMITIVE_DECIMAL		= "decimal";	// 4;
+cXSAnySimpleType.PRIMITIVE_DOUBLE		= "double";		// 6;
+cXSAnySimpleType.PRIMITIVE_DURATION		= "duration";	// 7;
+cXSAnySimpleType.PRIMITIVE_FLOAT		= "float";		// 5;
+cXSAnySimpleType.PRIMITIVE_GDAY			= "gDay";		// 14;
+cXSAnySimpleType.PRIMITIVE_GMONTH		= "gMonth";		// 15;
+cXSAnySimpleType.PRIMITIVE_GMONTHDAY	= "gMonthDay";	// 13;
+cXSAnySimpleType.PRIMITIVE_GYEAR		= "gYear";		// 12;
+cXSAnySimpleType.PRIMITIVE_GYEARMONTH	= "gYearMonth";	// 11;
+cXSAnySimpleType.PRIMITIVE_HEXBINARY	= "hexBinary";	// 16;
+cXSAnySimpleType.PRIMITIVE_NOTATION		= "NOTATION";	// 20;
+cXSAnySimpleType.PRIMITIVE_QNAME		= "QName";		// 19;
+cXSAnySimpleType.PRIMITIVE_STRING		= "string";		// 2;
+cXSAnySimpleType.PRIMITIVE_TIME			= "time";		// 9;
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyAtomicType() {
+
+};
+
+cXSAnyAtomicType.prototype	= new cXSAnySimpleType;
+cXSAnyAtomicType.prototype.builtInKind	= cXSConstants.ANYATOMICTYPE_DT;
+
+cXSAnyAtomicType.cast	= function(vValue) {
+	throw new cException("XPST0017"
+
+	);	//  {http://www.w3.org/2001/XMLSchema}anyAtomicType
+};
+
+function fXSAnyAtomicType_isNumeric(vItem) {
+	return vItem instanceof cXSFloat || vItem instanceof cXSDouble || vItem instanceof cXSDecimal;
+};
+
+//
+fStaticContext_defineSystemDataType("anyAtomicType",	cXSAnyAtomicType);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSAnyURI(sScheme, sAuthority, sPath, sQuery, sFragment) {
+	this.scheme		= sScheme;
+	this.authority	= sAuthority;
+	this.path		= sPath;
+	this.query		= sQuery;
+	this.fragment	= sFragment;
+};
+
+cXSAnyURI.prototype	= new cXSAnyAtomicType;
+cXSAnyURI.prototype.builtInKind		= cXSConstants.ANYURI_DT;
+cXSAnyURI.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_ANYURI;
+
+cXSAnyURI.prototype.scheme		= null;
+cXSAnyURI.prototype.authority	= null;
+cXSAnyURI.prototype.path		= null;
+cXSAnyURI.prototype.query		= null;
+cXSAnyURI.prototype.fragment	= null;
+
+cXSAnyURI.prototype.toString	= function() {
+	return (this.scheme ? this.scheme + ':' : '')
+			+ (this.authority ? '/' + '/' + this.authority : '')
+			+ (this.path ? this.path : '')
+			+ (this.query ? '?' + this.query : '')
+			+ (this.fragment ? '#' + this.fragment : '');
+};
+
+var rXSAnyURI	= /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;	// http://tools.ietf.org/html/rfc3986
+cXSAnyURI.cast	= function(vValue) {
+	if (vValue instanceof cXSAnyURI)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch;
+		if (aMatch = fString_trim(vValue).match(rXSAnyURI))
+			return new cXSAnyURI(aMatch[2], aMatch[4], aMatch[5], aMatch[7], aMatch[9]);
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("anyURI",	cXSAnyURI);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSBase64Binary(sValue) {
+	this.value	= sValue;
+};
+
+cXSBase64Binary.prototype	= new cXSAnyAtomicType;
+cXSBase64Binary.prototype.builtInKind	= cXSConstants.BASE64BINARY_DT;
+cXSBase64Binary.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_BASE64BINARY;
+
+cXSBase64Binary.prototype.value	= null;
+
+cXSBase64Binary.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSBase64Binary.prototype.toString	= function() {
+	return this.value;
+};
+
+var rXSBase64Binary		= /^((([A-Za-z0-9+\/]\s*){4})*(([A-Za-z0-9+\/]\s*){3}[A-Za-z0-9+\/]|([A-Za-z0-9+\/]\s*){2}[AEIMQUYcgkosw048]\s*=|[A-Za-z0-9+\/]\s*[AQgw]\s*=\s*=))?$/;
+cXSBase64Binary.cast	= function(vValue) {
+	if (vValue instanceof cXSBase64Binary)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSBase64Binary);
+		if (aMatch)
+			return new cXSBase64Binary(aMatch[0]);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSHexBinary) {
+		var aMatch	= vValue.valueOf().match(/.{2}/g),
+			aValue	= [];
+		for (var nIndex = 0, nLength = aMatch.length; nIndex < nLength; nIndex++)
+			aValue.push(cString.fromCharCode(fWindow_parseInt(aMatch[nIndex], 16)));
+		return new cXSBase64Binary(fWindow_btoa(aValue.join('')));
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("base64Binary",	cXSBase64Binary);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSBoolean(bValue) {
+	this.value	= bValue;
+};
+
+cXSBoolean.prototype	= new cXSAnyAtomicType;
+cXSBoolean.prototype.builtInKind	= cXSConstants.BOOLEAN_DT;
+cXSBoolean.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_BOOLEAN;
+
+cXSBoolean.prototype.value	= null;
+
+cXSBoolean.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSBoolean.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSBoolean	= /^(0|1|true|false)$/;
+cXSBoolean.cast	= function(vValue) {
+	if (vValue instanceof cXSBoolean)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch;
+		if (aMatch = fString_trim(vValue).match(rXSBoolean))
+			return new cXSBoolean(aMatch[1] == '1' || aMatch[1] == "true");
+		throw new cException("FORG0001");
+	}
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSBoolean(vValue != 0);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("boolean",	cXSBoolean);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDate(nYear, nMonth, nDay, nTimezone, bNegative) {
+	this.year		= nYear;
+	this.month		= nMonth;
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+	this.negative	= bNegative;
+};
+
+cXSDate.prototype	= new cXSAnyAtomicType;
+cXSDate.prototype.builtInKind	= cXSConstants.DATE_DT;
+cXSDate.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DATE;
+
+cXSDate.prototype.year		= null;
+cXSDate.prototype.month		= null;
+cXSDate.prototype.day		= null;
+cXSDate.prototype.timezone	= null;
+cXSDate.prototype.negative	= null;
+
+cXSDate.prototype.toString	= function() {
+	return fXSDateTime_getDateComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSDate		= /^(-?)([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSDate.cast	= function(vValue) {
+	if (vValue instanceof cXSDate)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDate);
+		if (aMatch) {
+			var nYear	= +aMatch[2],
+				nMonth	= +aMatch[3],
+				nDay	= +aMatch[4];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(nYear, nMonth))
+				return new cXSDate( nYear,
+									nMonth,
+									nDay,
+									aMatch[5] ? aMatch[5] == 'Z' ? 0 : (aMatch[6] == '-' ? -1 : 1) * (aMatch[7] * 60 + aMatch[8] * 1) : null,
+									aMatch[1] == '-'
+				);
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDateTime)
+		return new cXSDate(vValue.year, vValue.month, vValue.day, vValue.timezone, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+var aXSDate_days	= [31,28,31,30,31,30,31,31,30,31,30,31];
+function fXSDate_getDaysForYearMonth(nYear, nMonth) {
+	return nMonth == 2 && (nYear % 400 == 0 || nYear % 100 != 0 && nYear % 4 == 0) ? 29 : aXSDate_days[nMonth - 1];
+};
+
+function fXSDate_normalize(oValue, bDay) {
+	// Adjust day for month/year
+	if (!bDay) {
+		var nDay	= fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+		if (oValue.day > nDay) {
+			while (oValue.day > nDay) {
+				oValue.month	+= 1;
+				if (oValue.month > 12) {
+					oValue.year		+= 1;
+					if (oValue.year == 0)
+						oValue.year	= 1;
+					oValue.month	= 1;
+				}
+				oValue.day	-= nDay;
+				nDay = fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+			}
+		}
+		else
+		if (oValue.day < 1) {
+			while (oValue.day < 1) {
+				oValue.month	-= 1;
+				if (oValue.month < 1) {
+					oValue.year		-= 1;
+					if (oValue.year == 0)
+						oValue.year	=-1;
+					oValue.month	= 12;
+				}
+				nDay = fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+				oValue.day	+= nDay;
+			}
+		}
+	}
+//?	else
+	// Adjust month
+	if (oValue.month > 12) {
+		oValue.year		+= ~~(oValue.month / 12);
+		if (oValue.year == 0)
+			oValue.year	= 1;
+		oValue.month	= oValue.month % 12;
+	}
+	else
+	if (oValue.month < 1) {
+		oValue.year		+= ~~(oValue.month / 12) - 1;
+		if (oValue.year == 0)
+			oValue.year	=-1;
+		oValue.month	= oValue.month % 12 + 12;
+	}
+
+	return oValue;
+};
+
+//
+fStaticContext_defineSystemDataType("date",	cXSDate);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDateTime(nYear, nMonth, nDay, nHours, nMinutes, nSeconds, nTimezone, bNegative) {
+	this.year	= nYear;
+	this.month	= nMonth;
+	this.day	= nDay;
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.timezone	= nTimezone;
+	this.negative	= bNegative;
+};
+
+cXSDateTime.prototype	= new cXSAnyAtomicType;
+cXSDateTime.prototype.builtInKind	= cXSConstants.DATETIME_DT;
+cXSDateTime.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DATETIME;
+
+cXSDateTime.prototype.year		= null;
+cXSDateTime.prototype.month		= null;
+cXSDateTime.prototype.day		= null;
+cXSDateTime.prototype.hours		= null;
+cXSDateTime.prototype.minutes	= null;
+cXSDateTime.prototype.seconds	= null;
+cXSDateTime.prototype.timezone	= null;
+cXSDateTime.prototype.negative	= null;
+
+cXSDateTime.prototype.toString	= function() {
+	return fXSDateTime_getDateComponent(this)
+			+ 'T'
+			+ fXSDateTime_getTimeComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSDateTime		= /^(-?)([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T(([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d+))?|(24:00:00)(?:\.(0+))?)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSDateTime.cast	= function(vValue) {
+	if (vValue instanceof cXSDateTime)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDateTime);
+		if (aMatch) {
+			var nYear	= +aMatch[2],
+				nMonth	= +aMatch[3],
+				nDay	= +aMatch[4],
+				bValue	= !!aMatch[10];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(nYear, nMonth))
+				return fXSDateTime_normalize(new cXSDateTime( nYear,
+										nMonth,
+										nDay,
+										bValue ? 24 : +aMatch[6],
+										bValue ? 0 : +aMatch[7],
+										cNumber((bValue ? 0 : aMatch[8]) + '.' + (bValue ? 0 : aMatch[9] || 0)),
+										aMatch[12] ? aMatch[12] == 'Z' ? 0 : (aMatch[13] == '-' ? -1 : 1) * (aMatch[14] * 60 + aMatch[15] * 1) : null,
+										aMatch[1] == '-'
+				));
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate)
+		return new cXSDateTime(vValue.year, vValue.month, vValue.day, 0, 0, 0, vValue.timezone, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDateTime_pad(vValue, nLength) {
+	var sValue	= cString(vValue);
+	if (arguments.length < 2)
+		nLength	= 2;
+	return (sValue.length < nLength + 1 ? new cArray(nLength + 1 - sValue.length).join('0') : '') + sValue;
+};
+
+function fXSDateTime_getTZComponent(oDateTime) {
+	var nTimezone	= oDateTime.timezone;
+	return nTimezone == null
+			? ''
+			: nTimezone
+				? (nTimezone > 0 ? '+' : '-')
+					+ fXSDateTime_pad(cMath.abs(~~(nTimezone / 60)))
+					+ ':'
+					+ fXSDateTime_pad(cMath.abs(nTimezone % 60))
+				: 'Z';
+};
+
+function fXSDateTime_getDateComponent(oDateTime) {
+	return (oDateTime.negative ? '-' : '')
+			+ fXSDateTime_pad(oDateTime.year, 4)
+			+ '-' + fXSDateTime_pad(oDateTime.month)
+			+ '-' + fXSDateTime_pad(oDateTime.day);
+};
+
+function fXSDateTime_getTimeComponent(oDateTime) {
+	var aValue	= cString(oDateTime.seconds).split('.');
+	return fXSDateTime_pad(oDateTime.hours)
+			+ ':' + fXSDateTime_pad(oDateTime.minutes)
+			+ ':' + fXSDateTime_pad(aValue[0])
+			+ (aValue.length > 1 ? '.' + aValue[1] : '');
+};
+
+function fXSDateTime_normalize(oValue) {
+	return fXSDate_normalize(fXSTime_normalize(oValue));
+};
+
+//
+fStaticContext_defineSystemDataType("dateTime",	cXSDateTime);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDecimal(nValue) {
+	this.value	= nValue;
+};
+
+cXSDecimal.prototype	= new cXSAnyAtomicType;
+cXSDecimal.prototype.builtInKind	= cXSConstants.DECIMAL_DT;
+cXSDecimal.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DECIMAL;
+
+cXSDecimal.prototype.value	= null;
+
+cXSDecimal.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSDecimal.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSDecimal	= /^[+\-]?((\d+(\.\d*)?)|(\.\d+))$/;
+cXSDecimal.cast	= function(vValue) {
+	if (vValue instanceof cXSDecimal)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDecimal);
+		if (aMatch)
+			return new cXSDecimal(+vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSDecimal(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue)) {
+		if (!fIsNaN(vValue) && fIsFinite(vValue))
+			return new cXSDecimal(+vValue);
+		throw new cException("FOCA0002"
+
+		);
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("decimal",	cXSDecimal);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDouble(nValue) {
+	this.value	= nValue;
+};
+
+cXSDouble.prototype	= new cXSAnyAtomicType;
+cXSDouble.prototype.builtInKind		= cXSConstants.DOUBLE_DT;
+cXSDouble.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DOUBLE;
+
+cXSDouble.prototype.value	= null;
+
+cXSDouble.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSDouble.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSDouble	= /^([+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][+\-]?\d+)?|(-?INF)|NaN)$/;
+cXSDouble.cast	= function(vValue) {
+	if (vValue instanceof cXSDouble)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDouble);
+		if (aMatch)
+			return new cXSDouble(aMatch[7] ? +aMatch[7].replace("INF", "Infinity") : +vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSDouble(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSDouble(vValue.value);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("double",	cXSDouble);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDuration(nYear, nMonth, nDay, nHours, nMinutes, nSeconds, bNegative) {
+	this.year	= nYear;
+	this.month	= nMonth;
+	this.day	= nDay;
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.negative	= bNegative;
+};
+
+cXSDuration.prototype	= new cXSAnyAtomicType;
+cXSDuration.prototype.builtInKind	= cXSConstants.DURATION_DT;
+cXSDuration.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_DURATION;
+
+cXSDuration.prototype.year		= null;
+cXSDuration.prototype.month		= null;
+cXSDuration.prototype.day		= null;
+cXSDuration.prototype.hours		= null;
+cXSDuration.prototype.minutes	= null;
+cXSDuration.prototype.seconds	= null;
+cXSDuration.prototype.negative	= null;
+
+cXSDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ ((fXSDuration_getYearMonthComponent(this) + fXSDuration_getDayTimeComponent(this)) || 'T0S');
+};
+
+var rXSDuration		= /^(-)?P(?:([0-9]+)Y)?(?:([0-9]+)M)?(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:((?:(?:[0-9]+(?:.[0-9]*)?)|(?:.[0-9]+)))S)?)?$/;
+cXSDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSDuration)
+		return vValue;
+	if (vValue instanceof cXSYearMonthDuration)
+		return new cXSDuration(vValue.year, vValue.month, 0, 0, 0, 0, vValue.negative);
+	if (vValue instanceof cXSDayTimeDuration)
+		return new cXSDuration(0, 0, vValue.day, vValue.hours, vValue.minutes, vValue.seconds, vValue.negative);
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDuration);
+		if (aMatch)
+			return fXSDuration_normalize(new cXSDuration(+aMatch[2] || 0, +aMatch[3] || 0, +aMatch[4] || 0, +aMatch[5] || 0, +aMatch[6] || 0, +aMatch[7] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDuration_getYearMonthComponent(oDuration) {
+	return (oDuration.year ? oDuration.year + 'Y' : '')
+			+ (oDuration.month ? oDuration.month + 'M' : '');
+};
+
+function fXSDuration_getDayTimeComponent(oDuration) {
+	return (oDuration.day ? oDuration.day + 'D' : '')
+			+ (oDuration.hours || oDuration.minutes || oDuration.seconds
+				? 'T'
+					+ (oDuration.hours ? oDuration.hours + 'H' : '')
+					+ (oDuration.minutes ? oDuration.minutes + 'M' : '')
+					+ (oDuration.seconds ? oDuration.seconds + 'S' : '')
+				: '');
+};
+
+function fXSDuration_normalize(oDuration) {
+	return fXSYearMonthDuration_normalize(fXSDayTimeDuration_normalize(oDuration));
+};
+
+//
+fStaticContext_defineSystemDataType("duration",	cXSDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSFloat(nValue) {
+	this.value	= nValue;
+};
+
+cXSFloat.prototype	= new cXSAnyAtomicType;
+cXSFloat.prototype.builtInKind		= cXSConstants.FLOAT_DT;
+cXSFloat.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_FLOAT;
+
+cXSFloat.prototype.value	= null;
+
+cXSFloat.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSFloat.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+var rXSFloat	= /^([+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][+\-]?\d+)?|(-?INF)|NaN)$/;
+cXSFloat.cast	= function(vValue) {
+	if (vValue instanceof cXSFloat)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSFloat);
+		if (aMatch)
+			return new cXSFloat(aMatch[7] ? +aMatch[7].replace("INF", "Infinity") : +vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSFloat(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue))
+		return new cXSFloat(vValue.value);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("float",	cXSFloat);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGDay(nDay, nTimezone) {
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+};
+
+cXSGDay.prototype	= new cXSAnyAtomicType;
+cXSGDay.prototype.builtInKind	= cXSConstants.GDAY_DT;
+cXSGDay.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GDAY;
+
+cXSGDay.prototype.day		= null;
+cXSGDay.prototype.timezone	= null;
+
+cXSGDay.prototype.toString	= function() {
+	return '-'
+			+ '-'
+			+ '-' + fXSDateTime_pad(this.day)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGDay		= /^---(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGDay.cast	= function(vValue) {
+	if (vValue instanceof cXSGDay)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGDay);
+		if (aMatch) {
+			var nDay	= +aMatch[1];
+			return new cXSGDay(	nDay,
+								aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGDay(vValue.day, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gDay",	cXSGDay);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGMonth(nMonth, nTimezone) {
+	this.month		= nMonth;
+	this.timezone	= nTimezone;
+};
+
+cXSGMonth.prototype	= new cXSAnyAtomicType;
+cXSGMonth.prototype.builtInKind		= cXSConstants.GMONTH_DT;
+cXSGMonth.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GMONTH;
+
+cXSGMonth.prototype.month		= null;
+cXSGMonth.prototype.timezone	= null;
+
+cXSGMonth.prototype.toString	= function() {
+	return '-'
+			+ '-' + fXSDateTime_pad(this.month)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGMonth	= /^--(0[1-9]|1[0-2])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGMonth.cast	= function(vValue) {
+	if (vValue instanceof cXSGMonth)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGMonth);
+		if (aMatch) {
+			var nMonth	= +aMatch[1];
+			return new cXSGMonth(	nMonth,
+									aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGMonth(vValue.month, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gMonth",	cXSGMonth);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGMonthDay(nMonth, nDay, nTimezone) {
+	this.month		= nMonth;
+	this.day		= nDay;
+	this.timezone	= nTimezone;
+};
+
+cXSGMonthDay.prototype	= new cXSAnyAtomicType;
+cXSGMonthDay.prototype.builtInKind		= cXSConstants.GMONTHDAY_DT;
+cXSGMonthDay.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GMONTHDAY;
+
+cXSGMonthDay.prototype.month	= null;
+cXSGMonthDay.prototype.day		= null;
+cXSGMonthDay.prototype.timezone	= null;
+
+cXSGMonthDay.prototype.toString	= function() {
+	return '-'
+			+ '-' + fXSDateTime_pad(this.month)
+			+ '-' + fXSDateTime_pad(this.day)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGMonthDay	= /^--(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGMonthDay.cast	= function(vValue) {
+	if (vValue instanceof cXSGMonthDay)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGMonthDay);
+		if (aMatch) {
+			var nMonth	= +aMatch[1],
+				nDay	= +aMatch[2];
+			if (nDay - 1 < fXSDate_getDaysForYearMonth(1976, nMonth))
+				return new cXSGMonthDay(	nMonth,
+											nDay,
+											aMatch[3] ? aMatch[3] == 'Z' ? 0 : (aMatch[4] == '-' ? -1 : 1) * (aMatch[5] * 60 + aMatch[6] * 1) : null
+				);
+			//
+			throw new cException("FORG0001"
+
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGMonthDay(vValue.month, vValue.day, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gMonthDay",	cXSGMonthDay);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGYear(nYear, nTimezone) {
+	this.year	= nYear;
+	this.timezone	= nTimezone;
+};
+
+cXSGYear.prototype	= new cXSAnyAtomicType;
+cXSGYear.prototype.builtInKind		= cXSConstants.GYEAR_DT;
+cXSGYear.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GYEAR;
+
+cXSGYear.prototype.year		= null;
+cXSGYear.prototype.timezone	= null;
+
+cXSGYear.prototype.toString	= function() {
+	return fXSDateTime_pad(this.year)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGYear		= /^-?([1-9]\d\d\d+|0\d\d\d)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGYear.cast	= function(vValue) {
+	if (vValue instanceof cXSGYear)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGYear);
+		if (aMatch) {
+			var nYear	= +aMatch[1];
+			return new cXSGYear(	nYear,
+									aMatch[2] ? aMatch[2] == 'Z' ? 0 : (aMatch[3] == '-' ? -1 : 1) * (aMatch[4] * 60 + aMatch[5] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGYear(vValue.year, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gYear",	cXSGYear);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSGYearMonth(nYear, nMonth, nTimezone) {
+	this.year		= nYear;
+	this.month		= nMonth;
+	this.timezone	= nTimezone;
+};
+
+cXSGYearMonth.prototype	= new cXSAnyAtomicType;
+cXSGYearMonth.prototype.builtInKind		= cXSConstants.GYEARMONTH_DT;
+cXSGYearMonth.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_GYEARMONTH;
+
+cXSGYearMonth.prototype.year	= null;
+cXSGYearMonth.prototype.month	= null;
+cXSGYearMonth.prototype.timezone= null;
+
+cXSGYearMonth.prototype.toString	= function() {
+	return fXSDateTime_pad(this.year)
+			+ '-' + fXSDateTime_pad(this.month)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSGYearMonth	= /^-?([1-9]\d\d\d+|0\d\d\d)-(0[1-9]|1[0-2])(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSGYearMonth.cast	= function(vValue) {
+	if (vValue instanceof cXSGYearMonth)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSGYearMonth);
+		if (aMatch) {
+			var nYear	= +aMatch[1],
+				nMonth	= +aMatch[2];
+			return new cXSGYearMonth(	nYear,
+										nMonth,
+										aMatch[3] ? aMatch[3] == 'Z' ? 0 : (aMatch[4] == '-' ? -1 : 1) * (aMatch[5] * 60 + aMatch[6] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDate || vValue instanceof cXSDateTime)
+		return new cXSGYearMonth(vValue.year, vValue.month, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("gYearMonth",	cXSGYearMonth);
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSHexBinary(sValue) {
+	this.value	= sValue;
+};
+
+cXSHexBinary.prototype	= new cXSAnyAtomicType;
+cXSHexBinary.prototype.builtInKind		= cXSConstants.HEXBINARY_DT;
+cXSHexBinary.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_HEXBINARY;
+
+cXSHexBinary.prototype.value	= null;
+
+cXSHexBinary.prototype.valueOf	= function() {
+	return this.value;
+};
+
+cXSHexBinary.prototype.toString	= function() {
+	return this.value;
+};
+
+var rXSHexBinary	= /^([0-9a-fA-F]{2})*$/;
+cXSHexBinary.cast	= function(vValue) {
+	if (vValue instanceof cXSHexBinary)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSHexBinary);
+		if (aMatch)
+			return new cXSHexBinary(aMatch[0].toUpperCase());
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBase64Binary) {
+		var sValue	= fWindow_atob(vValue.valueOf()),
+			aValue	= [];
+		for (var nIndex = 0, nLength = sValue.length, sLetter; nIndex < nLength; nIndex++) {
+			sLetter = sValue.charCodeAt(nIndex).toString(16);
+			aValue.push(new cArray(3 - sLetter.length).join('0') + sLetter);
+		}
+		return new cXSHexBinary(aValue.join(''));
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("hexBinary",	cXSHexBinary);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNOTATION() {
+
+};
+
+cXSNOTATION.prototype	= new cXSAnyAtomicType;
+cXSNOTATION.prototype.builtInKind	= cXSConstants.NOTATION_DT;
+cXSNOTATION.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_NOTATION;
+
+cXSNOTATION.cast	= function(vValue) {
+	throw new cException("XPST0017"
+
+	);	//  {http://www.w3.org/2001/XMLSchema}NOTATION
+};
+
+//
+fStaticContext_defineSystemDataType("NOTATION",	cXSNOTATION);
+
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSQName(sPrefix, sLocalName, sNameSpaceURI) {
+	this.prefix	= sPrefix;
+	this.localName	= sLocalName;
+	this.namespaceURI	= sNameSpaceURI;
+};
+
+cXSQName.prototype	= new cXSAnyAtomicType;
+cXSQName.prototype.builtInKind		= cXSConstants.QNAME_DT;
+cXSQName.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_QNAME;
+
+cXSQName.prototype.prefix	= null;
+cXSQName.prototype.localName	= null;
+cXSQName.prototype.namespaceURI	= null;
+
+cXSQName.prototype.toString	= function() {
+	return (this.prefix ? this.prefix + ':' : '') + this.localName;
+};
+
+var rXSQName	= /^(?:(?![0-9-])(\w[\w.-]*)\:)?(?![0-9-])(\w[\w.-]*)$/;
+cXSQName.cast	= function(vValue) {
+	if (vValue instanceof cXSQName)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSQName);
+		if (aMatch)
+			return new cXSQName(aMatch[1] || null, aMatch[2], null);
+		throw new cException("FORG0001");
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("QName",	cXSQName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSString(sValue) {
+	this.value	= sValue;
+};
+
+cXSString.prototype	= new cXSAnyAtomicType;
+
+cXSString.prototype.value	= null;
+cXSString.prototype.builtInKind		= cXSConstants.STRING_DT;
+cXSString.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_STRING;
+
+cXSString.prototype.valueOf		= function() {
+	return this.value;
+};
+
+cXSString.prototype.toString	= function() {
+	return this.value;
+};
+
+cXSString.cast	= function(vValue) {
+	return new cXSString(cString(vValue));
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("string",	cXSString);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSTime(nHours, nMinutes, nSeconds, nTimezone) {
+	this.hours	= nHours;
+	this.minutes	= nMinutes;
+	this.seconds	= nSeconds;
+	this.timezone	= nTimezone;
+};
+
+cXSTime.prototype	= new cXSAnyAtomicType;
+cXSTime.prototype.builtInKind	= cXSConstants.TIME_DT;
+cXSTime.prototype.primitiveKind	= cXSAnySimpleType.PRIMITIVE_TIME;
+
+cXSTime.prototype.hours		= null;
+cXSTime.prototype.minutes	= null;
+cXSTime.prototype.seconds	= null;
+cXSTime.prototype.timezone		= null;
+
+cXSTime.prototype.toString	= function() {
+	return fXSDateTime_getTimeComponent(this)
+			+ fXSDateTime_getTZComponent(this);
+};
+
+var rXSTime		= /^(([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d+))?|(24:00:00)(?:\.(0+))?)(Z|([+\-])(0\d|1[0-4]):([0-5]\d))?$/;
+cXSTime.cast	= function(vValue) {
+	if (vValue instanceof cXSTime)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSTime);
+		if (aMatch) {
+			var bValue	= !!aMatch[6];
+			return new cXSTime(bValue ? 0 : +aMatch[2],
+								bValue ? 0 : +aMatch[3],
+								cNumber((bValue ? 0 : aMatch[4]) + '.' + (bValue ? 0 : aMatch[5] || 0)),
+								aMatch[8] ? aMatch[8] == 'Z' ? 0 : (aMatch[9] == '-' ? -1 : 1) * (aMatch[10] * 60 + aMatch[11] * 1) : null
+			);
+		}
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDateTime)
+		return new cXSTime(vValue.hours, vValue.minutes, vValue.seconds, vValue.timezone);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+function fXSTime_normalize(oValue) {
+	//
+	if (oValue.seconds >= 60 || oValue.seconds < 0) {
+		oValue.minutes	+= ~~(oValue.seconds / 60) - (oValue.seconds < 0 && oValue.seconds % 60 ? 1 : 0);
+		oValue.seconds	= oValue.seconds % 60 + (oValue.seconds < 0 && oValue.seconds % 60 ? 60 : 0);
+	}
+	//
+	if (oValue.minutes >= 60 || oValue.minutes < 0) {
+		oValue.hours	+= ~~(oValue.minutes / 60) - (oValue.minutes < 0 && oValue.minutes % 60 ? 1 : 0);
+		oValue.minutes	= oValue.minutes % 60 + (oValue.minutes < 0 && oValue.minutes % 60 ? 60 : 0);
+	}
+	//
+	if (oValue.hours >= 24 || oValue.hours < 0) {
+		if (oValue instanceof cXSDateTime)
+			oValue.day		+= ~~(oValue.hours / 24) - (oValue.hours < 0 && oValue.hours % 24 ? 1 : 0);
+		oValue.hours	= oValue.hours % 24 + (oValue.hours < 0 && oValue.hours % 24 ? 24 : 0);
+	}
+	//
+	return oValue;
+};
+
+//
+fStaticContext_defineSystemDataType("time",	cXSTime);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUntypedAtomic(sValue) {
+	this.value	= sValue;
+};
+
+cXSUntypedAtomic.prototype	= new cXSAnyAtomicType;
+cXSUntypedAtomic.prototype.builtInKind	= cXSConstants.XT_UNTYPEDATOMIC_DT;
+
+cXSUntypedAtomic.prototype.toString	= function() {
+	return cString(this.value);
+};
+
+cXSUntypedAtomic.cast	= function(vValue) {
+	if (vValue instanceof cXSUntypedAtomic)
+		return vValue;
+
+	return new cXSUntypedAtomic(cString(vValue));
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("untypedAtomic",	cXSUntypedAtomic);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSYearMonthDuration(nYear, nMonth, bNegative) {
+	cXSDuration.call(this, nYear, nMonth, 0, 0, 0, 0, bNegative);
+};
+
+cXSYearMonthDuration.prototype	= new cXSDuration;
+cXSYearMonthDuration.prototype.builtInKind	= cXSConstants.XT_YEARMONTHDURATION_DT;
+
+cXSYearMonthDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ (fXSDuration_getYearMonthComponent(this) || '0M');
+};
+
+var rXSYearMonthDuration	= /^(-)?P(?:([0-9]+)Y)?(?:([0-9]+)M)?$/;
+cXSYearMonthDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSYearMonthDuration)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSYearMonthDuration);
+		if (aMatch)
+			return fXSYearMonthDuration_normalize(new cXSYearMonthDuration(+aMatch[2] || 0, +aMatch[3] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSDayTimeDuration)
+		return new cXSYearMonthDuration(0, 0);
+	if (vValue instanceof cXSDuration)
+		return new cXSYearMonthDuration(vValue.year, vValue.month, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+function fXSYearMonthDuration_normalize(oDuration) {
+	if (oDuration.month >= 12) {
+		oDuration.year	+= ~~(oDuration.month / 12);
+		oDuration.month	%= 12;
+	}
+	return oDuration;
+};
+
+//
+fStaticContext_defineSystemDataType("yearMonthDuration",	cXSYearMonthDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSDayTimeDuration(nDay, nHours, nMinutes, nSeconds, bNegative) {
+	cXSDuration.call(this, 0, 0, nDay, nHours, nMinutes, nSeconds, bNegative);
+};
+
+cXSDayTimeDuration.prototype	= new cXSDuration;
+cXSDayTimeDuration.prototype.builtInKind	= cXSConstants.DAYTIMEDURATION_DT;
+
+cXSDayTimeDuration.prototype.toString	= function() {
+	return (this.negative ? '-' : '') + 'P'
+			+ (fXSDuration_getDayTimeComponent(this) || 'T0S');
+};
+
+var rXSDayTimeDuration	= /^(-)?P(?:([0-9]+)D)?(?:T(?:([0-9]+)H)?(?:([0-9]+)M)?(?:((?:(?:[0-9]+(?:.[0-9]*)?)|(?:.[0-9]+)))S)?)?$/;
+cXSDayTimeDuration.cast	= function(vValue) {
+	if (vValue instanceof cXSDayTimeDuration)
+		return vValue;
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSDayTimeDuration);
+		if (aMatch)
+			return fXSDayTimeDuration_normalize(new cXSDayTimeDuration(+aMatch[2] || 0, +aMatch[3] || 0, +aMatch[4] || 0, +aMatch[5] || 0, aMatch[1] == '-'));
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSYearMonthDuration)
+		return new cXSDayTimeDuration(0, 0, 0, 0);
+	if (vValue instanceof cXSDuration)
+		return new cXSDayTimeDuration(vValue.day, vValue.hours, vValue.minutes, vValue.seconds, vValue.negative);
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+// Utilities
+function fXSDayTimeDuration_normalize(oDuration) {
+	if (oDuration.seconds >= 60) {
+		oDuration.minutes	+= ~~(oDuration.seconds / 60);
+		oDuration.seconds	%= 60;
+	}
+	if (oDuration.minutes >= 60) {
+		oDuration.hours		+= ~~(oDuration.minutes / 60);
+		oDuration.minutes	%= 60;
+	}
+	if (oDuration.hours >= 24) {
+		oDuration.day		+= ~~(oDuration.hours / 24);
+		oDuration.hours		%= 24;
+	}
+	return oDuration;
+};
+
+//
+fStaticContext_defineSystemDataType("dayTimeDuration",	cXSDayTimeDuration);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSInteger.prototype	= new cXSDecimal;
+cXSInteger.prototype.builtInKind	= cXSConstants.INTEGER_DT;
+
+var rXSInteger	= /^[-+]?[0-9]+$/;
+cXSInteger.cast	= function(vValue) {
+	if (vValue instanceof cXSInteger)
+		return new cXSInteger(vValue.value);
+	if (vValue instanceof cXSString || vValue instanceof cXSUntypedAtomic) {
+		var aMatch	= fString_trim(vValue).match(rXSInteger);
+		if (aMatch)
+			return new cXSInteger(+vValue);
+		throw new cException("FORG0001");
+	}
+	if (vValue instanceof cXSBoolean)
+		return new cXSInteger(vValue * 1);
+	if (fXSAnyAtomicType_isNumeric(vValue)) {
+		if (!fIsNaN(vValue) && fIsFinite(vValue))
+			return new cXSInteger(+vValue);
+		throw new cException("FOCA0002"
+
+		);
+	}
+	//
+	throw new cException("XPTY0004"
+
+	);
+};
+
+//
+fStaticContext_defineSystemDataType("integer",	cXSInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNonPositiveInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNonPositiveInteger.prototype	= new cXSInteger;
+cXSNonPositiveInteger.prototype.builtInKind	= cXSConstants.NONPOSITIVEINTEGER_DT;
+
+cXSNonPositiveInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 0)
+		return new cXSNonPositiveInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("nonPositiveInteger",	cXSNonPositiveInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNegativeInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNegativeInteger.prototype	= new cXSNonPositiveInteger;
+cXSNegativeInteger.prototype.builtInKind	= cXSConstants.NEGATIVEINTEGER_DT;
+
+cXSNegativeInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= -1)
+		return new cXSNegativeInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("negativeInteger",	cXSNegativeInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSLong(nValue) {
+	this.value	= nValue;
+};
+
+cXSLong.prototype	= new cXSInteger;
+cXSLong.prototype.builtInKind	= cXSConstants.LONG_DT;
+
+cXSLong.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 9223372036854775807 && oValue.value >= -9223372036854775808)
+		return new cXSLong(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("long",	cXSLong);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSInt(nValue) {
+	this.value	= nValue;
+};
+
+cXSInt.prototype	= new cXSLong;
+cXSInt.prototype.builtInKind	= cXSConstants.INT_DT;
+
+cXSInt.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 2147483647 && oValue.value >= -2147483648)
+		return new cXSInt(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("int",	cXSInt);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSShort(nValue) {
+	this.value	= nValue;
+};
+
+cXSShort.prototype	= new cXSInt;
+cXSShort.prototype.builtInKind	= cXSConstants.SHORT_DT;
+
+cXSShort.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 32767 && oValue.value >= -32768)
+		return new cXSShort(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("short",	cXSShort);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSByte(nValue) {
+	this.value	= nValue;
+};
+
+cXSByte.prototype	= new cXSShort;
+cXSByte.prototype.builtInKind	= cXSConstants.BYTE_DT;
+
+cXSByte.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value <= 127 && oValue.value >= -128)
+		return new cXSByte(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("byte",	cXSByte);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNonNegativeInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSNonNegativeInteger.prototype	= new cXSInteger;
+cXSNonNegativeInteger.prototype.builtInKind	= cXSConstants.NONNEGATIVEINTEGER_DT;
+
+cXSNonNegativeInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 0)
+		return new cXSNonNegativeInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("nonNegativeInteger",	cXSNonNegativeInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSPositiveInteger(nValue) {
+	this.value	= nValue;
+};
+
+cXSPositiveInteger.prototype	= new cXSNonNegativeInteger;
+cXSPositiveInteger.prototype.builtInKind	= cXSConstants.POSITIVEINTEGER_DT;
+
+cXSPositiveInteger.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1)
+		return new cXSPositiveInteger(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("positiveInteger",	cXSPositiveInteger);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedLong(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedLong.prototype	= new cXSNonNegativeInteger;
+cXSUnsignedLong.prototype.builtInKind	= cXSConstants.UNSIGNEDLONG_DT;
+
+cXSUnsignedLong.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 18446744073709551615)
+		return new cXSUnsignedLong(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedLong",	cXSUnsignedLong);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedInt(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedInt.prototype	= new cXSNonNegativeInteger;
+cXSUnsignedInt.prototype.builtInKind	= cXSConstants.UNSIGNEDINT_DT;
+
+cXSUnsignedInt.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 4294967295)
+		return new cXSUnsignedInt(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedInt",	cXSUnsignedInt);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedShort(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedShort.prototype	= new cXSUnsignedInt;
+cXSUnsignedShort.prototype.builtInKind	= cXSConstants.UNSIGNEDSHORT_DT;
+
+cXSUnsignedShort.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 65535)
+		return new cXSUnsignedShort(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedShort",	cXSUnsignedShort);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSUnsignedByte(nValue) {
+	this.value	= nValue;
+};
+
+cXSUnsignedByte.prototype	= new cXSUnsignedShort;
+cXSUnsignedByte.prototype.builtInKind	= cXSConstants.UNSIGNEDBYTE_DT;
+
+cXSUnsignedByte.cast	= function(vValue) {
+	var oValue;
+	try {
+		oValue	= cXSInteger.cast(vValue);
+	}
+	catch (oError) {
+		throw oError;
+	}
+	// facet validation
+	if (oValue.value >= 1 && oValue.value <= 255)
+		return new cXSUnsignedByte(oValue.value);
+	//
+	throw new cException("FORG0001");
+};
+
+//
+fStaticContext_defineSystemDataType("unsignedByte",	cXSUnsignedByte);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNormalizedString(sValue) {
+	this.value	= sValue;
+};
+
+cXSNormalizedString.prototype	= new cXSString;
+cXSNormalizedString.prototype.builtInKind	= cXSConstants.NORMALIZEDSTRING_DT;
+
+cXSNormalizedString.cast	= function(vValue) {
+	return new cXSNormalizedString(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("normalizedString",	cXSNormalizedString);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSToken(sValue) {
+	this.value	= sValue;
+};
+
+cXSToken.prototype	= new cXSNormalizedString;
+cXSToken.prototype.builtInKind	= cXSConstants.TOKEN_DT;
+
+cXSToken.cast	= function(vValue) {
+	return new cXSToken(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("token",	cXSToken);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSName(sValue) {
+	this.value	= sValue;
+};
+
+cXSName.prototype	= new cXSToken;
+cXSName.prototype.builtInKind	= cXSConstants.NAME_DT;
+
+cXSName.cast	= function(vValue) {
+	return new cXSName(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("Name",	cXSName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNCName(sValue) {
+	this.value	= sValue;
+};
+
+cXSNCName.prototype	= new cXSName;
+cXSNCName.prototype.builtInKind	= cXSConstants.NCNAME_DT;
+
+cXSNCName.cast	= function(vValue) {
+	return new cXSNCName(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("NCName",	cXSNCName);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSENTITY(sValue) {
+	this.value	= sValue;
+};
+
+cXSENTITY.prototype	= new cXSNCName;
+cXSENTITY.prototype.builtInKind	= cXSConstants.ENTITY_DT;
+
+cXSENTITY.cast	= function(vValue) {
+	return new cXSENTITY(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("ENTITY",	cXSENTITY);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSID(sValue) {
+	this.value	= sValue;
+};
+
+cXSID.prototype	= new cXSNCName;
+cXSID.prototype.builtInKind	= cXSConstants.ID_DT;
+
+cXSID.cast	= function(vValue) {
+	return new cXSID(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("ID",	cXSID);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSIDREF(sValue) {
+	this.value	= sValue;
+};
+
+cXSIDREF.prototype	= new cXSNCName;
+cXSIDREF.prototype.builtInKind	= cXSConstants.IDREF_DT;
+
+cXSIDREF.cast	= function(vValue) {
+	return new cXSIDREF(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("IDREF",	cXSIDREF);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSLanguage(sValue) {
+	this.value	= sValue;
+};
+
+cXSLanguage.prototype	= new cXSToken;
+cXSLanguage.prototype.builtInKind	= cXSConstants.LANGUAGE_DT;
+
+cXSLanguage.cast	= function(vValue) {
+	return new cXSLanguage(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("language",	cXSLanguage);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXSNMTOKEN(sValue) {
+	this.value	= sValue;
+};
+
+cXSNMTOKEN.prototype	= new cXSToken;
+cXSNMTOKEN.prototype.builtInKind	= cXSConstants.NMTOKEN_DT;
+
+cXSNMTOKEN.cast	= function(vValue) {
+	return new cXSNMTOKEN(cString(vValue));
+};
+
+//
+fStaticContext_defineSystemDataType("NMTOKEN",	cXSNMTOKEN);
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTItem() {
+
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTNode() {
+
+};
+
+cXTNode.prototype	= new cXTItem;
+
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTAttribute() {
+
+};
+
+cXTAttribute.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTComment() {
+
+};
+
+cXTComment.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTDocument() {
+
+};
+
+cXTDocument.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTElement() {
+
+};
+
+cXTElement.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTProcessingInstruction() {
+
+};
+
+cXTProcessingInstruction.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+function cXTText() {
+
+};
+
+cXTText.prototype	= new cXTNode;
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	12.1 Comparisons of base64Binary and hexBinary Values
+		op:hexBinary-equal
+		op:base64Binary-equal
+*/
+hStaticContext_operators["hexBinary-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+hStaticContext_operators["base64Binary-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	9.2 Operators on Boolean Values
+		op:boolean-equal
+		op:boolean-less-than
+		op:boolean-greater-than
+*/
+
+// 9.2 Operators on Boolean Values
+// op:boolean-equal($value1 as xs:boolean, $value2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+// op:boolean-less-than($arg1 as xs:boolean, $arg2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() < oRight.valueOf());
+};
+
+// op:boolean-greater-than($arg1 as xs:boolean, $arg2 as xs:boolean) as xs:boolean
+hStaticContext_operators["boolean-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() > oRight.valueOf());
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	10.4 Comparison Operators on Duration, Date and Time Values
+		op:yearMonthDuration-less-than
+		op:yearMonthDuration-greater-than
+		op:dayTimeDuration-less-than
+		op:dayTimeDuration-greater-than
+		op:duration-equal
+		op:dateTime-equal
+		op:dateTime-less-than
+		op:dateTime-greater-than
+		op:date-equal
+		op:date-less-than
+		op:date-greater-than
+		op:time-equal
+		op:time-less-than
+		op:time-greater-than
+		op:gYearMonth-equal
+		op:gYear-equal
+		op:gMonthDay-equal
+		op:gMonth-equal
+		op:gDay-equal
+
+	10.6 Arithmetic Operators on Durations
+		op:add-yearMonthDurations
+		op:subtract-yearMonthDurations
+		op:multiply-yearMonthDuration
+		op:divide-yearMonthDuration
+		op:divide-yearMonthDuration-by-yearMonthDuration
+		op:add-dayTimeDurations
+		op:subtract-dayTimeDurations
+		op:multiply-dayTimeDuration
+		op:divide-dayTimeDuration
+		op:divide-dayTimeDuration-by-dayTimeDuration
+
+
+	10.8 Arithmetic Operators on Durations, Dates and Times
+		op:subtract-dateTimes
+		op:subtract-dates
+		op:subtract-times
+		op:add-yearMonthDuration-to-dateTime
+		op:add-dayTimeDuration-to-dateTime
+		op:subtract-yearMonthDuration-from-dateTime
+		op:subtract-dayTimeDuration-from-dateTime
+		op:add-yearMonthDuration-to-date
+		op:add-dayTimeDuration-to-date
+		op:subtract-yearMonthDuration-from-date
+		op:subtract-dayTimeDuration-from-date
+		op:add-dayTimeDuration-to-time
+		op:subtract-dayTimeDuration-from-time
+
+*/
+
+// 10.4 Comparison Operators on Duration, Date and Time Values
+// op:yearMonthDuration-less-than($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:boolean
+hStaticContext_operators["yearMonthDuration-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_yearMonthDuration_toMonths(oLeft) < fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:yearMonthDuration-greater-than($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:boolean
+hStaticContext_operators["yearMonthDuration-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_yearMonthDuration_toMonths(oLeft) > fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:dayTimeDuration-less-than($arg1 as dayTimeDuration, $arg2 as dayTimeDuration) as xs:boolean
+hStaticContext_operators["dayTimeDuration-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_dayTimeDuration_toSeconds(oLeft) < fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:dayTimeDuration-greater-than($arg1 as dayTimeDuration, $arg2 as dayTimeDuration) as xs:boolean
+hStaticContext_operators["dayTimeDuration-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(fOperator_dayTimeDuration_toSeconds(oLeft) > fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:duration-equal($arg1 as xs:duration, $arg2 as xs:duration) as xs:boolean
+hStaticContext_operators["duration-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.negative == oRight.negative
+			&& fOperator_yearMonthDuration_toMonths(oLeft) == fOperator_yearMonthDuration_toMonths(oRight)
+			&& fOperator_dayTimeDuration_toSeconds(oLeft) == fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:dateTime-equal($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'eq');
+};
+
+// op:dateTime-less-than($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'lt');
+};
+
+//op:dateTime-greater-than($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:boolean
+hStaticContext_operators["dateTime-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(oLeft, oRight, 'gt');
+};
+
+// op:date-equal($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'eq');
+};
+
+// op:date-less-than($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'lt');
+};
+
+// op:date-greater-than($arg1 as xs:date, $arg2 as xs:date) as xs:boolean
+hStaticContext_operators["date-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareDates(oLeft, oRight, 'gt');
+};
+
+// op:time-equal($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'eq');
+};
+
+// op:time-less-than($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-less-than"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'lt');
+};
+
+// op:time-greater-than($arg1 as xs:time, $arg2 as xs:time) as xs:boolean
+hStaticContext_operators["time-greater-than"]	= function(oLeft, oRight) {
+	return fOperator_compareTimes(oLeft, oRight, 'gt');
+};
+
+// op:gYearMonth-equal($arg1 as xs:gYearMonth, $arg2 as xs:gYearMonth) as xs:boolean
+hStaticContext_operators["gYearMonth-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(oLeft.year, oLeft.month, fXSDate_getDaysForYearMonth(oLeft.year, oLeft.month), 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(oRight.year, oRight.month, fXSDate_getDaysForYearMonth(oRight.year, oRight.month), 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gYear-equal($arg1 as xs:gYear, $arg2 as xs:gYear) as xs:boolean
+hStaticContext_operators["gYear-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(oLeft.year, 1, 1, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(oRight.year, 1, 1, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gMonthDay-equal($arg1 as xs:gMonthDay, $arg2 as xs:gMonthDay) as xs:boolean
+hStaticContext_operators["gMonthDay-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, oLeft.month, oLeft.day, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, oRight.month, oRight.day, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gMonth-equal($arg1 as xs:gMonth, $arg2 as xs:gMonth) as xs:boolean
+hStaticContext_operators["gMonth-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, oLeft.month, fXSDate_getDaysForYearMonth(1972, oRight.month), 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, oRight.month, fXSDate_getDaysForYearMonth(1972, oRight.month), 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// op:gDay-equal($arg1 as xs:gDay, $arg2 as xs:gDay) as xs:boolean
+hStaticContext_operators["gDay-equal"]	= function(oLeft, oRight) {
+	return fOperator_compareDateTimes(
+			new cXSDateTime(1972, 12, oLeft.day, 0, 0, 0, oLeft.timezone == null ? this.timezone : oLeft.timezone),
+			new cXSDateTime(1972, 12, oRight.day, 0, 0, 0, oRight.timezone == null ? this.timezone : oRight.timezone),
+			'eq'
+	);
+};
+
+// 10.6 Arithmetic Operators on Durations
+// op:add-yearMonthDurations($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:yearMonthDuration
+hStaticContext_operators["add-yearMonthDurations"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) + fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:subtract-yearMonthDurations($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:yearMonthDuration
+hStaticContext_operators["subtract-yearMonthDurations"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) - fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:multiply-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:double) as xs:yearMonthDuration
+hStaticContext_operators["multiply-yearMonthDuration"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) * oRight);
+};
+
+// op:divide-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:double) as xs:yearMonthDuration
+hStaticContext_operators["divide-yearMonthDuration"]	= function(oLeft, oRight) {
+	return fOperator_yearMonthDuration_fromMonths(fOperator_yearMonthDuration_toMonths(oLeft) / oRight);
+};
+
+// op:divide-yearMonthDuration-by-yearMonthDuration($arg1 as xs:yearMonthDuration, $arg2 as xs:yearMonthDuration) as xs:decimal
+hStaticContext_operators["divide-yearMonthDuration-by-yearMonthDuration"]	= function(oLeft, oRight) {
+	return new cXSDecimal(fOperator_yearMonthDuration_toMonths(oLeft) / fOperator_yearMonthDuration_toMonths(oRight));
+};
+
+// op:add-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:dayTimeDuration
+hStaticContext_operators["add-dayTimeDurations"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) + fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:subtract-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dayTimeDurations"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) - fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// op:multiply-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:double) as xs:dayTimeDuration
+hStaticContext_operators["multiply-dayTimeDuration"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) * oRight);
+};
+
+// op:divide-dayTimeDurations($arg1 as xs:dayTimeDuration, $arg2 as xs:double) as xs:dayTimeDuration
+hStaticContext_operators["divide-dayTimeDuration"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dayTimeDuration_toSeconds(oLeft) / oRight);
+};
+
+// op:divide-dayTimeDuration-by-dayTimeDuration($arg1 as xs:dayTimeDuration, $arg2 as xs:dayTimeDuration) as xs:decimal
+hStaticContext_operators["divide-dayTimeDuration-by-dayTimeDuration"]	= function(oLeft, oRight) {
+	return new cXSDecimal(fOperator_dayTimeDuration_toSeconds(oLeft) / fOperator_dayTimeDuration_toSeconds(oRight));
+};
+
+// 10.8 Arithmetic Operators on Durations, Dates and Times
+// op:subtract-dateTimes($arg1 as xs:dateTime, $arg2 as xs:dateTime) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dateTimes"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dateTime_toSeconds(oLeft) - fOperator_dateTime_toSeconds(oRight));
+};
+
+// op:subtract-dates($arg1 as xs:date, $arg2 as xs:date) as xs:dayTimeDuration
+hStaticContext_operators["subtract-dates"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_dateTime_toSeconds(oLeft) - fOperator_dateTime_toSeconds(oRight));
+};
+
+// op:subtract-times($arg1 as xs:time, $arg2 as xs:time) as xs:dayTimeDuration
+hStaticContext_operators["subtract-times"]	= function(oLeft, oRight) {
+	return fOperator_dayTimeDuration_fromSeconds(fOperator_time_toSeconds(oLeft) - fOperator_time_toSeconds(oRight));
+};
+
+// op:add-yearMonthDuration-to-dateTime($arg1 as xs:dateTime, $arg2 as xs:yearMonthDuration) as xs:dateTime
+hStaticContext_operators["add-yearMonthDuration-to-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:add-dayTimeDuration-to-dateTime($arg1 as xs:dateTime, $arg2 as xs:dayTimeDuration) as xs:dateTime
+hStaticContext_operators["add-dayTimeDuration-to-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:subtract-yearMonthDuration-from-dateTime($arg1 as xs:dateTime, $arg2 as xs:yearMonthDuration) as xs:dateTime
+hStaticContext_operators["subtract-yearMonthDuration-from-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:subtract-dayTimeDuration-from-dateTime($arg1 as xs:dateTime, $arg2 as xs:dayTimeDuration) as xs:dateTime
+hStaticContext_operators["subtract-dayTimeDuration-from-dateTime"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:add-yearMonthDuration-to-date($arg1 as xs:date, $arg2 as xs:yearMonthDuration) as xs:date
+hStaticContext_operators["add-yearMonthDuration-to-date"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:add-dayTimeDuration-to-date($arg1 as xs:date, $arg2 as xs:dayTimeDuration) as xs:date
+hStaticContext_operators["add-dayTimeDuration-to-date"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '+');
+};
+
+// op:subtract-yearMonthDuration-from-date($arg1 as xs:date, $arg2  as xs:yearMonthDuration) as xs:date
+hStaticContext_operators["subtract-yearMonthDuration-from-date"]	= function(oLeft, oRight) {
+	return fOperator_addYearMonthDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:subtract-dayTimeDuration-from-date($arg1 as xs:date, $arg2  as xs:dayTimeDuration) as xs:date
+hStaticContext_operators["subtract-dayTimeDuration-from-date"]	= function(oLeft, oRight) {
+	return fOperator_addDayTimeDuration2DateTime(oLeft, oRight, '-');
+};
+
+// op:add-dayTimeDuration-to-time($arg1 as xs:time, $arg2  as xs:dayTimeDuration) as xs:time
+hStaticContext_operators["add-dayTimeDuration-to-time"]	= function(oLeft, oRight) {
+	var oValue	= new cXSTime(oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone);
+	oValue.hours	+= oRight.hours;
+	oValue.minutes	+= oRight.minutes;
+	oValue.seconds	+= oRight.seconds;
+	//
+	return fXSTime_normalize(oValue);
+};
+
+// op:subtract-dayTimeDuration-from-time($arg1 as xs:time, $arg2  as xs:dayTimeDuration) as xs:time
+hStaticContext_operators["subtract-dayTimeDuration-from-time"]	= function(oLeft, oRight) {
+	var oValue	= new cXSTime(oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone);
+	oValue.hours	-= oRight.hours;
+	oValue.minutes	-= oRight.minutes;
+	oValue.seconds	-= oRight.seconds;
+	//
+	return fXSTime_normalize(oValue);
+};
+
+function fOperator_compareTimes(oLeft, oRight, sComparator) {
+	var nLeft	= fOperator_time_toSeconds(oLeft),
+		nRight	= fOperator_time_toSeconds(oRight);
+	return new cXSBoolean(sComparator == 'lt' ? nLeft < nRight : sComparator == 'gt' ? nLeft > nRight : nLeft == nRight);
+};
+
+function fOperator_compareDates(oLeft, oRight, sComparator) {
+	return fOperator_compareDateTimes(cXSDateTime.cast(oLeft), cXSDateTime.cast(oRight), sComparator);
+};
+
+function fOperator_compareDateTimes(oLeft, oRight, sComparator) {
+	// Adjust object time zone to Z and compare as strings
+	var oTimezone	= new cXSDayTimeDuration(0, 0, 0, 0),
+		sLeft	= fFunction_dateTime_adjustTimezone(oLeft, oTimezone).toString(),
+		sRight	= fFunction_dateTime_adjustTimezone(oRight, oTimezone).toString();
+	return new cXSBoolean(sComparator == 'lt' ? sLeft < sRight : sComparator == 'gt' ? sLeft > sRight : sLeft == sRight);
+};
+
+function fOperator_addYearMonthDuration2DateTime(oLeft, oRight, sOperator) {
+	var oValue;
+	if (oLeft instanceof cXSDate)
+		oValue	= new cXSDate(oLeft.year, oLeft.month, oLeft.day, oLeft.timezone, oLeft.negative);
+	else
+	if (oLeft instanceof cXSDateTime)
+		oValue	= new cXSDateTime(oLeft.year, oLeft.month, oLeft.day, oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone, oLeft.negative);
+	//
+	oValue.year		= oValue.year + oRight.year * (sOperator == '-' ?-1 : 1);
+	oValue.month	= oValue.month + oRight.month * (sOperator == '-' ?-1 : 1);
+	//
+	fXSDate_normalize(oValue, true);
+	// Correct day if out of month range
+	var nDay	= fXSDate_getDaysForYearMonth(oValue.year, oValue.month);
+	if (oValue.day > nDay)
+		oValue.day	= nDay;
+	//
+	return oValue;
+};
+
+function fOperator_addDayTimeDuration2DateTime(oLeft, oRight, sOperator) {
+	var oValue;
+	if (oLeft instanceof cXSDate) {
+		var nValue	= (oRight.hours * 60 + oRight.minutes) * 60 + oRight.seconds;
+		oValue	= new cXSDate(oLeft.year, oLeft.month, oLeft.day, oLeft.timezone, oLeft.negative);
+		oValue.day	= oValue.day + oRight.day * (sOperator == '-' ?-1 : 1) - 1 * (nValue && sOperator == '-');
+		//
+		fXSDate_normalize(oValue);
+	}
+	else
+	if (oLeft instanceof cXSDateTime) {
+		oValue	= new cXSDateTime(oLeft.year, oLeft.month, oLeft.day, oLeft.hours, oLeft.minutes, oLeft.seconds, oLeft.timezone, oLeft.negative);
+		oValue.seconds	= oValue.seconds + oRight.seconds * (sOperator == '-' ?-1 : 1);
+		oValue.minutes	= oValue.minutes + oRight.minutes * (sOperator == '-' ?-1 : 1);
+		oValue.hours	= oValue.hours + oRight.hours * (sOperator == '-' ?-1 : 1);
+		oValue.day		= oValue.day + oRight.day * (sOperator == '-' ?-1 : 1);
+		//
+		fXSDateTime_normalize(oValue);
+	}
+	return oValue;
+};
+
+// xs:dayTimeDuration to/from seconds
+function fOperator_dayTimeDuration_toSeconds(oDuration) {
+	return (((oDuration.day * 24 + oDuration.hours) * 60 + oDuration.minutes) * 60 + oDuration.seconds) * (oDuration.negative ? -1 : 1);
+};
+
+function fOperator_dayTimeDuration_fromSeconds(nValue) {
+	var bNegative	=(nValue = cMath.round(nValue)) < 0,
+		nDays	= ~~((nValue = cMath.abs(nValue)) / 86400),
+		nHours	= ~~((nValue -= nDays * 3600 * 24) / 3600),
+		nMinutes= ~~((nValue -= nHours * 3600) / 60),
+		nSeconds	= nValue -= nMinutes * 60;
+	return new cXSDayTimeDuration(nDays, nHours, nMinutes, nSeconds, bNegative);
+};
+
+// xs:yearMonthDuration to/from months
+function fOperator_yearMonthDuration_toMonths(oDuration) {
+	return (oDuration.year * 12 + oDuration.month) * (oDuration.negative ? -1 : 1);
+};
+
+function fOperator_yearMonthDuration_fromMonths(nValue) {
+	var nNegative	=(nValue = cMath.round(nValue)) < 0,
+		nYears	= ~~((nValue = cMath.abs(nValue)) / 12),
+		nMonths		= nValue -= nYears * 12;
+	return new cXSYearMonthDuration(nYears, nMonths, nNegative);
+};
+
+// xs:time to seconds
+function fOperator_time_toSeconds(oTime) {
+	return oTime.seconds + (oTime.minutes - (oTime.timezone != null ? oTime.timezone % 60 : 0) + (oTime.hours - (oTime.timezone != null ? ~~(oTime.timezone / 60) : 0)) * 60) * 60;
+};
+
+// This function unlike all other date-related functions rely on interpretor's dateTime handling
+function fOperator_dateTime_toSeconds(oValue) {
+	var oDate	= new cDate((oValue.negative ? -1 : 1) * oValue.year, oValue.month, oValue.day, 0, 0, 0, 0);
+	if (oValue instanceof cXSDateTime) {
+		oDate.setHours(oValue.hours);
+		oDate.setMinutes(oValue.minutes);
+		oDate.setSeconds(oValue.seconds);
+	}
+	if (oValue.timezone != null)
+		oDate.setMinutes(oDate.getMinutes() - oValue.timezone);
+	return oDate.getTime() / 1000;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	14 Functions and Operators on Nodes
+		op:is-same-node
+		op:node-before
+		op:node-after
+*/
+
+// 14 Operators on Nodes
+// op:is-same-node($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["is-same-node"]	= function(oLeft, oRight) {
+	return new cXSBoolean(this.DOMAdapter.isSameNode(oLeft, oRight));
+};
+
+// op:node-before($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["node-before"]	= function(oLeft, oRight) {
+	return new cXSBoolean(!!(this.DOMAdapter.compareDocumentPosition(oLeft, oRight) & 4));
+};
+
+// op:node-after($parameter1 as node(), $parameter2 as node()) as xs:boolean
+hStaticContext_operators["node-after"]	= function(oLeft, oRight) {
+	return new cXSBoolean(!!(this.DOMAdapter.compareDocumentPosition(oLeft, oRight) & 2));
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	13.1 Operators on NOTATION
+		op:NOTATION-equal
+*/
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	6.2 Operators on Numeric Values
+		op:numeric-add
+		op:numeric-subtract
+		op:numeric-multiply
+		op:numeric-divide
+		op:numeric-integer-divide
+		op:numeric-mod
+		op:numeric-unary-plus
+		op:numeric-unary-minus
+
+	6.3 Comparison Operators on Numeric Values
+		op:numeric-equal
+		op:numeric-less-than
+		op:numeric-greater-than
+*/
+
+// 6.2 Operators on Numeric Values
+function fFunctionCall_numeric_getPower(oLeft, oRight) {
+	if (fIsNaN(oLeft) || (cMath.abs(oLeft) == nInfinity) || fIsNaN(oRight) || (cMath.abs(oRight) == nInfinity))
+		return 0;
+	var aLeft	= cString(oLeft).match(rNumericLiteral),
+		aRight	= cString(oRight).match(rNumericLiteral),
+		nPower	= cMath.max(1, (aLeft[2] || aLeft[3] || '').length + (aLeft[5] || 0) * (aLeft[4] == '+' ?-1 : 1), (aRight[2] || aRight[3] || '').length + (aRight[5] || 0) * (aRight[4] == '+' ?-1 : 1));
+	return nPower + (nPower % 2 ? 0 : 1);
+};
+
+// op:numeric-add($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-add"]		= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) + (nRight * nPower))/nPower);
+};
+
+// op:numeric-subtract($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-subtract"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) - (nRight * nPower))/nPower);
+};
+
+// op:numeric-multiply($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-multiply"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) * (nRight * nPower))/(nPower * nPower));
+};
+
+// op:numeric-divide($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-divide"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, (oLeft * nPower) / (oRight * nPower));
+};
+
+// op:numeric-integer-divide($arg1 as numeric, $arg2 as numeric) as xs:integer
+hStaticContext_operators["numeric-integer-divide"]	= function(oLeft, oRight) {
+	var oValue = oLeft / oRight;
+	return new cXSInteger(cMath.floor(oValue) + (oValue < 0));
+};
+
+// op:numeric-mod($arg1 as numeric, $arg2 as numeric) as numeric
+hStaticContext_operators["numeric-mod"]	= function(oLeft, oRight) {
+	var nLeft	= oLeft.valueOf(),
+		nRight	= oRight.valueOf(),
+		nPower	= cMath.pow(10, fFunctionCall_numeric_getPower(nLeft, nRight));
+	return fOperator_numeric_getResultOfType(oLeft, oRight, ((nLeft * nPower) % (nRight * nPower)) / nPower);
+};
+
+// op:numeric-unary-plus($arg as numeric) as numeric
+hStaticContext_operators["numeric-unary-plus"]	= function(oRight) {
+	return oRight;
+};
+
+// op:numeric-unary-minus($arg as numeric) as numeric
+hStaticContext_operators["numeric-unary-minus"]	= function(oRight) {
+	oRight.value	*=-1;
+	return oRight;
+};
+
+
+// 6.3 Comparison Operators on Numeric Values
+// op:numeric-equal($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() == oRight.valueOf());
+};
+
+// op:numeric-less-than($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-less-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() < oRight.valueOf());
+};
+
+// op:numeric-greater-than($arg1 as numeric, $arg2 as numeric) as xs:boolean
+hStaticContext_operators["numeric-greater-than"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.valueOf() > oRight.valueOf());
+};
+
+function fOperator_numeric_getResultOfType(oLeft, oRight, nResult) {
+	return new (oLeft instanceof cXSInteger && oRight instanceof cXSInteger && nResult == cMath.round(nResult) ? cXSInteger : cXSDecimal)(nResult);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	11.2 Functions and Operators Related to QNames
+		op:QName-equal
+
+*/
+
+// 11.2 Operators Related to QNames
+// op:QName-equal($arg1 as xs:QName, $arg2 as xs:QName) as xs:boolean
+hStaticContext_operators["QName-equal"]	= function(oLeft, oRight) {
+	return new cXSBoolean(oLeft.localName == oRight.localName && oLeft.namespaceURI == oRight.namespaceURI);
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	15.1 General Functions and Operators on Sequences
+		op:concatenate
+
+	15.3 Equals, Union, Intersection and Except
+		op:union
+		op:intersect
+		op:except
+
+	15.5 Functions and Operators that Generate Sequences
+		op:to
+
+*/
+
+// 15.1 General Functions and Operators on Sequences
+// op:concatenate($seq1 as item()*, $seq2 as item()*) as item()*
+hStaticContext_operators["concatenate"]	= function(oSequence1, oSequence2) {
+	return oSequence1.concat(oSequence2);
+};
+
+// 15.3 Equals, Union, Intersection and Except
+// op:union($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["union"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	// Process first collection
+	for (var nIndex = 0, nLength = oSequence1.length, oItem; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		if (fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	// Process second collection
+	for (var nIndex = 0, nLength = oSequence2.length, oItem; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence2[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		if (fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// op:intersect($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["intersect"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, bFound; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		bFound	= false;
+		for (var nRightIndex = 0, nRightLength = oSequence2.length;(nRightIndex < nRightLength) && !bFound; nRightIndex++) {
+			if (!this.DOMAdapter.isNode(oSequence2[nRightIndex]))
+				throw new cException("XPTY0004"
+
+				);
+			bFound = this.DOMAdapter.isSameNode(oSequence2[nRightIndex], oItem);
+		}
+		//
+		if (bFound && fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// op:except($parameter1 as node()*, $parameter2 as node()*) as node()*
+hStaticContext_operators["except"]	= function(oSequence1, oSequence2) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, bFound; nIndex < nLength; nIndex++) {
+		if (!this.DOMAdapter.isNode(oItem = oSequence1[nIndex]))
+			throw new cException("XPTY0004"
+
+			);	// Required item type of second operand of 'intersect' is node(); supplied value has item type xs:integer
+		//
+		bFound	= false;
+		for (var nRightIndex = 0, nRightLength = oSequence2.length;(nRightIndex < nRightLength) && !bFound; nRightIndex++) {
+			if (!this.DOMAdapter.isNode(oSequence2[nRightIndex]))
+				throw new cException("XPTY0004"
+
+				);
+			bFound = this.DOMAdapter.isSameNode(oSequence2[nRightIndex], oItem);
+		}
+		//
+		if (!bFound && fArray_indexOf(oSequence, oItem) ==-1)
+			oSequence.push(oItem);
+	}
+	return fFunction_sequence_order(oSequence, this);
+};
+
+// 15.5 Functions and Operators that Generate Sequences
+// op:to($firstval as xs:integer, $lastval as xs:integer) as xs:integer*
+hStaticContext_operators["to"]	= function(oLeft, oRight) {
+	var oSequence	= [];
+	for (var nIndex = oLeft.valueOf(), nLength = oRight.valueOf(); nIndex <= nLength; nIndex++)
+		oSequence.push(new cXSInteger(nIndex));
+	//
+	return oSequence;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	2 Accessors
+		node-name
+		nilled
+		string
+		data
+		base-uri
+		document-uri
+
+*/
+
+// fn:node-name($arg as node()?) as xs:QName?
+fStaticContext_defineSystemFunction("node-name",		[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		var fGetProperty	= this.DOMAdapter.getProperty;
+		switch (fGetProperty(oNode, "nodeType")) {
+			case 1:		// ELEMENT_NAME
+			case 2:		// ATTRIBUTE_NODE
+				return new cXSQName(fGetProperty(oNode, "prefix"), fGetProperty(oNode, "localName"), fGetProperty(oNode, "namespaceURI"));
+			case 5:		// ENTITY_REFERENCE_NODE
+				throw "Not implemented";
+			case 6:		// ENTITY_NODE
+				throw "Not implemented";
+			case 7:		// PROCESSING_INSTRUCTION_NODE
+				return new cXSQName(null, fGetProperty(oNode, "target"), null);
+			case 10:	// DOCUMENT_TYPE_NODE
+				return new cXSQName(null, fGetProperty(oNode, "name"), null);
+		}
+	}
+	//
+	return null;
+});
+
+// fn:nilled($arg as node()?) as xs:boolean?
+fStaticContext_defineSystemFunction("nilled",	[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		if (this.DOMAdapter.getProperty(oNode, "nodeType") == 1)
+			return new cXSBoolean(false);	// TODO: Determine if node is nilled
+	}
+	//
+	return null;
+});
+
+// fn:string() as xs:string
+// fn:string($arg as item()?) as xs:string
+fStaticContext_defineSystemFunction("string",	[[cXTItem, '?', true]],	function(/*[*/oItem/*]*/) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oItem	= this.item;
+	}
+	return oItem == null ? new cXSString('') : cXSString.cast(fFunction_sequence_atomize([oItem], this)[0]);
+});
+
+// fn:data($arg as item()*) as xs:anyAtomicType*
+fStaticContext_defineSystemFunction("data",	[[cXTItem, '*']],		function(oSequence1) {
+	return fFunction_sequence_atomize(oSequence1, this);
+});
+
+// fn:base-uri() as xs:anyURI?
+// fn:base-uri($arg as node()?) as xs:anyURI?
+fStaticContext_defineSystemFunction("base-uri",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	//
+	return cXSAnyURI.cast(new cXSString(this.DOMAdapter.getProperty(oNode, "baseURI") || ''));
+});
+
+// fn:document-uri($arg as node()?) as xs:anyURI?
+fStaticContext_defineSystemFunction("document-uri",	[[cXTNode, '?']],	function(oNode) {
+	if (oNode != null) {
+		var fGetProperty	= this.DOMAdapter.getProperty;
+		if (fGetProperty(oNode, "nodeType") == 9)
+			return cXSAnyURI.cast(new cXSString(fGetProperty(oNode, "documentURI") || ''));
+	}
+	//
+	return null;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	8 Functions on anyURI
+		resolve-uri
+*/
+
+// fn:resolve-uri($relative as xs:string?) as xs:anyURI?
+// fn:resolve-uri($relative as xs:string?, $base as xs:string) as xs:anyURI?
+fStaticContext_defineSystemFunction("resolve-uri",	[[cXSString, '?'], [cXSString, '', true]],	function(sUri, sBaseUri) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		sBaseUri	= new cXSString(this.DOMAdapter.getProperty(this.item, "baseURI") || '');
+	}
+
+	if (sUri == null)
+		return null;
+
+	//
+	if (sUri.valueOf() == '' || sUri.valueOf().charAt(0) == '#')
+		return cXSAnyURI.cast(sBaseUri);
+
+	var oUri	= cXSAnyURI.cast(sUri);
+	if (oUri.scheme)
+		return oUri;
+
+	var oBaseUri	= cXSAnyURI.cast(sBaseUri);
+	oUri.scheme	= oBaseUri.scheme;
+
+	if (!oUri.authority) {
+		// authority
+		oUri.authority	= oBaseUri.authority;
+
+		// path
+		if (oUri.path.charAt(0) != '/') {
+			var aUriSegments		= oUri.path.split('/'),
+				aBaseUriSegments	= oBaseUri.path.split('/');
+			aBaseUriSegments.pop();
+
+			var nBaseUriStart	= aBaseUriSegments[0] == '' ? 1 : 0;
+			for (var nIndex = 0, nLength = aUriSegments.length; nIndex < nLength; nIndex++) {
+				if (aUriSegments[nIndex] == '..') {
+					if (aBaseUriSegments.length > nBaseUriStart)
+						aBaseUriSegments.pop();
+					else {
+						aBaseUriSegments.push(aUriSegments[nIndex]);
+						nBaseUriStart++;
+					}
+				}
+				else
+				if (aUriSegments[nIndex] != '.')
+					aBaseUriSegments.push(aUriSegments[nIndex]);
+			}
+			if (aUriSegments[--nIndex] == '..' || aUriSegments[nIndex] == '.')
+				aBaseUriSegments.push('');
+			//
+			oUri.path	= aBaseUriSegments.join('/');
+		}
+	}
+
+	return oUri;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	9.1 Additional Boolean Constructor Functions
+		true
+		false
+
+	9.3 Functions on Boolean Values
+		not
+*/
+
+// 9.1 Additional Boolean Constructor Functions
+// fn:true() as xs:boolean
+fStaticContext_defineSystemFunction("true",	[],	function() {
+	return new cXSBoolean(true);
+});
+
+// fn:false() as xs:boolean
+fStaticContext_defineSystemFunction("false",	[],	function() {
+	return new cXSBoolean(false);
+});
+
+// 9.3 Functions on Boolean Values
+// fn:not($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("not",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!fFunction_sequence_toEBV(oSequence1, this));
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	16 Context Functions
+		position
+		last
+		current-dateTime
+		current-date
+		current-time
+		implicit-timezone
+		default-collation
+		static-base-uri
+
+*/
+// fn:position() as xs:integer
+fStaticContext_defineSystemFunction("position",	[],	function() {
+	return new cXSInteger(this.position);
+});
+
+// fn:last() as xs:integer
+fStaticContext_defineSystemFunction("last",	[],	function() {
+	return new cXSInteger(this.size);
+});
+
+// fn:current-dateTime() as xs:dateTime (2004-05-12T18:17:15.125Z)
+fStaticContext_defineSystemFunction("current-dateTime",	[],	 function() {
+	return this.dateTime;
+});
+
+// fn:current-date() as xs:date (2004-05-12+01:00)
+fStaticContext_defineSystemFunction("current-date",	[],	function() {
+	return cXSDate.cast(this.dateTime);
+});
+
+// fn:current-time() as xs:time (23:17:00.000-05:00)
+fStaticContext_defineSystemFunction("current-time",	[],	function() {
+	return cXSTime.cast(this.dateTime);
+});
+
+// fn:implicit-timezone() as xs:dayTimeDuration
+fStaticContext_defineSystemFunction("implicit-timezone",	[],	function() {
+	return this.timezone;
+});
+
+// fn:default-collation() as xs:string
+fStaticContext_defineSystemFunction("default-collation",	[],	 function() {
+	return new cXSString(this.staticContext.defaultCollationName);
+});
+
+// fn:static-base-uri() as xs:anyURI?
+fStaticContext_defineSystemFunction("static-base-uri",	[],	function() {
+	return cXSAnyURI.cast(new cXSString(this.staticContext.baseURI || ''));
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	10.5 Component Extraction Functions on Durations, Dates and Times
+		years-from-duration
+		months-from-duration
+		days-from-duration
+		hours-from-duration
+		minutes-from-duration
+		seconds-from-duration
+		year-from-dateTime
+		month-from-dateTime
+		day-from-dateTime
+		hours-from-dateTime
+		minutes-from-dateTime
+		seconds-from-dateTime
+		timezone-from-dateTime
+		year-from-date
+		month-from-date
+		day-from-date
+		timezone-from-date
+		hours-from-time
+		minutes-from-time
+		seconds-from-time
+		timezone-from-time
+
+	10.7 Timezone Adjustment Functions on Dates and Time Values
+		adjust-dateTime-to-timezone
+		adjust-date-to-timezone
+		adjust-time-to-timezone
+*/
+
+// 10.5 Component Extraction Functions on Durations, Dates and Times
+// functions on duration
+// fn:years-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("years-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "year");
+});
+
+// fn:months-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("months-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "month");
+});
+
+// fn:days-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("days-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "day");
+});
+
+// fn:hours-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "hours");
+});
+
+// fn:minutes-from-duration($arg as xs:duration?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "minutes");
+});
+
+// fn:seconds-from-duration($arg as xs:duration?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-duration",	[[cXSDuration, '?']],	function(oDuration) {
+	return fFunction_duration_getComponent(oDuration, "seconds");
+});
+
+// functions on dateTime
+// fn:year-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("year-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime,	"year");
+});
+
+// fn:month-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("month-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "month");
+});
+
+// fn:day-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("day-from-dateTime",			[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "day");
+});
+
+// fn:hours-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "hours");
+});
+
+// fn:minutes-from-dateTime($arg as xs:dateTime?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "minutes");
+});
+
+// fn:seconds-from-dateTime($arg as xs:dateTime?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-dateTime",		[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "seconds");
+});
+
+// fn:timezone-from-dateTime($arg as xs:dateTime?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-dateTime",	[[cXSDateTime, '?']],	function(oDateTime) {
+	return fFunction_dateTime_getComponent(oDateTime, "timezone");
+});
+
+// functions on date
+// fn:year-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("year-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "year");
+});
+
+// fn:month-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("month-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "month");
+});
+
+// fn:day-from-date($arg as xs:date?) as xs:integer?
+fStaticContext_defineSystemFunction("day-from-date",		[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "day");
+});
+
+// fn:timezone-from-date($arg as xs:date?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-date",	[[cXSDate, '?']],	function(oDate) {
+	return fFunction_dateTime_getComponent(oDate, "timezone");
+});
+
+// functions on time
+// fn:hours-from-time($arg as xs:time?) as xs:integer?
+fStaticContext_defineSystemFunction("hours-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "hours");
+});
+
+// fn:minutes-from-time($arg as xs:time?) as xs:integer?
+fStaticContext_defineSystemFunction("minutes-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "minutes");
+});
+
+// fn:seconds-from-time($arg as xs:time?) as xs:decimal?
+fStaticContext_defineSystemFunction("seconds-from-time",		[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "seconds");
+});
+
+// fn:timezone-from-time($arg as xs:time?) as xs:dayTimeDuration?
+fStaticContext_defineSystemFunction("timezone-from-time",	[[cXSTime, '?']],	function(oTime) {
+	return fFunction_dateTime_getComponent(oTime, "timezone");
+});
+
+
+// 10.7 Timezone Adjustment Functions on Dates and Time Values
+// fn:adjust-dateTime-to-timezone($arg as xs:dateTime?) as xs:dateTime?
+// fn:adjust-dateTime-to-timezone($arg as xs:dateTime?, $timezone as xs:dayTimeDuration?) as xs:dateTime?
+fStaticContext_defineSystemFunction("adjust-dateTime-to-timezone",	[[cXSDateTime, '?'], [cXSDayTimeDuration, '?', true]],	function(oDateTime, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oDateTime, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+// fn:adjust-date-to-timezone($arg as xs:date?) as xs:date?
+// fn:adjust-date-to-timezone($arg as xs:date?, $timezone as xs:dayTimeDuration?) as xs:date?
+fStaticContext_defineSystemFunction("adjust-date-to-timezone",		[[cXSDate, '?'], [cXSDayTimeDuration, '?', true]],	function(oDate, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oDate, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+// fn:adjust-time-to-timezone($arg as xs:time?) as xs:time?
+// fn:adjust-time-to-timezone($arg as xs:time?, $timezone as xs:dayTimeDuration?) as xs:time?
+fStaticContext_defineSystemFunction("adjust-time-to-timezone",		[[cXSTime, '?'], [cXSDayTimeDuration, '?', true]],	function(oTime, oDayTimeDuration) {
+	return fFunction_dateTime_adjustTimezone(oTime, arguments.length > 1 && oDayTimeDuration != null ? arguments.length > 1 ? oDayTimeDuration : this.timezone : null);
+});
+
+//
+function fFunction_duration_getComponent(oDuration, sName) {
+	if (oDuration == null)
+		return null;
+
+	var nValue	= oDuration[sName] * (oDuration.negative ?-1 : 1);
+	return sName == "seconds" ? new cXSDecimal(nValue) : new cXSInteger(nValue);
+};
+
+//
+function fFunction_dateTime_getComponent(oDateTime, sName) {
+	if (oDateTime == null)
+		return null;
+
+	if (sName == "timezone") {
+		var nTimezone	= oDateTime.timezone;
+		if (nTimezone == null)
+			return null;
+		return new cXSDayTimeDuration(0, cMath.abs(~~(nTimezone / 60)), cMath.abs(nTimezone % 60), 0, nTimezone < 0);
+	}
+	else {
+		var nValue	= oDateTime[sName];
+		if (!(oDateTime instanceof cXSDate)) {
+			if (sName == "hours")
+				if (nValue == 24)
+					nValue	= 0;
+		}
+		if (!(oDateTime instanceof cXSTime))
+			nValue	*= oDateTime.negative ?-1 : 1;
+		return sName == "seconds" ? new cXSDecimal(nValue) : new cXSInteger(nValue);
+	}
+};
+
+//
+function fFunction_dateTime_adjustTimezone(oDateTime, oTimezone) {
+	if (oDateTime == null)
+		return null;
+
+	// Create a copy
+	var oValue;
+	if (oDateTime instanceof cXSDate)
+		oValue	= new cXSDate(oDateTime.year, oDateTime.month, oDateTime.day, oDateTime.timezone, oDateTime.negative);
+	else
+	if (oDateTime instanceof cXSTime)
+		oValue	= new cXSTime(oDateTime.hours, oDateTime.minutes, oDateTime.seconds, oDateTime.timezone, oDateTime.negative);
+	else
+		oValue	= new cXSDateTime(oDateTime.year, oDateTime.month, oDateTime.day, oDateTime.hours, oDateTime.minutes, oDateTime.seconds, oDateTime.timezone, oDateTime.negative);
+
+	//
+	if (oTimezone == null)
+		oValue.timezone	= null;
+	else {
+		var nTimezone	= fOperator_dayTimeDuration_toSeconds(oTimezone) / 60;
+		if (oDateTime.timezone != null) {
+			var nDiff	= nTimezone - oDateTime.timezone;
+			if (oDateTime instanceof cXSDate) {
+				if (nDiff < 0)
+					oValue.day--;
+			}
+			else {
+				oValue.minutes	+= nDiff % 60;
+				oValue.hours	+= ~~(nDiff / 60);
+			}
+			//
+			fXSDateTime_normalize(oValue);
+		}
+		oValue.timezone	= nTimezone;
+	}
+	return oValue;
+};
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	14 Functions and Operators on Nodes
+		name
+		local-name
+		namespace-uri
+		number
+		lang
+		root
+
+*/
+
+// 14 Functions on Nodes
+// fn:name() as xs:string
+// fn:name($arg as node()?) as xs:string
+fStaticContext_defineSystemFunction("name",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return new cXSString('');
+	//
+	var vValue	= hStaticContext_functions["node-name"].call(this, oNode);
+	return new cXSString(vValue == null ? '' : vValue.toString());
+});
+
+// fn:local-name() as xs:string
+// fn:local-name($arg as node()?) as xs:string
+fStaticContext_defineSystemFunction("local-name",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return new cXSString('');
+	//
+	return new cXSString(this.DOMAdapter.getProperty(oNode, "localName") || '');
+});
+
+// fn:namespace-uri() as xs:anyURI
+// fn:namespace-uri($arg as node()?) as xs:anyURI
+fStaticContext_defineSystemFunction("namespace-uri",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return cXSAnyURI.cast(new cXSString(''));
+	//
+	return cXSAnyURI.cast(new cXSString(this.DOMAdapter.getProperty(oNode, "namespaceURI") || ''));
+});
+
+// fn:number() as xs:double
+// fn:number($arg as xs:anyAtomicType?) as xs:double
+fStaticContext_defineSystemFunction("number",	[[cXSAnyAtomicType, '?', true]],	function(/*[*/oItem/*]*/) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oItem	= fFunction_sequence_atomize([this.item], this)[0];
+	}
+
+	// If input item cannot be cast to xs:decimal, a NaN should be returned
+	var vValue	= new cXSDouble(nNaN);
+	if (oItem != null) {
+		try {
+			vValue	= cXSDouble.cast(oItem);
+		}
+		catch (e) {
+
+		}
+	}
+	return vValue;
+});
+
+// fn:lang($testlang as xs:string?) as xs:boolean
+// fn:lang($testlang as xs:string?, $node as node()) as xs:boolean
+fStaticContext_defineSystemFunction("lang",	[[cXSString, '?'], [cXTNode, '', true]],	function(sLang, oNode) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+
+	var fGetProperty	= this.DOMAdapter.getProperty;
+	if (fGetProperty(oNode, "nodeType") == 2)
+		oNode	= fGetProperty(oNode, "ownerElement");
+
+	// walk up the tree looking for xml:lang attribute
+	for (var aAttributes; oNode; oNode = fGetProperty(oNode, "parentNode"))
+		if (aAttributes = fGetProperty(oNode, "attributes"))
+			for (var nIndex = 0, nLength = aAttributes.length; nIndex < nLength; nIndex++)
+				if (fGetProperty(aAttributes[nIndex], "nodeName") == "xml:lang")
+					return new cXSBoolean(fGetProperty(aAttributes[nIndex], "value").replace(/-.+/, '').toLowerCase() == sLang.valueOf().replace(/-.+/, '').toLowerCase());
+	//
+	return new cXSBoolean(false);
+});
+
+// fn:root() as node()
+// fn:root($arg as node()?) as node()?
+fStaticContext_defineSystemFunction("root",	[[cXTNode, '?', true]],	function(oNode) {
+	if (!arguments.length) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+	else
+	if (oNode == null)
+		return null;
+
+	var fGetProperty	= this.DOMAdapter.getProperty;
+
+	// If context node is Attribute
+	if (fGetProperty(oNode, "nodeType") == 2)
+		oNode	= fGetProperty(oNode, "ownerElement");
+
+	for (var oParent = oNode; oParent; oParent = fGetProperty(oNode, "parentNode"))
+		oNode	= oParent;
+
+	return oNode;
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	6.4 Functions on Numeric Values
+		abs
+		ceiling
+		floor
+		round
+		round-half-to-even
+*/
+
+// 6.4 Functions on Numeric Values
+// fn:abs($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("abs",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.abs(oValue));
+});
+
+// fn:ceiling($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("ceiling",	[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.ceil(oValue));
+});
+
+// fn:floor($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("floor",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.floor(oValue));
+});
+
+// fn:round($arg as numeric?) as numeric?
+fStaticContext_defineSystemFunction("round",		[[cXSDouble, '?']],	function(oValue) {
+	return new cXSDecimal(cMath.round(oValue));
+});
+
+// fn:round-half-to-even($arg as numeric?) as numeric?
+// fn:round-half-to-even($arg as numeric?, $precision as xs:integer) as numeric?
+fStaticContext_defineSystemFunction("round-half-to-even",	[[cXSDouble, '?'], [cXSInteger, '', true]],	function(oValue, oPrecision) {
+	var nPrecision	= arguments.length > 1 ? oPrecision.valueOf() : 0;
+
+	//
+	if (nPrecision < 0) {
+		var oPower	= new cXSInteger(cMath.pow(10,-nPrecision)),
+			nRounded= cMath.round(hStaticContext_operators["numeric-divide"].call(this, oValue, oPower)),
+			oRounded= new cXSInteger(nRounded);
+			nDecimal= cMath.abs(hStaticContext_operators["numeric-subtract"].call(this, oRounded, hStaticContext_operators["numeric-divide"].call(this, oValue, oPower)));
+		return hStaticContext_operators["numeric-multiply"].call(this, hStaticContext_operators["numeric-add"].call(this, oRounded, new cXSDecimal(nDecimal == 0.5 && nRounded % 2 ?-1 : 0)), oPower);
+	}
+	else {
+		var oPower	= new cXSInteger(cMath.pow(10, nPrecision)),
+			nRounded= cMath.round(hStaticContext_operators["numeric-multiply"].call(this, oValue, oPower)),
+			oRounded= new cXSInteger(nRounded);
+			nDecimal= cMath.abs(hStaticContext_operators["numeric-subtract"].call(this, oRounded, hStaticContext_operators["numeric-multiply"].call(this, oValue, oPower)));
+		return hStaticContext_operators["numeric-divide"].call(this, hStaticContext_operators["numeric-add"].call(this, oRounded, new cXSDecimal(nDecimal == 0.5 && nRounded % 2 ?-1 : 0)), oPower);
+	}
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	11.1 Additional Constructor Functions for QNames
+		resolve-QName
+		QName
+
+	11.2 Functions and Operators Related to QNames
+		prefix-from-QName
+		local-name-from-QName
+		namespace-uri-from-QName
+		namespace-uri-for-prefix
+		in-scope-prefixes
+
+*/
+
+// 11.1 Additional Constructor Functions for QNames
+// fn:resolve-QName($qname as xs:string?, $element as element()) as xs:QName?
+fStaticContext_defineSystemFunction("resolve-QName",	[[cXSString, '?'], [cXTElement]],	function(oQName, oElement) {
+	if (oQName == null)
+		return null;
+
+	var sQName	= oQName.valueOf(),
+		aMatch	= sQName.match(rXSQName);
+	if (!aMatch)
+		throw new cException("FOCA0002"
+
+		);
+
+	var sPrefix	= aMatch[1] || null,
+		sLocalName	= aMatch[2],
+		sNameSpaceURI = this.DOMAdapter.lookupNamespaceURI(oElement, sPrefix);
+	//
+	if (sPrefix != null &&!sNameSpaceURI)
+		throw new cException("FONS0004"
+
+		);
+
+	return new cXSQName(sPrefix, sLocalName, sNameSpaceURI || null);
+});
+
+// fn:QName($paramURI as xs:string?, $paramQName as xs:string) as xs:QName
+fStaticContext_defineSystemFunction("QName",		[[cXSString, '?'], [cXSString]],	function(oUri, oQName) {
+	var sQName	= oQName.valueOf(),
+		aMatch	= sQName.match(rXSQName);
+
+	if (!aMatch)
+		throw new cException("FOCA0002"
+
+		);
+
+	return new cXSQName(aMatch[1] || null, aMatch[2] || null, oUri == null ? '' : oUri.valueOf());
+});
+
+// 11.2 Functions Related to QNames
+// fn:prefix-from-QName($arg as xs:QName?) as xs:NCName?
+fStaticContext_defineSystemFunction("prefix-from-QName",			[[cXSQName, '?']],	function(oQName) {
+	if (oQName != null) {
+		if (oQName.prefix)
+			return new cXSNCName(oQName.prefix);
+	}
+	//
+	return null;
+});
+
+// fn:local-name-from-QName($arg as xs:QName?) as xs:NCName?
+fStaticContext_defineSystemFunction("local-name-from-QName",		[[cXSQName, '?']],	function(oQName) {
+	if (oQName == null)
+		return null;
+
+	return new cXSNCName(oQName.localName);
+});
+
+// fn:namespace-uri-from-QName($arg as xs:QName?) as xs:anyURI?
+fStaticContext_defineSystemFunction("namespace-uri-from-QName",	[[cXSQName, '?']],	function(oQName) {
+	if (oQName == null)
+		return null;
+
+	return cXSAnyURI.cast(new cXSString(oQName.namespaceURI || ''));
+});
+
+// fn:namespace-uri-for-prefix($prefix as xs:string?, $element as element()) as xs:anyURI?
+fStaticContext_defineSystemFunction("namespace-uri-for-prefix",	[[cXSString, '?'], [cXTElement]],	function(oPrefix, oElement) {
+	var sPrefix	= oPrefix == null ? '' : oPrefix.valueOf(),
+		sNameSpaceURI	= this.DOMAdapter.lookupNamespaceURI(oElement, sPrefix || null);
+
+	return sNameSpaceURI == null ? null : cXSAnyURI.cast(new cXSString(sNameSpaceURI));
+});
+
+// fn:in-scope-prefixes($element as element()) as xs:string*
+fStaticContext_defineSystemFunction("in-scope-prefixes",	[[cXTElement]],	function(oElement) {
+	throw "Function '" + "in-scope-prefixes" + "' not implemented";
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	15.1 General Functions and Operators on Sequences
+		boolean
+		index-of
+		empty
+		exists
+		distinct-values
+		insert-before
+		remove
+		reverse
+		subsequence
+		unordered
+
+	15.2 Functions That Test the Cardinality of Sequences
+		zero-or-one
+		one-or-more
+		exactly-one
+
+	15.3 Equals, Union, Intersection and Except
+		deep-equal
+
+	15.4 Aggregate Functions
+		count
+		avg
+		max
+		min
+		sum
+
+	15.5 Functions and Operators that Generate Sequences
+		id
+		idref
+		doc
+		doc-available
+		collection
+		element-with-id
+
+*/
+
+// 15.1 General Functions and Operators on Sequences
+// fn:boolean($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("boolean",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(fFunction_sequence_toEBV(oSequence1, this));
+});
+
+// fn:index-of($seqParam as xs:anyAtomicType*, $srchParam as xs:anyAtomicType) as xs:integer*
+// fn:index-of($seqParam as xs:anyAtomicType*, $srchParam as xs:anyAtomicType, $collation as xs:string) as xs:integer*
+fStaticContext_defineSystemFunction("index-of",	[[cXSAnyAtomicType, '*'], [cXSAnyAtomicType], [cXSString, '', true]],	function(oSequence1, oSearch, oCollation) {
+	if (!oSequence1.length || oSearch == null)
+		return [];
+
+	// TODO: Implement collation
+
+	var vLeft	= oSearch;
+	// Cast to XSString if Untyped
+	if (vLeft instanceof cXSUntypedAtomic)
+		vLeft	= cXSString.cast(vLeft);
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+		vRight	= oSequence1[nIndex];
+		// Cast to XSString if Untyped
+		if (vRight instanceof cXSUntypedAtomic)
+			vRight	= cXSString.cast(vRight);
+		//
+		if (vRight.valueOf() === vLeft.valueOf())
+			oSequence.push(new cXSInteger(nIndex + 1));
+	}
+
+	return oSequence;
+});
+
+// fn:empty($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("empty",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!oSequence1.length);
+});
+
+// fn:exists($arg as item()*) as xs:boolean
+fStaticContext_defineSystemFunction("exists",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSBoolean(!!oSequence1.length);
+});
+
+// fn:distinct-values($arg as xs:anyAtomicType*) as xs:anyAtomicType*
+// fn:distinct-values($arg as xs:anyAtomicType*, $collation as xs:string) as xs:anyAtomicType*
+fStaticContext_defineSystemFunction("distinct-values",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (arguments.length > 1)
+		throw "Collation parameter in function '" + "distinct-values" + "' is not implemented";
+
+	if (!oSequence1.length)
+		return null;
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, vLeft; nIndex < nLength; nIndex++) {
+		vLeft	= oSequence1[nIndex];
+		// Cast to XSString if Untyped
+		if (vLeft instanceof cXSUntypedAtomic)
+			vLeft	= cXSString.cast(vLeft);
+		for (var nRightIndex = 0, nRightLength = oSequence.length, vRight, bFound = false; (nRightIndex < nRightLength) &&!bFound; nRightIndex++) {
+			vRight	= oSequence[nRightIndex];
+			// Cast to XSString if Untyped
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSString.cast(vRight);
+			//
+			if (vRight.valueOf() === vLeft.valueOf())
+				bFound	= true;
+		}
+		if (!bFound)
+			oSequence.push(oSequence1[nIndex]);
+	}
+
+	return oSequence;
+});
+
+// fn:insert-before($target as item()*, $position as xs:integer, $inserts as item()*) as item()*
+fStaticContext_defineSystemFunction("insert-before",	[[cXTItem, '*'], [cXSInteger], [cXTItem, '*']],	function(oSequence1, oPosition, oSequence3) {
+	if (!oSequence1.length)
+		return oSequence3;
+	if (!oSequence3.length)
+		return oSequence1;
+
+	var nLength 	= oSequence1.length,
+		nPosition	= oPosition.valueOf();
+	if (nPosition < 1)
+		nPosition	= 1;
+	else
+	if (nPosition > nLength)
+		nPosition	= nLength + 1;
+
+	var oSequence	=  [];
+	for (var nIndex = 0; nIndex < nLength; nIndex++) {
+		if (nPosition == nIndex + 1)
+			oSequence	= oSequence.concat(oSequence3);
+		oSequence.push(oSequence1[nIndex]);
+	}
+	if (nPosition == nIndex + 1)
+		oSequence	= oSequence.concat(oSequence3);
+
+	return oSequence;
+});
+
+// fn:remove($target as item()*, $position as xs:integer) as item()*
+fStaticContext_defineSystemFunction("remove",	[[cXTItem, '*'], [cXSInteger]],	function(oSequence1, oPosition) {
+	if (!oSequence1.length)
+		return [];
+
+	var nLength 	= oSequence1.length,
+		nPosition	= oPosition.valueOf();
+
+	if (nPosition < 1 || nPosition > nLength)
+		return oSequence1;
+
+	var oSequence	=  [];
+	for (var nIndex = 0; nIndex < nLength; nIndex++)
+		if (nPosition != nIndex + 1)
+			oSequence.push(oSequence1[nIndex]);
+
+	return oSequence;
+});
+
+// fn:reverse($arg as item()*) as item()*
+fStaticContext_defineSystemFunction("reverse",	[[cXTItem, '*']],	function(oSequence1) {
+	oSequence1.reverse();
+
+	return oSequence1;
+});
+
+// fn:subsequence($sourceSeq as item()*, $startingLoc as xs:double) as item()*
+// fn:subsequence($sourceSeq as item()*, $startingLoc as xs:double, $length as xs:double) as item()*
+fStaticContext_defineSystemFunction("subsequence",	[[cXTItem, '*'], [cXSDouble, ''], [cXSDouble, '', true]],	function(oSequence1, oStart, oLength) {
+	var nPosition	= cMath.round(oStart),
+		nLength		= arguments.length > 2 ? cMath.round(oLength) : oSequence1.length - nPosition + 1;
+
+	// TODO: Handle out-of-range position and length values
+	return oSequence1.slice(nPosition - 1, nPosition - 1 + nLength);
+});
+
+// fn:unordered($sourceSeq as item()*) as item()*
+fStaticContext_defineSystemFunction("unordered",	[[cXTItem, '*']],	function(oSequence1) {
+	return oSequence1;
+});
+
+
+// 15.2 Functions That Test the Cardinality of Sequences
+// fn:zero-or-one($arg as item()*) as item()?
+fStaticContext_defineSystemFunction("zero-or-one",	[[cXTItem, '*']],	function(oSequence1) {
+	if (oSequence1.length > 1)
+		throw new cException("FORG0003");
+
+	return oSequence1;
+});
+
+// fn:one-or-more($arg as item()*) as item()+
+fStaticContext_defineSystemFunction("one-or-more",	[[cXTItem, '*']],	function(oSequence1) {
+	if (!oSequence1.length)
+		throw new cException("FORG0004");
+
+	return oSequence1;
+});
+
+// fn:exactly-one($arg as item()*) as item()
+fStaticContext_defineSystemFunction("exactly-one",	[[cXTItem, '*']],	function(oSequence1) {
+	if (oSequence1.length != 1)
+		throw new cException("FORG0005");
+
+	return oSequence1;
+});
+
+
+// 15.3 Equals, Union, Intersection and Except
+// fn:deep-equal($parameter1 as item()*, $parameter2 as item()*) as xs:boolean
+// fn:deep-equal($parameter1 as item()*, $parameter2 as item()*, $collation as string) as xs:boolean
+fStaticContext_defineSystemFunction("deep-equal",	[[cXTItem, '*'], [cXTItem, '*'], [cXSString, '', true]],	function(oSequence1, oSequence2, oCollation) {
+	throw "Function '" + "deep-equal" + "' not implemented";
+});
+
+
+// 15.4 Aggregate Functions
+// fn:count($arg as item()*) as xs:integer
+fStaticContext_defineSystemFunction("count",	[[cXTItem, '*']],	function(oSequence1) {
+	return new cXSInteger(oSequence1.length);
+});
+
+// fn:avg($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("avg",	[[cXSAnyAtomicType, '*']],	function(oSequence1) {
+	if (!oSequence1.length)
+		return null;
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			vValue	= hAdditiveExpr_operators['+'](vValue, vRight, this);
+		}
+		return hMultiplicativeExpr_operators['div'](vValue, new cXSInteger(nLength), this);
+	}
+	catch (e) {
+		// XPTY0004: Arithmetic operator is not defined for provided arguments
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:max($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+// fn:max($arg as xs:anyAtomicType*, $collation as string) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("max",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (!oSequence1.length)
+		return null;
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			if (hComparisonExpr_ValueComp_operators['ge'](vRight, vValue, this).valueOf())
+				vValue	= vRight;
+		}
+		return vValue;
+	}
+	catch (e) {
+		// XPTY0004: Cannot compare {type1} with {type2}
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:min($arg as xs:anyAtomicType*) as xs:anyAtomicType?
+// fn:min($arg as xs:anyAtomicType*, $collation as string) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("min",	[[cXSAnyAtomicType, '*'], [cXSString, '', true]],	function(oSequence1, oCollation) {
+	if (!oSequence1.length)
+		return null;
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			if (hComparisonExpr_ValueComp_operators['le'](vRight, vValue, this).valueOf())
+				vValue	= vRight;
+			}
+		return vValue;
+	}
+	catch (e) {
+		// Cannot compare {type1} with {type2}
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+// fn:sum($arg as xs:anyAtomicType*) as xs:anyAtomicType
+// fn:sum($arg as xs:anyAtomicType*, $zero as xs:anyAtomicType?) as xs:anyAtomicType?
+fStaticContext_defineSystemFunction("sum",	[[cXSAnyAtomicType, '*'], [cXSAnyAtomicType, '?', true]],	function(oSequence1, oZero) {
+	if (!oSequence1.length) {
+		if (arguments.length > 1)
+			return oZero;
+		else
+			return new cXSDouble(0);
+
+		return null;
+	}
+
+	// TODO: Implement collation
+
+	//
+	try {
+		var vValue	= oSequence1[0];
+		if (vValue instanceof cXSUntypedAtomic)
+			vValue	= cXSDouble.cast(vValue);
+		for (var nIndex = 1, nLength = oSequence1.length, vRight; nIndex < nLength; nIndex++) {
+			vRight	= oSequence1[nIndex];
+			if (vRight instanceof cXSUntypedAtomic)
+				vRight	= cXSDouble.cast(vRight);
+			vValue	= hAdditiveExpr_operators['+'](vValue, vRight, this);
+		}
+		return vValue;
+	}
+	catch (e) {
+		// XPTY0004: Arithmetic operator is not defined for provided arguments
+		throw e.code != "XPTY0004" ? e : new cException("FORG0006"
+
+		);
+	}
+});
+
+
+// 15.5 Functions and Operators that Generate Sequences
+// fn:id($arg as xs:string*) as element()*
+// fn:id($arg as xs:string*, $node as node()) as element()*
+fStaticContext_defineSystemFunction("id",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	if (arguments.length < 2) {
+		if (!this.DOMAdapter.isNode(this.item))
+			throw new cException("XPTY0004"
+
+			);
+		oNode	= this.item;
+	}
+
+	// Get root node and check if it is Document
+	var oDocument	= hStaticContext_functions["root"].call(this, oNode);
+	if (this.DOMAdapter.getProperty(oDocument, "nodeType") != 9)
+		throw new cException("FODC0001");
+
+	// Search for elements
+	var oSequence	= [];
+	for (var nIndex = 0; nIndex < oSequence1.length; nIndex++)
+		for (var nRightIndex = 0, aValue = fString_trim(oSequence1[nIndex]).split(/\s+/), nRightLength = aValue.length; nRightIndex < nRightLength; nRightIndex++)
+			if ((oNode = this.DOMAdapter.getElementById(oDocument, aValue[nRightIndex])) && fArray_indexOf(oSequence, oNode) ==-1)
+				oSequence.push(oNode);
+	//
+	return fFunction_sequence_order(oSequence, this);
+});
+
+// fn:idref($arg as xs:string*) as node()*
+// fn:idref($arg as xs:string*, $node as node()) as node()*
+fStaticContext_defineSystemFunction("idref",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	throw "Function '" + "idref" + "' not implemented";
+});
+
+// fn:doc($uri as xs:string?) as document-node()?
+fStaticContext_defineSystemFunction("doc",			[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "doc" + "' not implemented";
+});
+
+// fn:doc-available($uri as xs:string?) as xs:boolean
+fStaticContext_defineSystemFunction("doc-available",	[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "doc-available" + "' not implemented";
+});
+
+// fn:collection() as node()*
+// fn:collection($arg as xs:string?) as node()*
+fStaticContext_defineSystemFunction("collection",	[[cXSString, '?', true]],	function(oUri) {
+	throw "Function '" + "collection" + "' not implemented";
+});
+
+// fn:element-with-id($arg as xs:string*) as element()*
+// fn:element-with-id($arg as xs:string*, $node as node()) as element()*
+fStaticContext_defineSystemFunction("element-with-id",	[[cXSString, '*'], [cXTNode, '', true]],	function(oSequence1, oNode) {
+	throw "Function '" + "element-with-id" + "' not implemented";
+});
+
+// EBV calculation
+function fFunction_sequence_toEBV(oSequence1, oContext) {
+	if (!oSequence1.length)
+		return false;
+
+	var oItem	= oSequence1[0];
+	if (oContext.DOMAdapter.isNode(oItem))
+		return true;
+
+	if (oSequence1.length == 1) {
+		if (oItem instanceof cXSBoolean)
+			return oItem.value.valueOf();
+		if (oItem instanceof cXSString)
+			return !!oItem.valueOf().length;
+		if (fXSAnyAtomicType_isNumeric(oItem))
+			return !(fIsNaN(oItem.valueOf()) || oItem.valueOf() == 0);
+
+		throw new cException("FORG0006"
+
+		);
+	}
+
+	throw new cException("FORG0006"
+
+	);
+};
+
+function fFunction_sequence_atomize(oSequence1, oContext) {
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = oSequence1.length, oItem, vItem; nIndex < nLength; nIndex++) {
+		oItem	= oSequence1[nIndex];
+		vItem	= null;
+		// Untyped
+		if (oItem == null)
+			vItem	= null;
+		// Node type
+		else
+		if (oContext.DOMAdapter.isNode(oItem)) {
+			var fGetProperty	= oContext.DOMAdapter.getProperty;
+			switch (fGetProperty(oItem, "nodeType")) {
+				case 1:	// ELEMENT_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "textContent"));
+					break;
+				case 2:	// ATTRIBUTE_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "value"));
+					break;
+				case 3:	// TEXT_NODE
+				case 4:	// CDATA_SECTION_NODE
+				case 8:	// COMMENT_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "data"));
+					break;
+				case 7:	// PROCESSING_INSTRUCTION_NODE
+					vItem	= new cXSUntypedAtomic(fGetProperty(oItem, "data"));
+					break;
+				case 9:	// DOCUMENT_NODE
+					var oNode	= fGetProperty(oItem, "documentElement");
+					vItem	= new cXSUntypedAtomic(oNode ? fGetProperty(oNode, "textContent") : '');
+					break;
+			}
+		}
+		// Base types
+		else
+		if (oItem instanceof cXSAnyAtomicType)
+			vItem	= oItem;
+
+		//
+		if (vItem != null)
+			oSequence.push(vItem);
+	}
+
+	return oSequence;
+};
+
+// Orders items in sequence in document order
+function fFunction_sequence_order(oSequence1, oContext) {
+	return oSequence1.sort(function(oNode, oNode2) {
+		var nPosition	= oContext.DOMAdapter.compareDocumentPosition(oNode, oNode2);
+		return nPosition & 2 ? 1 : nPosition & 4 ?-1 : 0;
+	});
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	7.2 Functions to Assemble and Disassemble Strings
+		codepoints-to-string
+		string-to-codepoints
+
+	7.3 Equality and Comparison of Strings
+		compare
+		codepoint-equal
+
+	7.4 Functions on String Values
+		concat
+		string-join
+		substring
+		string-length
+		normalize-space
+		normalize-unicode
+		upper-case
+		lower-case
+		translate
+		encode-for-uri
+		iri-to-uri
+		escape-html-uri
+
+	7.5 Functions Based on Substring Matching
+		contains
+		starts-with
+		ends-with
+		substring-before
+		substring-after
+
+	7.6 String Functions that Use Pattern Matching
+		matches
+		replace
+		tokenize
+*/
+
+// 7.2 Functions to Assemble and Disassemble Strings
+// fn:codepoints-to-string($arg as xs:integer*) as xs:string
+fStaticContext_defineSystemFunction("codepoints-to-string",	[[cXSInteger, '*']],	function(oSequence1) {
+	var aValue	= [];
+	for (var nIndex = 0, nLength = oSequence1.length; nIndex < nLength; nIndex++)
+		aValue.push(cString.fromCharCode(oSequence1[nIndex]));
+
+	return new cXSString(aValue.join(''));
+});
+
+// fn:string-to-codepoints($arg as xs:string?) as xs:integer*
+fStaticContext_defineSystemFunction("string-to-codepoints",	[[cXSString, '?']],	function(oValue) {
+	if (oValue == null)
+		return null;
+
+	var sValue	= oValue.valueOf();
+	if (sValue == '')
+		return [];
+
+	var oSequence	= [];
+	for (var nIndex = 0, nLength = sValue.length; nIndex < nLength; nIndex++)
+		oSequence.push(new cXSInteger(sValue.charCodeAt(nIndex)));
+
+	return oSequence;
+});
+
+// 7.3 Equality and Comparison of Strings
+// fn:compare($comparand1 as xs:string?, $comparand2 as xs:string?) as xs:integer?
+// fn:compare($comparand1 as xs:string?, $comparand2 as xs:string?, $collation as xs:string) as xs:integer?
+fStaticContext_defineSystemFunction("compare",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue1, oValue2, oCollation) {
+	if (oValue1 == null || oValue2 == null)
+		return null;
+
+	var sCollation	= this.staticContext.defaultCollationName,
+		vCollation;
+	if (arguments.length > 2)
+		sCollation	= oCollation.valueOf();
+
+	vCollation	= sCollation == sNS_XPF + "/collation/codepoint" ? oCodepointStringCollator : this.staticContext.getCollation(sCollation);
+	if (!vCollation)
+		throw new cException("FOCH0002"
+
+		);
+
+	return new cXSInteger(vCollation.compare(oValue1.valueOf(), oValue2.valueOf()));
+});
+
+// fn:codepoint-equal($comparand1 as xs:string?, $comparand2  as xs:string?) as xs:boolean?
+fStaticContext_defineSystemFunction("codepoint-equal",	[[cXSString, '?'], [cXSString, '?']],	function(oValue1, oValue2) {
+	if (oValue1 == null || oValue2 == null)
+		return null;
+
+	// TODO: Check if JS uses 'Unicode code point collation' here
+
+	return new cXSBoolean(oValue1.valueOf() == oValue2.valueOf());
+});
+
+
+// 7.4 Functions on String Values
+// fn:concat($arg1 as xs:anyAtomicType?, $arg2 as xs:anyAtomicType?, ...) as xs:string
+fStaticContext_defineSystemFunction("concat",	null,	function() {
+	// check arguments length
+	if (arguments.length < 2)
+		throw new cException("XPST0017"
+
+		);
+
+	var aValue	= [];
+	for (var nIndex = 0, nLength = arguments.length, oSequence; nIndex < nLength; nIndex++) {
+		oSequence	= arguments[nIndex];
+		// Assert cardinality
+		fFunctionCall_assertSequenceCardinality(this, oSequence, '?'
+
+		);
+		//
+		if (oSequence.length)
+			aValue[aValue.length]	= cXSString.cast(fFunction_sequence_atomize(oSequence, this)[0]).valueOf();
+	}
+
+	return new cXSString(aValue.join(''));
+});
+
+// fn:string-join($arg1 as xs:string*, $arg2 as xs:string) as xs:string
+fStaticContext_defineSystemFunction("string-join",	[[cXSString, '*'], [cXSString]],	function(oSequence1, oValue) {
+	return new cXSString(oSequence1.join(oValue));
+});
+
+// fn:substring($sourceString as xs:string?, $startingLoc as xs:double) as xs:string
+// fn:substring($sourceString as xs:string?, $startingLoc as xs:double, $length as xs:double) as xs:string
+fStaticContext_defineSystemFunction("substring",	[[cXSString, '?'], [cXSDouble], [cXSDouble, '', true]],	function(oValue, oStart, oLength) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		nStart	= cMath.round(oStart) - 1,
+		nEnd	= arguments.length > 2 ? nStart + cMath.round(oLength) : sValue.length;
+
+	// TODO: start can be negative
+	return new cXSString(nEnd > nStart ? sValue.substring(nStart, nEnd) : '');
+});
+
+// fn:string-length() as xs:integer
+// fn:string-length($arg as xs:string?) as xs:integer
+fStaticContext_defineSystemFunction("string-length",	[[cXSString, '?', true]],	function(oValue) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oValue	= cXSString.cast(fFunction_sequence_atomize([this.item], this)[0]);
+	}
+	return new cXSInteger(oValue == null ? 0 : oValue.valueOf().length);
+});
+
+// fn:normalize-space() as xs:string
+// fn:normalize-space($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("normalize-space",	[[cXSString, '?', true]],	function(oValue) {
+	if (!arguments.length) {
+		if (!this.item)
+			throw new cException("XPDY0002");
+		oValue	= cXSString.cast(fFunction_sequence_atomize([this.item], this)[0]);
+	}
+	return new cXSString(oValue == null ? '' : fString_trim(oValue).replace(/\s\s+/g, ' '));
+});
+
+// fn:normalize-unicode($arg as xs:string?) as xs:string
+// fn:normalize-unicode($arg as xs:string?, $normalizationForm as xs:string) as xs:string
+fStaticContext_defineSystemFunction("normalize-unicode",	[[cXSString, '?'], [cXSString, '', true]],	function(oValue, oNormalization) {
+	throw "Function '" + "normalize-unicode" + "' not implemented";
+});
+
+// fn:upper-case($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("upper-case",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : oValue.valueOf().toUpperCase());
+});
+
+// fn:lower-case($arg as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("lower-case",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : oValue.valueOf().toLowerCase());
+});
+
+// fn:translate($arg as xs:string?, $mapString as xs:string, $transString as xs:string) as xs:string
+fStaticContext_defineSystemFunction("translate",	[[cXSString, '?'], [cXSString], [cXSString]],	function(oValue, oMap, oTranslate) {
+	if (oValue == null)
+		return new cXSString('');
+
+	var aValue	= oValue.valueOf().split(''),
+		aMap	= oMap.valueOf().split(''),
+		aTranslate	= oTranslate.valueOf().split(''),
+		nTranslateLength	= aTranslate.length,
+		aReturn	= [];
+	for (var nIndex = 0, nLength = aValue.length, nPosition; nIndex < nLength; nIndex++)
+		if ((nPosition = aMap.indexOf(aValue[nIndex])) ==-1)
+			aReturn[aReturn.length]	= aValue[nIndex];
+		else
+		if (nPosition < nTranslateLength)
+			aReturn[aReturn.length]	= aTranslate[nPosition];
+
+	return new cXSString(aReturn.join(''));
+});
+
+// fn:encode-for-uri($uri-part as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("encode-for-uri",	[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : window.encodeURIComponent(oValue));
+});
+
+// fn:iri-to-uri($iri as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("iri-to-uri",		[[cXSString, '?']],	function(oValue) {
+	return new cXSString(oValue == null ? '' : window.encodeURI(window.decodeURI(oValue)));
+});
+
+// fn:escape-html-uri($uri as xs:string?) as xs:string
+fStaticContext_defineSystemFunction("escape-html-uri",	[[cXSString, '?']],	function(oValue) {
+	if (oValue == null || oValue.valueOf() == '')
+		return new cXSString('');
+	// Encode
+	var aValue	= oValue.valueOf().split('');
+	for (var nIndex = 0, nLength = aValue.length, nCode; nIndex < nLength; nIndex++)
+		if ((nCode = aValue[nIndex].charCodeAt(0)) < 32 || nCode > 126)
+			aValue[nIndex]	= window.encodeURIComponent(aValue[nIndex]);
+	return new cXSString(aValue.join(''));
+});
+
+
+// 7.5 Functions Based on Substring Matching
+// fn:contains($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:contains($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("contains",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "contains" + "' is not implemented";
+	return new cXSBoolean((oValue == null ? '' : oValue.valueOf()).indexOf(oSearch == null ? '' : oSearch.valueOf()) >= 0);
+});
+
+// fn:starts-with($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:starts-with($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("starts-with",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "starts-with" + "' is not implemented";
+	return new cXSBoolean((oValue == null ? '' : oValue.valueOf()).indexOf(oSearch == null ? '' : oSearch.valueOf()) == 0);
+});
+
+// fn:ends-with($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean
+// fn:ends-with($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("ends-with",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "ends-with" + "' is not implemented";
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf();
+
+	return new cXSBoolean(sValue.indexOf(sSearch) == sValue.length - sSearch.length);
+});
+
+// fn:substring-before($arg1 as xs:string?, $arg2 as xs:string?) as xs:string
+// fn:substring-before($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:string
+fStaticContext_defineSystemFunction("substring-before",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "substring-before" + "' is not implemented";
+
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf(),
+		nPosition;
+
+	return new cXSString((nPosition = sValue.indexOf(sSearch)) >= 0 ? sValue.substring(0, nPosition) : '');
+});
+
+// fn:substring-after($arg1 as xs:string?, $arg2 as xs:string?) as xs:string
+// fn:substring-after($arg1 as xs:string?, $arg2 as xs:string?, $collation as xs:string) as xs:string
+fStaticContext_defineSystemFunction("substring-after",	[[cXSString, '?'], [cXSString, '?'], [cXSString, '', true]],	function(oValue, oSearch, oCollation) {
+	if (arguments.length > 2)
+		throw "Collation parameter in function '" + "substring-after" + "' is not implemented";
+
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		sSearch	= oSearch == null ? '' : oSearch.valueOf(),
+		nPosition;
+
+	return new cXSString((nPosition = sValue.indexOf(sSearch)) >= 0 ? sValue.substring(nPosition + sSearch.length) : '');
+});
+
+
+// 7.6 String Functions that Use Pattern Matching
+function fFunction_string_createRegExp(sValue, sFlags) {
+	var d1	= '\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF',
+		d2	= '\u0370-\u037D\u037F-\u1FFF\u200C-\u200D',
+		d3	= '\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD',
+		c	= 'A-Z_a-z\\-.0-9\u00B7' + d1 + '\u0300-\u036F' + d2 + '\u203F-\u2040' + d3,
+		i	= 'A-Z_a-z' + d1 + d2 + d3;
+
+	sValue	= sValue
+				.replace(/\[\\i-\[:\]\]/g, '[' + i + ']')
+				.replace(/\[\\c-\[:\]\]/g, '[' + c + ']')
+				.replace(/\\i/g, '[:' + i + ']')
+				.replace(/\\I/g, '[^:' + i + ']')
+				.replace(/\\c/g, '[:' + c + ']')
+				.replace(/\\C/g, '[^:' + c + ']');
+
+	// Check if all flags are legal
+	if (sFlags && !sFlags.match(/^[smix]+$/))
+		throw new cException("FORX0001");	// Invalid character '{%0}' in regular expression flags
+
+	var bFlagS	= sFlags.indexOf('s') >= 0,
+		bFlagX	= sFlags.indexOf('x') >= 0;
+	if (bFlagS || bFlagX) {
+		// Strip 's' and 'x' from flags
+		sFlags	= sFlags.replace(/[sx]/g, '');
+		var aValue	= [],
+			rValue	= /\s/;
+		for (var nIndex = 0, nLength = sValue.length, bValue = false, sCharCurr, sCharPrev = ''; nIndex < nLength; nIndex++) {
+			sCharCurr	= sValue.charAt(nIndex);
+			if (sCharPrev != '\\') {
+				if (sCharCurr == '[')
+					bValue	= true;
+				else
+				if (sCharCurr == ']')
+					bValue	= false;
+			}
+			// Replace '\s' for flag 'x' if not in []
+			if (bValue || !(bFlagX && rValue.test(sCharCurr))) {
+				// Replace '.' for flag 's' if not in []
+				if (!bValue && (bFlagS && sCharCurr == '.' && sCharPrev != '\\'))
+					aValue[aValue.length]	= '(?:.|\\s)';
+				else
+					aValue[aValue.length]	= sCharCurr;
+			}
+			sCharPrev	= sCharCurr;
+		}
+		sValue	= aValue.join('');
+	}
+
+	return new cRegExp(sValue, sFlags + 'g');
+};
+
+// fn:matches($input as xs:string?, $pattern as xs:string) as xs:boolean
+// fn:matches($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:boolean
+fStaticContext_defineSystemFunction("matches",	[[cXSString, '?'], [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 2 ? oFlags.valueOf() : '');
+
+	return new cXSBoolean(rRegExp.test(sValue));
+});
+
+// fn:replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string) as xs:string
+// fn:replace($input as xs:string?, $pattern as xs:string, $replacement as xs:string, $flags as xs:string) as xs:string
+fStaticContext_defineSystemFunction("replace",	[[cXSString, '?'], [cXSString],  [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oReplacement, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 3 ? oFlags.valueOf() : '');
+
+	return new cXSBoolean(sValue.replace(rRegExp, oReplacement.valueOf()));
+});
+
+// fn:tokenize($input as xs:string?, $pattern as xs:string) as xs:string*
+// fn:tokenize($input as xs:string?, $pattern as xs:string, $flags as xs:string) as xs:string*
+fStaticContext_defineSystemFunction("tokenize",	[[cXSString, '?'], [cXSString], [cXSString, '', true]],	function(oValue, oPattern, oFlags) {
+	var sValue	= oValue == null ? '' : oValue.valueOf(),
+		rRegExp	= fFunction_string_createRegExp(oPattern.valueOf(), arguments.length > 2 ? oFlags.valueOf() : '');
+
+	var oSequence	= [];
+	for (var nIndex = 0, aValue = sValue.split(rRegExp), nLength = aValue.length; nIndex < nLength; nIndex++)
+		oSequence.push(new cXSString(aValue[nIndex]));
+
+	return oSequence;
+});
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+/*
+	4 The Trace Function
+		trace
+*/
+
+// fn:trace($value as item()*, $label as xs:string) as item()*
+fStaticContext_defineSystemFunction("trace",		[[cXTItem, '*'], [cXSString]],	function(oSequence1, oLabel) {
+	var oConsole	= window.console;
+	if (oConsole && oConsole.log)
+		oConsole.log(oLabel.valueOf(), oSequence1);
+	return oSequence1;
+});
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+var oCodepointStringCollator	= new cStringCollator;
+
+oCodepointStringCollator.equals	= function(sValue1, sValue2) {
+	return sValue1 == sValue2;
+};
+
+oCodepointStringCollator.compare	= function(sValue1, sValue2) {
+	return sValue1 == sValue2 ? 0 : sValue1 > sValue2 ? 1 :-1;
+};
+function cLXDOMAdapter() {
+
+};
+
+cLXDOMAdapter.prototype	= new cDOMAdapter;
+
+var oLXDOMAdapter_staticContext	= new cStaticContext;
+
+cLXDOMAdapter.prototype.getProperty	= function(oNode, sName) {
+		if (sName in oNode)
+		return oNode[sName];
+
+		if (sName == "baseURI") {
+		var sBaseURI	= '',
+			fResolveUri	= oLXDOMAdapter_staticContext.getFunction('{' + "http://www.w3.org/2005/xpath-functions" + '}' + "resolve-uri"),
+			cXSString	= oLXDOMAdapter_staticContext.getDataType('{' + "http://www.w3.org/2001/XMLSchema" + '}' + "string");
+
+		for (var oParent = oNode, sUri; oParent; oParent = oParent.parentNode)
+			if (oParent.nodeType == 1  && (sUri = oParent.getAttribute("xml:base")))
+				sBaseURI	= fResolveUri(new cXSString(sUri), new cXSString(sBaseURI)).toString();
+				return sBaseURI;
+	}
+	else
+	if (sName == "textContent") {
+		var aText = [];
+		(function(oNode) {
+			for (var nIndex = 0, oChild; oChild = oNode.childNodes[nIndex]; nIndex++)
+				if (oChild.nodeType == 3  || oChild.nodeType == 4 )
+					aText.push(oChild.data);
+				else
+				if (oChild.nodeType == 1  && oChild.firstChild)
+					arguments.callee(oChild);
+		})(oNode);
+		return aText.join('');
+	}
+};
+
+cLXDOMAdapter.prototype.compareDocumentPosition	= function(oNode, oChild) {
+		if ("compareDocumentPosition" in oNode)
+		return oNode.compareDocumentPosition(oChild);
+
+		if (oChild == oNode)
+		return 0;
+
+		var oAttr1	= null,
+		oAttr2	= null,
+		aAttributes,
+		oAttr, oElement, nIndex, nLength;
+	if (oNode.nodeType == 2 ) {
+		oAttr1	= oNode;
+		oNode	= this.getProperty(oAttr1, "ownerElement");
+	}
+	if (oChild.nodeType == 2 ) {
+		oAttr2	= oChild;
+		oChild	= this.getProperty(oAttr2, "ownerElement");
+	}
+
+		if (oAttr1 && oAttr2 && oNode && oNode == oChild) {
+		for (nIndex = 0, aAttributes = this.getProperty(oNode, "attributes"), nLength = aAttributes.length; nIndex < nLength; nIndex++) {
+			oAttr	= aAttributes[nIndex];
+			if (oAttr == oAttr1)
+				return 32  | 4 ;
+			if (oAttr == oAttr2)
+				return 32  | 2 ;
+		}
+	}
+
+		var aChain1	= [], nLength1, oNode1,
+		aChain2	= [], nLength2, oNode2;
+		if (oAttr1)
+		aChain1.push(oAttr1);
+	for (oElement = oNode; oElement; oElement = oElement.parentNode)
+		aChain1.push(oElement);
+	if (oAttr2)
+		aChain2.push(oAttr2);
+	for (oElement = oChild; oElement; oElement = oElement.parentNode)
+		aChain2.push(oElement);
+		if (((oNode.ownerDocument || oNode) != (oChild.ownerDocument || oChild)) || (aChain1[aChain1.length - 1] != aChain2[aChain2.length - 1]))
+		return 32  | 1 ;
+		for (nIndex = cMath.min(nLength1 = aChain1.length, nLength2 = aChain2.length); nIndex; --nIndex)
+		if ((oNode1 = aChain1[--nLength1]) != (oNode2 = aChain2[--nLength2])) {
+						if (oNode1.nodeType == 2 )
+				return 4 ;
+			if (oNode2.nodeType == 2 )
+				return 2 ;
+						if (!oNode2.nextSibling)
+				return 4 ;
+			if (!oNode1.nextSibling)
+				return 2 ;
+			for (oElement = oNode2.previousSibling; oElement; oElement = oElement.previousSibling)
+				if (oElement == oNode1)
+					return 4 ;
+			return 2 ;
+		}
+		return nLength1 < nLength2 ? 4  | 16  : 2  | 8 ;
+};
+
+cLXDOMAdapter.prototype.lookupNamespaceURI	= function(oNode, sPrefix) {
+		if ("lookupNamespaceURI" in oNode)
+		return oNode.lookupNamespaceURI(sPrefix);
+
+		for (; oNode && oNode.nodeType != 9  ; oNode = oNode.parentNode)
+		if (sPrefix == this.getProperty(oChild, "prefix"))
+			return this.getProperty(oNode, "namespaceURI");
+		else
+		if (oNode.nodeType == 1)				for (var oAttributes = this.getProperty(oNode, "attributes"), nIndex = 0, nLength = oAttributes.length, sName = "xmlns" + ':' + sPrefix; nIndex < nLength; nIndex++)
+				if (this.getProperty(oAttributes[nIndex], "nodeName") == sName)
+					return this.getProperty(oAttributes[nIndex], "value");
+	return null;
+};
+
+cLXDOMAdapter.prototype.getElementsByTagNameNS	= function(oNode, sNameSpaceURI, sLocalName) {
+		if ("getElementsByTagNameNS" in oNode)
+		return oNode.getElementsByTagNameNS(sNameSpaceURI, sLocalName);
+
+		var aElements	= [],
+		bNameSpaceURI	= '*' == sNameSpaceURI,
+		bLocalName		= '*' == sLocalName;
+	(function(oNode) {
+		for (var nIndex = 0, oChild; oChild = oNode.childNodes[nIndex]; nIndex++)
+			if (oChild.nodeType == 1) {					if ((bLocalName || sLocalName == this.getProperty(oChild, "localName")) && (bNameSpaceURI || sNameSpaceURI == this.getProperty(oChild, "namespaceURI")))
+					aElements[aElements.length]	= oChild;
+				if (oChild.firstChild)
+					arguments.callee(oChild);
+			}
+	})(oNode);
+	return aElements;
+};
+
+var oMSHTMLDOMAdapter	= new cLXDOMAdapter;
+
+oMSHTMLDOMAdapter.getProperty	= function(oNode, sName) {
+	if (sName == "localName") {
+		if (oNode.nodeType == 1)
+			return oNode.nodeName.toLowerCase();
+	}
+	if (sName == "prefix")
+		return null;
+	if (sName == "namespaceURI")
+		return oNode.nodeType == 1 ? "http://www.w3.org/1999/xhtml" : null;
+	if (sName == "textContent")
+		return oNode.innerText;
+	if (sName == "attributes" && oNode.nodeType == 1) {
+		var aAttributes	= [];
+		for (var nIndex = 0, oAttributes = oNode.attributes, nLength = oAttributes.length, oNode2, oAttribute; nIndex < nLength; nIndex++) {
+			oNode2	= oAttributes[nIndex];
+			if (oNode2.specified) {
+				oAttribute	= new cAttr;
+				oAttribute.ownerElement	= oNode;
+				oAttribute.ownerDocument= oNode.ownerDocument;
+				oAttribute.specified	= true;
+				oAttribute.value		=
+				oAttribute.nodeValue	= oNode2.nodeValue;
+				oAttribute.name			=
+				oAttribute.nodeName		=
+								oAttribute.localName	= oNode2.nodeName.toLowerCase();
+								aAttributes[aAttributes.length]	= oAttribute;
+			}
+		}
+		return aAttributes;
+	}
+		return cLXDOMAdapter.prototype.getProperty.call(this, oNode, sName);
+};
+
+
+var oMSXMLDOMAdapter	= new cLXDOMAdapter;
+
+oMSXMLDOMAdapter.getProperty	= function(oNode, sName) {
+	if (sName == "localName") {
+		if (oNode.nodeType == 7)
+			return null;
+		if (oNode.nodeType == 1)
+			return oNode.baseName;
+	}
+	if (sName == "prefix" || sName == "namespaceURI")
+		return oNode[sName] || null;
+	if (sName == "textContent")
+		return oNode.text;
+	if (sName == "attributes" && oNode.nodeType == 1) {
+		var aAttributes	= [];
+		for (var nIndex = 0, oAttributes = oNode.attributes, nLength = oAttributes.length, oNode2, oAttribute; nIndex < nLength; nIndex++) {
+			oNode2	= oAttributes[nIndex];
+			if (oNode2.specified) {
+				oAttribute	= new cAttr;
+				oAttribute.nodeType		= 2;
+				oAttribute.ownerElement	= oNode;
+				oAttribute.ownerDocument= oNode.ownerDocument;
+				oAttribute.specified	= true;
+				oAttribute.value		=
+				oAttribute.nodeValue	= oNode2.nodeValue;
+				oAttribute.name			=
+				oAttribute.nodeName		= oNode2.nodeName;
+								oAttribute.localName	= oNode2.baseName;
+				oAttribute.prefix		= oNode2.prefix || null;
+				oAttribute.namespaceURI	= oNode2.namespaceURI || null;
+								aAttributes[aAttributes.length]	= oAttribute;
+			}
+		}
+		return aAttributes;
+	}
+		return cLXDOMAdapter.prototype.getProperty.call(this, oNode, sName);
+};
+
+oMSXMLDOMAdapter.getElementById	= function(oDocument, sId) {
+	return oDocument.nodeFromID(sId);
+};
+
+function cEvaluator() {
+
+};
+
+cEvaluator.prototype.defaultOL2DOMAdapter		= new cLXDOMAdapter;
+cEvaluator.prototype.defaultOL2HTMLDOMAdapter	= new cLXDOMAdapter;
+
+cEvaluator.prototype.defaultHTMLStaticContext	= new cStaticContext;
+cEvaluator.prototype.defaultHTMLStaticContext.baseURI	= window.document.location.href;
+cEvaluator.prototype.defaultHTMLStaticContext.defaultFunctionNamespace	= "http://www.w3.org/2005/xpath-functions";
+cEvaluator.prototype.defaultHTMLStaticContext.defaultElementNamespace	= "http://www.w3.org/1999/xhtml";
+
+cEvaluator.prototype.defaultXMLStaticContext	= new cStaticContext;
+cEvaluator.prototype.defaultXMLStaticContext.defaultFunctionNamespace	= "http://www.w3.org/2005/xpath-functions";
+
+cEvaluator.prototype.bOldMS		= !!window.document.namespaces && !window.document.createElementNS;
+cEvaluator.prototype.bOldW3		= !cEvaluator.prototype.bOldMS && window.document.documentElement.namespaceURI != "http://www.w3.org/1999/xhtml";
+
+cEvaluator.prototype.defaultDOMAdapter		= new cDOMAdapter;
+
+cEvaluator.prototype.compile	= function(sExpression, oStaticContext) {
+    return new cExpression(sExpression, oStaticContext);
+};
+
+cEvaluator.prototype.evaluate	= function(oQuery, sExpression, fNSResolver) {
+	if (! (oQuery instanceof window.jQuery))
+        oQuery = new window.jQuery(oQuery)
+
+    if (typeof sExpression == "undefined" || sExpression === null)
+        sExpression	= '';
+
+    var oNode	= oQuery[0];
+    if (typeof oNode == "undefined")
+        oNode	= null;
+
+    var oStaticContext	= oNode && (oNode.nodeType == 9 ? oNode : oNode.ownerDocument).createElement("div").tagName == "DIV" ? this.defaultHTMLStaticContext : this.defaultXMLStaticContext;
+
+    oStaticContext.namespaceResolver	= fNSResolver;
+
+    var oExpression	= new cExpression(cString(sExpression), oStaticContext);
+
+    oStaticContext.namespaceResolver	= null;
+
+    var aSequence,
+        oSequence	= new window.jQuery,
+        oAdapter	= this.defaultOL2DOMAdapter;
+
+    if (this.bOldMS)
+        oAdapter	= oStaticContext == this.defaultHTMLStaticContext ? oMSHTMLDOMAdapter : oMSXMLDOMAdapter;
+    else
+    if (this.bOldW3 && oStaticContext == this.defaultHTMLStaticContext)
+        oAdapter	= this.defaultOL2HTMLDOMAdapter;
+
+    aSequence	= oExpression.evaluate(new cDynamicContext(oStaticContext, oNode, null, oAdapter));
+    for (var nIndex = 0, nLength = aSequence.length, oItem; nIndex < nLength; nIndex++)
+        oSequence.push(oAdapter.isNode(oItem = aSequence[nIndex]) ? oItem : cStaticContext.xs2js(oItem));
+
+    return oSequence;
+};
+
+/*
+ * XPath.js - Pure JavaScript implementation of XPath 2.0 parser and evaluator
+ *
+ * Copyright (c) 2012 Sergey Ilinsky
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ *
+ */
+
+var oXPathEvaluator	= new cEvaluator,
+    oXPathClasses	= oXPathEvaluator.classes = {};
+
+//
+oXPathClasses.Exception		= cException;
+oXPathClasses.Expression	= cExpression;
+oXPathClasses.DOMAdapter	= cDOMAdapter;
+oXPathClasses.StaticContext	= cStaticContext;
+oXPathClasses.DynamicContext= cDynamicContext;
+oXPathClasses.StringCollator= cStringCollator;
+
+// Publish object
+window.xpath	= oXPathEvaluator;
+
+})()

+ 117 - 2
src/js/operations/Extract.js

@@ -1,3 +1,5 @@
+/* globals xpath */
+
 /**
  * Identifier extraction operations.
  *
@@ -10,7 +12,7 @@
 var Extract = {
 
     /**
-     * Runs search operations across the input data using refular expressions.
+     * Runs search operations across the input data using regular expressions.
      *
      * @private
      * @param {string} input
@@ -293,5 +295,118 @@ var Extract = {
         output += Extract.run_dates(input, []);
         return output;
     },
-    
+
+    /**
+     * @constant
+     * @default
+     */
+    XPATH_INITIAL: "",
+
+    /**
+     * @constant
+     * @default
+     */
+    XPATH_DELIMITER: "\\n",
+
+    /**
+     * Extract information (from an xml document) with an XPath query
+     *
+     * @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run_xpath:function(input, args) {
+        const query = args[0];
+        const delimiter = args[1];
+
+        var xml;
+        try {
+            xml = $.parseXML(input);
+        } catch (err) {
+            return "Invalid input XML.";
+        }
+
+        var result;
+        try {
+            result = xpath.evaluate(xml, query);
+        } catch (err) {
+            return "Invalid XPath. Details:\n" + err.message;
+        }
+
+        const serializer = new XMLSerializer();
+        const nodeToString = function(node) {
+            switch (node.nodeType) {
+                case Node.ELEMENT_NODE: return serializer.serializeToString(node);
+                case Node.ATTRIBUTE_NODE: return node.value;
+                case Node.COMMENT_NODE: return node.data;
+                case Node.DOCUMENT_NODE: return serializer.serializeToString(node);
+                default: throw new Error("Unknown Node Type: " + node.nodeType);
+            }
+        };
+
+        return Object.values(result).slice(0, -1) // all values except last (length)
+            .map(nodeToString)
+            .join(delimiter);
+    },
+
+
+    /**
+     * @constant
+     * @default
+     */
+    SELECTOR_INITIAL: "",
+    /**
+     * @constant
+     * @default
+     */
+    CSS_QUERY_DELIMITER: "\\n",
+
+    /**
+     * Extract information (from an hmtl document) with an css selector
+     *
+     * @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run_css_query: function(input, args) {
+        const query = args[0];
+        const delimiter = args[1];
+
+        var html;
+        try {
+            html = $.parseHTML(input);
+        } catch (err) {
+            return "Invalid input HTML.";
+        }
+
+        var result;
+        try {
+            result = $(html).find(query);
+        } catch (err) {
+            return "Invalid CSS Selector. Details:\n" + err.message;
+        }
+
+        const nodeToString = function(node) {
+            switch (node.nodeType) {
+                case Node.ELEMENT_NODE: return node.outerHTML;
+                case Node.ATTRIBUTE_NODE: return node.value;
+                case Node.COMMENT_NODE: return node.data;
+                case Node.TEXT_NODE: return node.wholeText;
+                case Node.DOCUMENT_NODE: return node.outerHTML;
+                default: throw new Error("Unknown Node Type: " + node.nodeType);
+            }
+        };
+
+        return Array.apply(null, Array(result.length))
+            .map(function(_, i) {
+                return result[i];
+            })
+            .map(nodeToString)
+            .join(delimiter);
+    },
+
 };