読者です 読者をやめる 読者になる 読者になる
スポンサーリンク

jQuery をSQLの「select文」のように使う方法

javascript jQuery SQL


jQueryオブジェクトを,まるでSQLのselect文のような呼び出し方で使える関数を作成した。


面白いだろうと思ってやっつけで作ってみたのだが,下記のようなコードが書ける。

jselect( "select * from document where id = p1" ).each(function(){
	alert( $(this).text() );
});

こうすると,documentから全てのタグをスキャンし,id が "p1" であるようなDOM要素をjQueryオブジェクトとして返却し,そのタグ中のテキストを表示する。

要するに, $( "#p1" ) に変換している。

jselect( "select p from div" )

これは,div要素(親要素)の中にあるp要素をすべて返却する。つまり $( "div p" ) のこと。


正規表現によるセレクションもできる。

jselect( "select p from document where id ^= p and class $= hoge" )

とすれば,IDが "p" で始まり, CSSのclassが "hoge" で終わるような p 要素を document からすべて拾い出す。


生のjQueryで書けば, $( "p[@id^='p'][@class$='hoge']" ) という事だ。


*= によるマッチや, .classname による指定もできる。



要するに,

  • HTMLのDOM構造に対してSQL文のようなものを発行すると,
  • それを解釈してjQueryの記法に変換する

というだけで,実際のセレクション処理には関わってはいない。


このjselectという関数のコードを下記に記す。



// <script src="jquery-1.2.6.min.js"></script>


// jQueryオブジェクトをSQLのselect文のように呼び出す
function jselect( sql ){

	// 解釈
	var sql_info = getSqlInfo( sql );

	// セレクタ文構築
	var str_selector = getStrSelector( sql_info );
	
	// jQueryオブジェクトを返す
	return $( str_selector );
	
	
	// --- 以下関数 ---
	
	
	// SQL文を受け取り,属性情報をオブジェクトで返す
	function getSqlInfo( str )
	{
		str = str
			.replace( /(select.+)/gi, "$1" )
			.replace( "  ", " " );
		var part = str.split( " where " );
		// 結果情報をセットするオブジェクト
		var ret_obj = {};
	
		// 前半 (タグ名,親要素を指定)
		part[0].match( "select (.+) from (.+)" );
		ret_obj.tags = {eq:"=", val:RegExp.$1};
		ret_obj.from = {eq:"=", val:RegExp.$2};

		// 後半 (id, class, name等を指定)
		if( part.length > 1 )
		{
			$.each( part[1].split( / and /i ), function(i){
				this.match( /(.+) (.?=) (.+)/ );
				var key = RegExp.$1;
				var t_eq = RegExp.$2;
				var t_val = RegExp.$3;
				ret_obj[ key ] = {eq:t_eq, val:t_val};
			});
		}

		return ret_obj;
	}
	
	// 属性情報を受け取り,セレクタ文を返す
	function getStrSelector( obj )
	{
		// 抽出
		var tags = "" + obj.tags.val.replace("*","");
		var from = "" + obj.from.val.replace("document","");
		var id = ("id" in obj && obj.id.eq == "=") 
			? obj.id.val 
			: null;
		var class = ("class" in obj && obj.class.eq == "=") 
			? obj.class.val 
			: null;

		// セレクタ文の構築を開始
		var ret = "";
		ret += (from.length > 0) 
			? from + " " 
			: "";
		ret += (tags.length > 0)
			? tags 
			: "";
		ret += (class) 
			? "." + class 
			: "";
		ret += (id) 
			? "#" + id 
			: "";

		// その他の属性
		for( attr in obj )
		{
			if(
				("id" in obj && (!id) && attr === "id")
				||
				("class" in obj && (!class) && attr === "class")
				||
				(
					attr !== "id" &&
					attr !== "class" &&
					attr !== "from" &&
					attr !== "tags"
				)
			)
			{
				ret += "[@" 
					+ attr // 属性名
					+ obj[attr]["eq"] // 符号
					+ "'" + obj[attr]["val"] // 値
					+ "']";
			}
		}
		//alert(ret);
		return ret;
	}
}


返ってきたオブジェクトに

.each(function(){ alert( this.innerHTML ); });

とか付加すれば,それらのオブジェクト全ての中身を表示できる。


なお今のところ,このjselectなる関数で指定できるのは

  • id
  • class
  • 親要素関係
  • HTML属性

のみ。実用性は乏しい。

さらに改良してselectの入れ子ができたらいいと思う。
今は親要素にIDを指定した場合,その子要素にgetElementsByTagName()をかけるなら

jselect( "select p from #div1" )

と書く必要があるが,例えば,この#div1というjQuery記法をなくすために

jselect( "select p from (select * from document where id = div1)" )

のようにできたら便利だ。( ) 内の一つのselect文が,getElementById() か,getElementsByTagName() に相当するわけだ。

何がしたいのか?

やりたかったのは,「select文の世界で眺めることにより,jQueryでどういう事が実現可能なのかをわかりやすく表現する」ということ。


何か物を探索するとき,DBのように扱えたら楽だろうなと夢見てしまう事がある。

例えば,机の引出しをあけたとき Windows PC内からファイルを探し出すとき。時間指定やファイルサイズ指定など,1つの「select文」をコマンドプロンプトで実行すれば,該当ファイルがごっそりと手に入る。
そんなうまい話は今のところない。

※コマンドプロンプトの限界については,ある程度下記記事で紹介した。


コマンドプロンプトで,暗記するべき10の必須コマンド  (前半) ファイル処理系
http://language-and-engineering.hatenablog.jp/entry/20081001/1222857265


しかしDOM要素に対しては,そういったSQLによるかのような便利な抽出が,現在はJavaScriptライブラリを使って実現可能なのだ。

その便利さを,本当にselect文のようなものを使って表現できたら面白いと思った。


追記1

jsonデータに対して,上と同様のselect文のようなものを指定してデータ抽出できるjQueryプラグインが存在する。

SQL調にデータを取得できるJavascript、JsonSQL【jQuery】
http://2-laps.com/mt/2008/02/sqljavascriptjsonsqljquery.html


また、PHPでHTMLを扱う際には、HTMLSQLというのが使える。

HTMLの要素をSQLのように取り出せるPHPのライブラリ『htmlSQL』
http://www.ideaxidea.com/archives/200...

追記2

classというプロパティを使っているのはまずいな…