xpath.js
Summary
Shared utilities for using XPath.
Version: 0.8
$Id: overview-summary-xpath.js.html,v 1.12 2006/08/23 23:30:17 jameso Exp $
Author: James A. Overton
mozile.require("mozile.dom");
mozile.require("mozile.xml");
mozile.provide("mozile.xpath.*");
mozile.xpath = new Object();
mozile.xpath.prototype = new mozile.Module;
mozile.xpath.getXPath = function(node, root) {
if(!node || node.nodeType == undefined || !node.nodeType) return "";
if(node == root) return "";
var parent = node.parentNode;
switch(node.nodeType) {
case mozile.dom.ELEMENT_NODE:
var nodeName;
if(node.prefix) nodeName = node.nodeName;
else nodeName = node.nodeName;
if(!nodeName) nodeName = node.nodeName;
if(mozile.dom.isHTML(node)) nodeName = nodeName.toLowerCase();
if(node.ownerDocument && node.ownerDocument.documentElement == node)
return "/"+ nodeName +"[1]";
else return mozile.xpath.getXPath(parent, root)
+"/"+ nodeName +"["+ mozile.dom.getPosition(node) +"]";
case mozile.dom.ATTRIBUTE_NODE:
if(!parent) parent = node.ownerElement;
return mozile.xpath.getXPath(parent, root) +"/@"+ node.nodeName;
case mozile.dom.TEXT_NODE:
if(node == this._lastNode && root == this._lastRoot)
return this._lastXPath;
var xpath = mozile.xpath.getXPath(parent, root)
+"/text()["+ mozile.dom.getPosition(node) +"]";
this._lastNode = node;
this._lastRoot = root;
this._lastXPath = xpath;
return xpath;
case mozile.dom.COMMENT_NODE:
return mozile.xpath.getXPath(parent, root)
+"/comment()["+ mozile.dom.getPosition(node) +"]";
default:
if(parent) return mozile.xpath.getXPath(parent, root);
else return "";
}
}
mozile.xpath.getComponents = function(expression) {
if(typeof(expression) != "string") return [];
var components = expression.split("/");
for(var c=0; c < components.length; c++) {
if(!components[c]) components.splice(c,1);
}
return components;
}
mozile.xpath.getComponent = function(expression) {
var result = new Object();
var components = mozile.xpath.getComponents(expression);
if(components.length == 0) return result;
var component = components[components.length - 1];
var match = component.match(/(\S+:)?(\S+)\[(\d+)\]|(\S+:)?(\S+)/);
if(match) {
if(match[1] && match[2]) {
result.name = match[1] + match[2];
result.localName = match[2];
}
else if(match[2]) {
result.name = match[2];
result.localName = match[2];
}
else if(match[4] && match[5]) {
result.name = match[4] + match[5];
result.localName = match[5];
}
else if(match[5]) {
result.name = match[5];
result.localName = match[5];
}
if(match[3]) result.position = match[3];
else result.position = null;
}
return result;
}
mozile.xpath.getNode = function(expression, root) {
if(!root) root = document;
if(!expression) return root;
if(expression == this._lastXPath && root == this._lastRoot) return this._lastNode;
var node;
if(!node) {
var components = mozile.xpath.getComponents(expression);
var node = root;
for(var i=0; i < components.length; i++) {
var component = mozile.xpath.getComponent(components[i]);
node = mozile.xpath._getNthChild(node, component.name, component.position);
if(!node) return null;
}
}
if(node) {
this._lastNode = node;
this._lastRoot = root;
this._lastXPath = expression;
return node;
}
else return null;
}
mozile.xpath._getNthChild = function(parent, name, position) {
var c = 0;
var p = 1;
if(parent.nodeType == mozile.dom.DOCUMENT_NODE)
return parent.documentElement;
if(name == "text()") {
for(c=0; c < parent.childNodes.length; c++) {
if(parent.childNodes[c].nodeType == mozile.dom.TEXT_NODE) {
if(p == position) return parent.childNodes[c];
p++;
}
}
}
else if(name == "comment()") {
for(c=0; c < parent.childNodes.length; c++) {
if(parent.childNodes[c].nodeType == mozile.dom.COMMENT_NODE) {
if(p == position) return parent.childNodes[c];
p++;
}
}
}
if(name.indexOf("@") == 0) {
name = name.substring(1);
return parent.getAttributeNode(name);
}
else {
if(name.indexOf("xmlns:") > -1) name = name.substring(6);
for(c=0; c < parent.childNodes.length; c++) {
var childName = parent.childNodes[c].nodeName;
if(childName == name || childName == name.toUpperCase()) {
if(p == position) return parent.childNodes[c];
p++;
}
}
}
return null;
}
mozile.xpath.evaluate = function(expression, root) {
if(!root) root = document;
var doc;
if(root.ownerDocument) doc = root.ownerDocument;
else {
doc = root;
root = root.documentElement;
}
var nodes = new Array();
if(window.XPathEvaluator) {
var XPE = new XPathEvaluator;
var NSE = function(prefix) {
var namespaceURI = mozile.dom.lookupNamespaceURI(root, prefix);
if(namespaceURI) return namespaceURI;
else if(mozile.xml.ns[prefix]) return mozile.xml.ns[prefix];
return mozile.defaultNS;
}
try {
var results = XPE.evaluate(expression, root, NSE, 0, null);
if(results) {
var result = results.iterateNext();
while(result) {
nodes.push(result);
result = results.iterateNext();
}
}
} catch(e) {
alert(doc.documentElement.getAttribute("xmlns") +"\n"+ e);
}
}
else if(root.selectNodes) {
var results = root.selectNodes(expression);
var result = results.nextNode();
while(result) {
nodes.push(result);
result = results.nextNode();
}
}
return nodes;
}
Documentation generated by
JSDoc on Wed Aug 23 18:45:51 2006