function
addXPathSupport(document) {
var
isIe = /MSIE [56789]/.test(navigator.userAgent) && (navigator.platform ==
"Win32"
);
if
(isIe)
{
document.DomL3XPathRelease =
"0.0.3.0"
;
var
XPathException =
new
_XPathExceptionHandler();
function
_XPathExceptionHandler()
{
this
.INVALID_EXPRESSION_ERR = 51;
this
.TYPE_ERR = 52;
this
.NOT_IMPLEMENTED_ERR = -1;
this
.RUNTIME_ERR = -2;
this
.ThrowNotImplemented =
function
(message)
{
ThrowError(
this
.NOT_IMPLEMENTED_ERR,
"This functionality is not implemented."
, message);
}
this
.ThrowInvalidExpression =
function
(message)
{
ThrowError(
this
.INVALID_EXPRESSION_ERR,
"Invalid expression"
, message);
}
this
.ThrowType =
function
(message)
{
ThrowError(
this
.TYPE_ERR,
"Type error"
, message);
}
this
.Throw =
function
(message)
{
ThrowError(
this
.RUNTIME_ERR,
"Run-time error"
, message);
}
function
ThrowError(code, description, message)
{
var
error =
new
Error(code,
"DOM-L3-XPath "
+ document.DomL3XPathRelease +
": "
+ description + (message ?
", \""
+ message +
"\""
:
""
));
error.code = code;
error.name =
"XPathException"
;
throw
error;
}
}
var
DOMException =
new
_DOMExceptionHandler();
function
_DOMExceptionHandler()
{
this
.ThrowInvalidState =
function
(message)
{
ThrowError(13,
"The state of the object is no longer valid"
, message);
}
function
ThrowError(code, description, message)
{
var
error =
new
Error(code,
"DOM : "
+ description + (message ?
", \""
+ message +
"\""
:
""
));
error.code = code;
error.name =
"DOMException"
;
throw
error;
}
}
document.createExpression =
function
(
expression,
resolver
)
{
return
new
XPathExpression(expression, resolver);
}
document.createNSResolver =
function
(
nodeResolver
)
{
return
new
XPathNSResolver(nodeResolver);
}
document.evaluate =
function
(
expression,
contextNode,
resolver,
type,
result
)
{
return
document.createExpression(expression, resolver).evaluate(contextNode, type, result);
}
function
XPathExpression
(
expression,
resolver
)
{
this
.expressionString = expression;
this
.resolver = resolver;
this
.evaluate =
function
(
contextNode,
type,
result
)
{
return
(result && result.constructor == XPathResult ? result.initialize(
this
, contextNode, resolver, type) :
new
XPathResult(
this
, contextNode, resolver, type));
}
this
.toString =
function
()
{
return
"[XPathExpression]"
;
}
}
function
XPathNSResolver(node)
{
this
.node = node;
this
.lookupNamespaceURI =
function
(
prefix
)
{
XPathException.ThrowNotImplemented();
return
null
;
}
this
.toString =
function
()
{
return
"[XPathNSResolver]"
;
}
}
XPathResult.ANY_TYPE = 0;
XPathResult.NUMBER_TYPE = 1;
XPathResult.STRING_TYPE = 2;
XPathResult.BOOLEAN_TYPE = 3;
XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4;
XPathResult.ORDERED_NODE_ITERATOR_TYPE = 5;
XPathResult.UNORDERED_SNAPSHOT_TYPE = 6;
XPathResult.ORDERED_SNAPSHOT_TYPE = 7;
XPathResult.ANY_UNORDERED_NODE_TYPE = 8;
XPathResult.FIRST_ORDERED_NODE_TYPE = 9;
function
XPathResult
(
expression,
contextNode,
resolver,
type
)
{
this
.initialize =
function
(expression, contextNode, resolver, type)
{
this
._domResult =
null
;
this
._expression = expression;
this
._contextNode = contextNode;
this
._resolver = resolver;
if
(type)
{
this
.resultType = type;
this
._isIterator = (type == XPathResult.UNORDERED_NODE_ITERATOR_TYPE ||
type == XPathResult.ORDERED_NODE_ITERATOR_TYPE ||
type == XPathResult.ANY_TYPE);
this
._isSnapshot = (type == XPathResult.UNORDERED_SNAPSHOT_TYPE || type == XPathResult.ORDERED_SNAPSHOT_TYPE);
this
._isNodeSet = type > XPathResult.BOOLEAN_TYPE;
}
else
{
this
.resultType = XPathResult.ANY_TYPE;
this
._isIterator =
true
;
this
._isSnapshot =
false
;
this
._isNodeSet =
true
;
}
return
this
;
}
this
.initialize(expression, contextNode, resolver, type);
this
.getInvalidIteratorState =
function
()
{
return
documentChangeDetected() || !
this
._isIterator;
}
this
.getSnapshotLength =
function
()
{
if
(!
this
._isSnapshot)
{
XPathException.ThrowType(
"Snapshot is not an expected result type"
);
}
activateResult(
this
);
return
this
._domResult.length;
}
this
.iterateNext =
function
()
{
if
(!
this
._isIterator)
{
XPathException.ThrowType(
"Iterator is not an expected result type"
);
}
activateResult(
this
);
if
(documentChangeDetected())
{
DOMException.ThrowInvalidState(
"iterateNext"
);
}
return
getNextNode(
this
);
}
this
.snapshotItem =
function
(index)
{
if
(!
this
._isSnapshot)
{
XPathException.ThrowType(
"Snapshot is not an expected result type"
);
}
return
getItemNode(
this
, index);
}
this
.toString =
function
()
{
return
"[XPathResult]"
;
}
this
.getStringValue =
function
()
{
if
(
this
.resultType != XPathResult.STRING_TYPE)
{
XPathException.ThrowType(
"The expression can not be converted to return String"
);
}
return
getNodeText(
this
);
}
this
.getNumberValue =
function
()
{
if
(
this
.resultType != XPathResult.NUMBER_TYPE)
{
XPathException.ThrowType(
"The expression can not be converted to return Number"
);
}
var
number = parseInt(getNodeText(
this
));
if
(isNaN(number))
{
XPathException.ThrowType(
"The result can not be converted to Number"
);
}
return
number;
}
this
.getBooleanValue =
function
()
{
if
(
this
.resultType != XPathResult.BOOLEAN_TYPE)
{
XPathException.ThrowType(
"The expression can not be converted to return Boolean"
);
}
var
text = getNodeText(
this
);
bool = (text ? text.toLowerCase() :
null
);
if
(bool ==
"false"
|| bool ==
"true"
)
{
return
bool;
}
XPathException.ThrowType(
"The result can not be converted to Boolean"
);
}
this
.getSingleNodeValue =
function
()
{
if
(
this
.resultType != XPathResult.ANY_UNORDERED_NODE_TYPE &&
this
.resultType != XPathResult.FIRST_ORDERED_NODE_TYPE)
{
XPathException.ThrowType(
"The expression can not be converted to return single Node value"
);
}
return
getSingleNode(
this
);
}
function
documentChangeDetected()
{
return
document._XPathMsxmlDocumentHelper.documentChangeDetected();
}
function
getNodeText(result)
{
activateResult(result);
return
result._textResult;
}
function
findNode(result, current)
{
switch
(current.nodeType)
{
case
1:
var
id = current.attributes.getNamedItem(
"id"
);
if
(id)
{
return
document.getElementById(id.value);
}
XPathException.Throw(
"unable to locate element in XML tree"
);
case
2:
var
id = current.selectSingleNode(
".."
).attributes.getNamedItem(
"id"
);
if
(id)
{
var
node = document.getElementById(id.text);
if
(node)
{
return
node.attributes.getNamedItem(current.nodeName);
}
}
XPathException.Throw(
"unable to locate attribute in XML tree"
);
case
3:
var
id = current.selectSingleNode(
".."
).attributes.getNamedItem(
"id"
);
if
(id)
{
var
node = document.getElementById(id.value);
if
(node)
{
for
(child
in
node.childNodes)
{
if
(child.nodeType == 3 && child.nodeValue == current.nodeValue)
{
return
child;
}
}
}
}
XPathException.Throw(
"unable to locate text in XML tree"
);
}
XPathException.Throw(
"unknown node type"
);
}
function
activateResult(result)
{
if
(!result._domResult)
{
try
{
var
expression = result._expression.expressionString;
if
(result._contextNode != document && expression.indexOf(
"//"
) != 0)
{
expression =
"//*[@id = '"
+ result._contextNode.id +
"']"
+
(expression.indexOf(
"/"
) == 0 ?
""
:
"/"
) + expression;
}
if
(result._isNodeSet)
{
result._domResult = document._XPathMsxmlDocumentHelper.getDom().selectNodes(expression);
}
else
{
result._domResult =
true
;
result._textResult = document._XPathMsxmlDocumentHelper.getTextResult(expression);
}
}
catch
(error)
{
alert(error.description);
XPathException.ThrowInvalidExpression(error.description);
}
}
}
function
getSingleNode(result)
{
var
node = getItemNode(result, 0);
result._domResult =
null
;
return
node;
}
function
getItemNode(result, index)
{
activateResult(result);
var
current = result._domResult.item(index);
return
(current ? findNode(result, current) :
null
);
}
function
getNextNode(result)
{
var
current = result._domResult.nextNode;
if
(current)
{
return
findNode(result, current);
}
result._domResult =
null
;
return
null
;
}
}
document.reloadDom =
function
()
{
document._XPathMsxmlDocumentHelper.reset();
}
document._XPathMsxmlDocumentHelper =
new
_XPathMsxmlDocumentHelper();
function
_XPathMsxmlDocumentHelper()
{
this
.getDom =
function
()
{
activateDom(
this
);
return
this
.dom;
}
this
.getXml =
function
()
{
activateDom(
this
);
return
this
.dom.xml;
}
this
.getTextResult =
function
(expression)
{
expression = expression.replace(/</g,
"<"
).replace(/>/g,
">"
).replace(/
"/g, "
\
""
);
"<xsl:output method=\"text\"/><xsl:template match=\"*\"><xsl:value-of select=\""
+ expression +
"\"/>"
+
"</xsl:template></xsl:stylesheet>"
;
var
xsl =
new
ActiveXObject(
"Msxml2.DOMDocument"
);
xsl.loadXML(xslText);
try
{
var
result =
this
.getDom().transformNode(xsl);
}
catch
(error)
{
alert(
"Error: "
+ error.description);
}
return
result;
}
this
.reset =
function
()
{
this
.dom =
null
;
}
function
onPropertyChangeEventHandler()
{
document._propertyChangeDetected =
true
;
}
this
.documentChangeDetected =
function
()
{
return
(document.ignoreDocumentChanges ?
false
:
this
._currentElementCount != document.all.length || document._propertyChangeDetected);
}
function
activateDom(helper)
{
if
(!helper.dom)
{
var
dom =
new
ActiveXObject(
"Msxml2.DOMDocument"
);
/** SELENIUM:PATCH TO ALLOW PROVIDE FULL XPATH SUPPORT */
dom.setProperty(
"SelectionLanguage"
,
"XPath"
);
dom.async =
false
;
dom.resolveExternals =
false
;
loadDocument(dom, helper);
helper.dom = dom;
helper._currentElementCount = document.all.length;
document._propertyChangeDetected =
false
;
}
else
{
if
(helper.documentChangeDetected())
{
var
dom = helper.dom;
dom.load(
""
);
loadDocument(dom, helper);
helper._currentElementCount = document.all.length;
document._propertyChangeDetected =
false
;
}
}
}
function
loadDocument(dom, helper)
{
return
loadNode(dom, dom, document.body, helper);
}
function
loadNode(dom, domParentNode, node, helper)
{
if
(node.nodeName.indexOf(
"/"
) > -1
|| node.nodeName ==
""
|| node.nodeName ==
"#document"
|| node.nodeName ==
"#document-fragment"
|| node.nodeName ==
"#cdata-section"
|| node.nodeName ==
"#xml-declaration"
|| node.nodeName ==
"#whitespace"
|| node.nodeName ==
"#significat-whitespace"
)
{
return
;
}
if
(node.nodeName ==
"#comment"
)
{
try
{
domParentNode.appendChild(dom.createComment(node.nodeValue));
}
catch
(ex)
{
}
}
else
if
(node.nodeType == 3)
{
domParentNode.appendChild(dom.createTextNode(node.nodeValue));
}
else
{
var
domNode = dom.createElement(node.nodeName.toLowerCase());
if
(!node.id)
{
node.id = node.uniqueID;
}
domParentNode.appendChild(domNode);
loadAttributes(dom, domNode, node);
var
length = node.childNodes.length;
for
(
var
i = 0; i < length; i ++ )
{
loadNode(dom, domNode, node.childNodes[i], helper);
}
node.attachEvent(
"onpropertychange"
, onPropertyChangeEventHandler);
}
}
function
loadAttributes(dom, domParentNode, node)
{
for
(
var
i = 0; i < node.attributes.length; i ++ )
{
var
attribute = node.attributes[i];
var
attributeValue = attribute.nodeValue;
if
(attributeValue && attribute.specified)
{
var
domAttribute = dom.createAttribute(attribute.nodeName);
domAttribute.value = attributeValue;
domParentNode.setAttributeNode(domAttribute);
}
}
}
}
}
else
{
document.reloadDom =
function
() {}
XPathResult.prototype.getStringValue =
function
()
{
return
this
.stringValue;
}
XPathResult.prototype.getNumberValue =
function
()
{
return
this
.numberValue;
}
XPathResult.prototype.getBooleanValue =
function
()
{
return
this
.booleanValue;
}
XPathResult.prototype.getSingleNodeValue =
function
()
{
return
this
.singleNodeValue;
}
XPathResult.prototype.getInvalidIteratorState =
function
()
{
return
this
.invalidIteratorState;
}
XPathResult.prototype.getSnapshotLength =
function
()
{
return
this
.snapshotLength;
}
XPathResult.prototype.getResultType =
function
()
{
return
this
.resultType;
}
}
}