Skip to content

Instantly share code, notes, and snippets.

@brettz9
Created July 14, 2014 22:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brettz9/762bf8552834d338d40a to your computer and use it in GitHub Desktop.
Save brettz9/762bf8552834d338d40a to your computer and use it in GitHub Desktop.
Non-functioning scribbles for XQuery-like approach in JS
<!DOCTYPE html>
<meta charset="utf-8" />
<label class="myItems">Hello</label>
<label class="myItems">World!</label>
<script src="jqflower.js"></script>
<script>
try {
queryAll([document, '.myItems']).reduce(function (a, b) {
a.push(b);
}, []);
// also consider https://github.com/nkallen/jquery-database
var result = JQFlower().
// XML Pipelining / XProc functions: http://www.ibm.com/developerworks/library/x-xproc/
$declaration(
{output:[]}
).
$( // Better to put wrapper outside, but can at least put in order here if desired
document.body
).
$for(
['$a', $at('count'), $in(document, '.myItems')],
{$a: $in([document, '.myItems']), // Fix: also allow $in() to accept callback, e.g., auto-generated by Ajax-creator funtion
at: '$count' // for numbering count as go along
}, // allow retrieval from server, and also allow XPath (e.g. MDBX?)
// allow joining multiple nodes in association with first without need for count (and way to make up for difference with append)
// also allow callback which is given 'this' as argument to continue the chain instead (since asynchronous);
{$a: JSONP(url, function (flower) { // JSONP returns the function so $for can detect it should call with 'this'?
flower.$let().$where().$return(function () {document.body.appendChild($a);});
})}
). // Fix: allow multiple 'for's (including non-nested joinable ones in the same $for())
$at('$count').
$at({'$item': arr}).
$at({'$item': function (ct, node) {
return arr[ct] ? arr[c] : 'something else';
}}).
$let([
{$b:5},
// call functions with the count and/or 'for'?
{$c: function () { // Fix: make one useful for XML and one useful for JSON
// Fix: also allow {$c: letter('$a', '@value')}
// {$c: increment(data)}
return string(this.$a);
}}
]).
// allow this too?
// $for('$a', $in('.myItems', document))
/**/
$where(function () { // Fix: add custom where and orderBy specific to XML and ones specific to JSON; demo calling function to return function,
// e.g., $where('$a', '>', '$b')
return number(this.$a) > 5;
}).
$orderBy(function (a, b) {
// e.g., $orderBy('@value', 'asc')
// If a zero or single argument defined function, just treat it as returning all filtered (with argument as the nodes)
return a.attr('value') > b.attr('value'); // [?value]\\
}).
//*/
// Fix: throw if any extra return function calls
// Fix: decide whether recursion needs to be nested inside here, or can be as next chained call; should be chained since two subsequent "for"'s must be (unless using return); specify output as "input" so continues into other process
$return(function (output) { // Demo as output XML DOM, XML String (concat with outside HTML string for use in $J()), or JSON Object, JSON array, and JSON string
// XML.$for(...); // Fix: Test nested and demo a join!
// Demo modification of input nodes (XQUF)
//$return(push('string($a) + $b;'));
output.push(string(this.$a) + this.$b); // $count, etc.
});
alert(result);
// Make XML.for and a JSON.for classes, which have different default where/orderBy (and include different built-in static classes)
var result = $for({$a: '.myItems'}, document).
$let({$b: '$a.length'}). // also allow $let({$b:function () {return this.$a.length;}}).
//or $let({$b:function () this.$a.length}). in JS 1.8
$return('alert(string($a) + $b);');
// also allow $return(function ($a) {return string(this.$a) + this.$b;}); // with the $a in the arguments being the latest or 2nd latest for (but not let?)?
// could also refer to global if set up global "var $a, $b;", etc.?
var result = $for({$a: '.myItems'}, document).
// Fix: At least allow "for"'s to be accessible as $a ($b, etc.) arguments like this:
$let(function ($a, $b) {return {$c:string($a)+string($b)};}). // Do we need this? // Fix: (function($a,$b) { })();
$return('alert(string($a) + $b);');
}
catch(e) {
alert(e);
}
</script>
// Inspiration from XQuery, https://github.com/nkallen/jquery-database , and http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/
// I also came across http://plugins.jquery.com/project/jLINQ (and http://www.hugoware.net/Projects/jLinq ) and http://jsinq.codeplex.com/ after starting this work
// Flower is inspired by the FLWOR expressions of XQuery (For, Let, Where, Order by, Return)
// Methods are prefixed by '$' to avoid use of JavaScript keywords (e.g., for, let, return)
// (JS-pre-declared) Variables could be implementable without need for "this." in subsequent methods by using eval() and strings, but less JS-like (and may as well do XQuery parser in that case) and also less secure
// Fix: only accept where, order by, and return if a let or for has been called, and require where, order by, and return in that order
function JQFlower (opts) {
if (!(this instanceof JQFlower)) {
return new JQFlower(opts);
}
this.depth = 0;
this.forMap = {children:{}};
if (opts) {
this.$declaration(opts);
}
}
// Allows invoking on an explicit function separately though it is unnecessary
// as this function is also auto-invoked by the constructor
JQFlower.prototype.$declaration = function (opts) {
for (var opt in opts) {
}
return this;
};
JQFlower.prototype.$ = JQFlower.prototype.$wrapper = function () {
return this;
};
JQFlower.prototype.$for = function (query) {
for (var key in query) {
query = query[key];
break;
}
this.key = key;
this.query = query;
this.vrs = '';
if (typeof query === 'function') {
query.call(this); // Continue the FLWOR chain asynchronously
}
};
JQFlower.prototype.$at = function (vrs) {
return this;
};
JQFlower.prototype.$let = function (vrs) {
if (typeof vrs === 'function') {
vrs = vrs();
}
for (var p in vrs) {
this.vrs += 'var ' + p + '=' + vrs[p] + ';';
}
return this;
};
JQFlower.prototype.$where = function (__clause__) {
// Fix: filter down this.key
eval(this.vrs);
this.nodes = this.nodes.querySelectorAll(__clause__);
return this;
};
JQFlower.prototype.$orderBy = function (order) {
// Fix: order this.key
eval(this.vrs);
return this;
};
JQFlower.prototype.$return = function (cb) {
if (typeof cb === 'function') {
var scope = {};
scope[this.key] = document.querySelectorAll(this.query);
return cb.call(scope);
}
var nodes = document.querySelectorAll(this.query);
for (var i=0; i < nodes.length; i++) {
eval('var '+this.key + '= nodes[i];' +this.vrs + ';' + cb);
}
};
// Branch off into domain-specific functions (and associated with constant strings?)
// Fix: define this on JQFlower, unless a 'global' declaration is made
// Make JSON-specific ones, jQuery-specific (e.g., filter()), etc.
// XQuery-like element converter
function string (el) {
if (el.length) {
var content = '';
for (var i = 0; i < el.length; i++) {
content += el[i].textContent;
}
return content;
}
return el.textContent;
}
// For users who don't want jQuery
var $in = function queryAll (node, selector) {
if (selector) {
return [].slice.call(node.querySelectorAll(this.query));
}
else {
return [].slice.call(document.querySelectorAll(this.query));
}
};
var queryAll = $in;
/*
Design requirements
1) Support all of FLWOR
2) Allow hierarchically evaluated but sequentially nested
3) Synchronous or asynchronous loading of URLs?
4) Reference to JSXQueryParser code?
5) Shortcoming: inability of xqueryjs to represent the recursive possibilities of XQueryX or XSL, so make (hopefully easier!) version of XQueryX-as-E()
collection() argument with Mongodb?
*/
// Note: Need function to get variables (unless used some string syntax)
$let('myUls', function ($) {
return $('ul.myClass', 'http://www.example.com');
}).
$for('ul', function ($) {
return $('ul.anotherClass');
}).
$for('li', function ($) {
return $('li.anotherClass');
}).
$let('myLis', function ($) {
return $('li', this.$myUls);
}).
$let('links', 'a'). // 2nd argument string as shorthand for function () {return $('a');}
$where(function (liWhereMethod) { // Long-hand form (but better to avoid adding too much logic in here)
return liWhereMethod($('*:contains("hello")', this.$links));
}).
$orderBy(function () {
return [this.$links.children('em'), 'ASC'];
}).
$return(function () {
return $('div', [this.$li, this.$myLis]);
});
// Other possible approach (if iteration predictable order, could use regular objects instead of array of functions, but ECMAScript does not require for-in iteration order to be same as creation order)
var xqueryTemplates = [
function $for () {
},
function $let () {
},
function $for2 () {
}
];
@L2L2L
Copy link

L2L2L commented Aug 3, 2014

I scroll through it, I'm on my phone.

Cause the other half of the pie is (X)HTML. If you had looked at the pdf dated 2011, you'll see the comparison of all xQuery.

The fist link to the site xqib.org, it'll also show you LiveScript(ECMAScript) and xqib in the broswer communicating. And this will extinguish a large amount of utilizing the broswer API.

In no way am I aiming to have this as a replacement for LiveScript.

I feel this is more interesting and more powerful than google dart language.

I've tired to reach out to so many to seek this as a interest of reviveful.

To day I recieve a post on GitHub in eXist db issues section. Saying that if the opportunity rise, thru discuss on it.

Getting the xml native datedase to cooperate on this; xqib(xqic(xQuery in the console)) can become a powerful language as an alternative and most importantly as a compliment to LiveScript.

@brettz9
Copy link
Author

brettz9 commented Aug 4, 2014

I did some work with XQuery earlier, but now it is not on my plate, and I still think jQuery which is practically universally adopted on the web can be adapted to do the trick, as there is no reason it cannot be used with XHTML either (including for the likes of my https://github.com/brettz9/httpquery project ). In any case, I'm sorry, but at the moment, I barely have time or energy for my existing projects, so I can't really get involved in anything new.

@L2L2L
Copy link

L2L2L commented Aug 29, 2014

can this be done via JavaScript alone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment