ちょっと徹夜。
書きかけです。
Q$MSXML2$XMLHttpRequest と、Q$CSV$parseCSV は、もちろん拝借。
where は、「やっつけ」のような・・・。
> 厳密な文法
> kvpairs = 1*( col "=" val 0*1(",") )
この 0*1(",") の解釈が理解できず・・・(涙)。
<!DOCTYPE html> <title>TEST</title> <h1>CSV</h1> <script> var Q$MSXML2$XMLHttpRequest = (function () { var I = arguments.length; var i; for (i = 0; i < I; i++) { try { arguments[i] (); return arguments[i]; } catch (err) { ; } } return null; }) ( function () { return new ActiveXObject ('Msxml2.XMLHTTP.6.0'); }, function () { return new ActiveXObject ('Msxml2.XMLHTTP.3.0'); } ); if ('undefined' === typeof XMLHttpRequest) eval ('var XMLHttpRequest = Q$MSXML2$XMLHttpRequest; '); //___________________ var Q$CSV$parseCSV = (function () { return function (stringData, strict, separator) { if ((separator || (separator = ',')) === ',' || separator === '\t') { var isWellFormed = strict ? isStrict : isLoose; var pattern = new RegExp ('^(?:' + separator + '|(?:\\r\\n|\\r|\\n)' + '|"(?:""|[^"])*"' + '|[^\\r\\n"' + separator + '][^\\r\\n' + separator + ']*' + ')'); var flength = 0; var findex = 0; var fields = [ '' ]; var records = [ fields ]; var token; for ( stringData = trim (stringData); (token = pattern.exec (stringData)) && (token = token[0]); stringData = stringData.slice (token.length) ) { switch (token.charAt (0)) { case separator : fields[++findex] = ''; break; case '\r' : case '\n' : if (! isWellFormed (flength || (flength = findex), findex)) { throw new Error ('malformed CSV.'); } fields = records[records.length] = [''], findex = 0; break; case '"' : fields[findex] = token.slice (1, -1).replace (/""/g, '"'); break; default : fields[findex] = token; break; } } if (stringData === '' && isWellFormed (flength, findex)) { return records; } } throw new Error ('malformed CSV.'); }; function trim (str) { return String (str).replace (/^[\r\n]+|[\r\n]+$/g, ''); } function isStrict (flength, findex) { return flength === findex; } function isLoose () { return true; } }) (); var getFile = (function (fileName) { var text = ''; var req = new XMLHttpRequest; if (req) { req.open ('GET', fileName, false); req.send (null); text = (200 == req.status) ? req.responseText : ''; req = null; } return text; }); (function () { var REG_CSV_FRAGMENT = (function () { var DIGIT = '[\\x30-\\x39]'; var TEXTDATA = '[\\x23-\\x2B\\x2D-\\x3C\\x3E-\\x7E]'; var rownum = DIGIT + '+'; var column = '(?:' + DIGIT + '+' + '|' + TEXTDATA + '+)'; var rowspec = '(?:\\*' + '|' + rownum + ')'; var colspec = column; var val = TEXTDATA + '+'; var col = TEXTDATA + '+'; var kvpairs = '(?:(' + col + ')' + '=' + '(' + val + '))'; var wheresel = '(?:(where):' + '(?:' + kvpairs + '))'; var colsel = '(?:(col):' + '(' + colspec + '))'; var rowsel = '(?:(row):' + '(' + rowspec + '))'; var headersel = '(head)'; return new RegExp ('^#?(?:' + headersel + '|' + wheresel + '|' + colsel + '|' + rowsel + ')$'); }) (); function decomposition (fgmt) { return REG_CSV_FRAGMENT.exec (fgmt); } function fileLoad (fileName) { this.csv = (fileName) ? Q$CSV$parseCSV (getFile (fileName)) : null; return !! (this.csv); } function getHeader () { return this.csv[0].slice (0); } function getBody () { return this.csv.slice (1); } //__________________ function CSVFragment () { this.csv = []; } function _getIdentifiers (cmd, op1, op2) { var r; var no; var pr; var hd; switch (cmd) { case 'head' : return getHeader.call (this); case 'where' : hd = getHeader.call (this); no = hd.indexOf (op1); if (-1 === no) { throw new Error ('Not found field name.'); } pr = { no : no, val : op2 }; return ([hd].concat ( getBody.call (this) .filter (function (cells) { return (cells[this.no] === this.val); }, pr ))) .map (function (cells) { cells.splice (this.no, 1); return cells; }, pr); case 'col' : if (isNaN (op1)) { hd = getHeader.call (this); no = hd.indexOf (op1); if (-1 === no) { throw new Error ('Not found field name.'); } pr = { no : no }; } else { pr = { no : Number (op1) }; } return getBody.call (this).map (function (cells) { return cells[this.no]; }, pr); case 'row' : if (isNaN (op1)) { if ('*' !== op1) { throw new Error ('Syntax Error : row'); } return getBody.call (this); } else { return getBody.call (this)[Number(op1)]; // this.csv [Number (op1) + 1] } default : throw new Error (); } } function getIdentifiers (fgmt) { var op = (fgmt) ? decomposition (fgmt): null; if (op){ return _getIdentifiers.call ( this, op[1] || op[2] || op[5] || op[7], op[3] || op[6] || op[8], op[4]); } else { throw new Error ('Syntax error : fragument.'); } } //_______________ function create (url) { var obj; if (url) { obj = new CSVFragment; if (fileLoad.call (obj, url)) { return obj; } } return null; } CSVFragment.prototype.getIdentifiers = getIdentifiers; //CSVFragment.prototype.getHeader = getHeader; //CSVFragment.prototype.getBody = getHeader; CSVFragment.create = create; //this.CSVFragment = CSVFragment; //__________________ function getCSVData (url) { if (0 === arguments.length) return null; var fgmt = /^[^:/?#]+#(.+)$/.exec (url); var obj = CSVFragment.create (url); return (fgmt) ? obj.getIdentifiers (fgmt[1]) : null; } //_______________ this.getCSVFVragmentIdentifiers = getCSVData; }) (); alert (getCSVFVragmentIdentifiers ('sample.csv#head')); alert (getCSVFVragmentIdentifiers ('sample.csv#row:2')); alert (getCSVFVragmentIdentifiers ('sample.csv#row:*').join("\n")); alert (getCSVFVragmentIdentifiers ('sample.csv#col:temperature').join("\n")); alert (getCSVFVragmentIdentifiers ('sample.csv#col:2').join("\n")); alert (getCSVFVragmentIdentifiers ('sample.csv#where:date=2011-01-01').join("\n")); </script> <ul> <li>http://tools.ietf.org/id/draft-hausenblas-csv-fragment-00.html <li>http://www39.atwiki.jp/eriax/pages/124.html <li>http://translate.google.co.jp/translate?hl=ja&sl=en&tl=ja&u=http%3A%2F%2Ftools.ietf.org%2Fhtml%2F%2Fdraft-hausenblas-csv-fragment-00 </ul>