XPath式をOOPにつくるXPathBuilder(よく考えないとだめ)
まいかいXPathをがんばって作るコードを書いてていやになったのでSQLみたいに
var xpath = new XPathBuilder(); xpath.div.className("next").position(4).a.rel("no-follow").img.toString();
こう書いたら
div[contains(" " + @class + " ", " next ") and position() = 4]/a[@rel = "no-follow" ]/img
こうなるやつができないかなーとおもって作ってみた(下のやつ。js1.7でないと動きません)けど、たしかに
xpath.div.className("next").position(4).a.rel("no-follow").img
みたいに単純だったらいいけど、じゃあ contains(@class, "no") とかどう書くの? とか、とりあえずは
とかにしたらごまかせるけど、きちんと設計できないとぜったい破綻するのが見えたので中止。
これ書くの楽しそうだけど自分はチョイ役ぐらいでしか使わないので、こんなの書いてていいのかという気持ちに。
誰か作ってください!
追記
とりあえず div.id って書いたときに attributeのidなのかXPath functionのidなのかがわかんないので、この書き方は厳しい。
div.@idは書けないのでその代わりにdiv.$idにするとかかなー。いまいち$が好きじゃない。
var XPathBuilder = function () { this.steps = [ ]; //new XPathBuilder.Step(name) ]; var htmlTags = [ 'a', 'img', 'div', 'table', 'tbody', 'tr', 'td', 'p', 'span', 'em', 'thead', ]; var self = this; htmlTags.forEach( function (name) { self.__defineGetter__( name, let(n = name) function () { var step = new XPathBuilder.Step(n); self.steps.push(step); return self; } ); } ); } XPathBuilder.Step = function (name) { this.elementName = name; this.predicates = []; console.log(this.predicates); } XPathBuilder.Step.prototype.toString = function () { console.log("XPathBuilder.Step", this.elementName, this.predicates); var exp = this.elementName; if ( this.predicates.length > 0 ) { var predicate = this.predicates.join(" and "); exp += '[' + predicate +']'; } return exp; } XPathBuilder.prototype.__noSuchMethod__ = function (name, args) { if ( name == 'className' ) { var classname = args.shift(); this.__push( 'contains(" " + @class + " ", " ' + classname + ' ")' ); } else { var value = args.shift(); this.__push( '@' + name + ' = "' + value + '" ' ); } return this; }; XPathBuilder.prototype.__defineGetter__("__tail", function () { return this.steps[this.steps.length - 1] ; } ); XPathBuilder.prototype.__push = function (v) { this.__tail.predicates.push(v); } XPathBuilder.prototype.position = function (n) { this.__push( 'position() = ' + n); return this; } XPathBuilder.prototype.toString = function () { return this.steps.map( function (step) { return step.toString() } ).join("/"); }