Skip to content

Instantly share code, notes, and snippets.

@snj14
Forked from cho45/dollarX.js
Created August 3, 2008 12:03
Show Gist options
  • Save snj14/3820 to your computer and use it in GitHub Desktop.
Save snj14/3820 to your computer and use it in GitHub Desktop.
complex $X
// $X
//
// usage:
//
// $X(aExpression);
// $X(aExpression, aContext, aType);
// $X(aExpression, aContext, aType, aResolver, aNamespaceHash);
// $X(aNamespaceHash, aResolver, aType, aContext, aExpression);
//
// or
//
// $X()
// .setExpression(aXPathExpression) // XPath expression
// .setCotext(aContext) // to use relative XPath
// .setType(aType) // type of result (*1)
// .setNamespace(aNamespaceHash) // namespace hash (*2)
// .setResolver(aResolver) // function. high priority than NamespaceHash
// .setDocument(aDocument) // base document
// .setDefault(aExpression, aContext, aType, aResolver, aNamespaceHash) // same as $X() arguments
// .evaluate();
//
// or
//
// var $x = $X().setDocument(aDocument).setNamespace(aNamespaceHash).getX();
// $x(aExpression, aContext, aType);
// *1 type of result example
//
// var aType = Number // return Number
// var aType = Boolean // return Boolean
// var aType = String // return String
// var aType = Array // return Array
//
// *2 namespace hash example
//
// var aNamespaceHash = {
// h: "http://www.w3.org/1999/xhtml"
// , rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
// , grddl: "http://www.w3.org/2003/g/data-view#"
// }
function $X(){
function XPath(){return (this instanceof XPath) ? this : new XPath()}
XPath.prototype = {
evaluate: function(){
var self = this;
var doc = this.doc ||
(window.content && window.content.document) || // for Addons
document.ownerDocument ||
document;
var context = this.context || doc;
var resolver = this.resolver || function(prefix){
if(doc.contentType == "text/html") return ""; // text/html need no namespace uri
return (self.namespace[prefix] ||
((doc.contentType == "application/xhtml+xml") && "http://www.w3.org/1999/xhtml") ||
doc.createNSResolver(context.documentElement).lookupNamespaceURI(prefix) ||
doc.documentElement.namespaceURI);
}
var exp = doc.createExpression(this.expression, resolver);
switch (this.type) {
case String:
return exp.evaluate(
context,
XPathResult.STRING_TYPE,
null
).stringValue;
case Number:
return exp.evaluate(
context,
XPathResult.NUMBER_TYPE,
null
).numberValue;
case Boolean:
return exp.evaluate(
context,
XPathResult.BOOLEAN_TYPE,
null
).booleanValue;
case Array:
var result = exp.evaluate(
context,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
var ret = [];
for (var i = 0, len = result.snapshotLength; i < len; ret.push(result.snapshotItem(i++)));
return ret;
case undefined:
var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
switch (result.resultType) {
case XPathResult.STRING_TYPE : return result.stringValue;
case XPathResult.NUMBER_TYPE : return result.numberValue;
case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
// not ensure the order.
var ret = [];
var i;
while ((i = result.iterateNext())) {
ret.push(i);
}
return ret;
}
}
return null;
default:
throw(TypeError("$X: specified type is not valid type."));
}
},
setExpression: function(arg){
this.expression = arg;
return this;
},
setContext: function(arg){
this.context = arg;
return this;
},
setType: function(arg){
this.type = arg;
return this;
},
setResolver: function(arg){
this.resolver = arg;
return this;
},
setNamespace: function(arg){
this.namespace = arg;
return this;
},
setDocument: function(arg){
this.doc = arg;
return this;
},
checkArgumentType: function(o){
return (((o == String ||
o == Number ||
o == Boolean ||
o == Array) &&
'type') ||
((typeof o == 'string') && 'expression') ||
((o instanceof Function) && 'resolver') ||
((o instanceof Node) && 'context') ||
((o instanceof Object) && 'namespace')
);
},
setDefault: function(args){ // args is Array. e.g. setDefault(['//div', context, Array])
var self = this;
args = Array.slice(args);
args.forEach(function(o){
var a = self.checkArgumentType(o);
if(a) self[a] = o;
});
return this;
},
getX: function(){
var self = this;
return function(){
if(arguments.length == 0) return self;
return self.setDefault(arguments).evaluate();
}
}
}
if(arguments.length == 0) return XPath();
return XPath()
.setDefault(arguments)
.evaluate();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment