function Allxpath() {
	this.evalSingleValue = function(xml, xpathStr) {
		var node = this.evalSingle(xml, xpathStr);
		if (node != null) {
			return this.valueOf(node);
		} else {
			return null;
		}
	}
}

function IExpath() {
	this._allxpath = Allxpath;
	this._allxpath();
	
	this._xpather = nzm.xml.deserialize('<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/><xsl:variable name="result" select="true()"/><xsl:template match="/"><root><xsl:attribute name="type"><xsl:choose><xsl:when test="string(number($result)) = string($result)">number</xsl:when><xsl:when test="string(boolean($result)) = string($result)">boolean</xsl:when><xsl:otherwise>string</xsl:otherwise></xsl:choose></xsl:attribute><xsl:value-of select="$result"/></root></xsl:template></xsl:stylesheet>');
	
	this.evalSingle = function(xml, xpathStr) {
		try {
			return xml.selectSingleNode(xpathStr);
		} catch(e) { 
			var xsl = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
			xsl.async = false;
			xsl.loadXML(this._xpather.xml);
			xsl.documentElement.childNodes[1].setAttribute("select", xpathStr);
			var template = new ActiveXObject("Msxml2.XSLTemplate");
			template.stylesheet = xsl;
			var proc = template.createProcessor();
			proc.input = xml;
			proc.output = nzm.xml.create();
			proc.transform();
			var result = this.evalSingleValue(proc.output, "/root/text()");
			switch (proc.output.documentElement.getAttribute('type')) {
				case "number":
					return parseInt(result);
				case "boolean":
					return (result.toString() == "true");
				default:
					return result;
			}
		}
	}
	this.eval = function(xml, xpathStr) {
		return xml.selectNodes(xpathStr);
	}
	this.iterate = function(iterator) {
		return iterator.nextNode();
	}
	this.valueOf = function(xpathResult) {
		if (xpathResult.nodeType == null) {
			return xpathResult;
		} else if (xpathResult.nodeType == 1 || xpathResult.nodeType == 9) {
			return xpathResult.text;
		} else {
			return xpathResult.nodeValue;
		}
	}
}

function FFxpath() {
	this._allxpath = Allxpath;
	this._allxpath();
	
	this.evalSingle = function(xml, xpathStr) {
		var doc = xml.ownerDocument == null ? xml.documentElement : xml.ownerDocument.documentElement;
		var nsResolver = document.createNSResolver(doc);
		try {
			return xml.evaluate(xpathStr, xml, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
		} catch(e) {
			return xml.evaluate(xpathStr, xml, nsResolver, XPathResult.ANY_TYPE, null);
		}
	}
	this.eval = function(xml, xpathStr) {
		var doc = xml.ownerDocument == null ? xml.documentElement : xml.ownerDocument.documentElement;
		var nsResolver = document.createNSResolver( doc );
		return xml.evaluate(xpathStr, xml, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
	}
	this.iterate = function(iterator) {
		return iterator.iterateNext();
	}
	this.valueOf = function(xpathResult) {
		/*for (x in xpathResult) {
			try {
				alert(x + " = " + xpathResult[x]);
			} catch(e) {}
		}*/
		switch (xpathResult.resultType) {
			case XPathResult.NUMBER_TYPE:
				return xpathResult.numberValue;
			case XPathResult.STRING_TYPE:
				return xpathResult.stringValue;
			case XPathResult.BOOLEAN_TYPE:
				return xpathResult.booleanValue;
			default:
				if (xpathResult.singleNodeValue) {
					return xpathResult.singleNodeValue.textContent;
				} else {
					return xpathResult.textContent;
				}
		}
	}
}

if (nzm.browser.isIE) {
	nzm.xml.xpath = new IExpath();
} else {
	nzm.xml.xpath = new FFxpath();
}