Ergebnis 1 bis 5 von 5
  1. #1
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.702

    queryString Parser und Stringifier

    Hi Leute,

    ihr kennt doch alle die PHP-Syntax für GET und POST (key=value) und die Besonderheit mit den eckigen Klammern (arr[]=1&arr[]=2 => arr ist ein Array mit [1, 2] - aber auch Abgefahreneres: arr[hallo][][was]=2&arr[hallo][0][das]=3 => arr ist ein "Array" mit {hallo: [{was: 2, das:3}]}).
    Hab' das Ganze mal so gut wie möglich in JS nachgebildet (es werden sogar, wo möglich, echte Arrays erzeugt) und bitte euch, es auf Herz und Nieren zu testen:
    Code:
    var queryString = {
    	parse: function(str){
    		var ret = {};
    		var retInfo = {};
    		if (str.charAt(0) === "?") str = str.substr(1);
    		var param = str.split("&");
    		for (var i = 0; i < param.length; i++){
    			var par = param[i].split("=");
    			switch (par.length){
    				case 1:
    					par[1] = "";
    					break;
    				case 2:
    					break;
    				default:
    					par[1] = par.slice(1).join("=");
    			}
    			var parts = [];
    			var name = decodeURIComponent(par[0]).replace(/\][^\[].+/, "]").replace(/\[([^\]]*)\]/g, function(m, c){parts.push(c); return "";});
    			var value = decodeURIComponent(par[1]);
    			if (!name) continue;
    			var partsLength = parts.length;
    			if (!partsLength){
    				ret[name] = value;
    			}
    			else {
    				if (!is.object(ret[name])){
    					ret[name] = {};
    					retInfo[name] = {nextIndex: 0, subObjects: {}, onlyDiggits: true};
    				}
    				var obj = ret[name];
    				var objInfo = retInfo[name];
    				parts.forEach(function(name, i){
    					if (!name){
    						name = objInfo.nextIndex;
    						objInfo.nextIndex++;
    					}
    					
    					var diggitName = /^\d+$/.test(name);
    					if (!diggitName) objInfo.onlyDiggits = false;
    					
    					if (i == partsLength - 1) obj[name] = value;
    					else {
    						if (!is.object(obj[name])){
    							obj[name] = {};
    							objInfo.subObjects[name] = {nextIndex: 0, subObjects: {}, onlyDiggits: true};
    						}
    						if (diggitName){
    							if (name > objInfo.nextIndex){
    								objInfo.nextIndex = parseInt(name, 10) + 1;
    							}
    						}
    						obj = obj[name];
    						objInfo = objInfo.subObjects[name];
    					}
    				});
    			}
    		}
    		function toArrayIfPossible(obj, objInfo){
    			if (!is.object(obj)) return obj;
    			var ret = objInfo.onlyDiggits? []: obj;
    			for (var i in obj){
    				if (obj.hasOwnProperty(i)){
    					ret[i] = toArrayIfPossible(obj[i], objInfo.subObjects[i]);
    				}
    			}
    			return ret;
    		}
    		return toArrayIfPossible(ret, {onlyDiggits: false, subObjects: retInfo});
    	},
    	stringify: function stringify(value){
    		var stringifyStack = [];
    		function process(value, namescope){
    			// recursion detection
    			if (stringifyStack.indexOf(value) > -1) throw new TypeError("recursive structure");
    			stringifyStack.push(value);
    			
    			namescope = (namescope || "");
    			var ret = [];
    			if (namescope && is.array(value)){
    				var name = namescope + "[";
    				value.forEach(function(value, i){
    					ret.push(process(value, name + i + "]"));
    				});
    			}
    			else if (is.object(value)){
    				for (var name in value){
    					if (value.hasOwnProperty(name)){
    						var v = value[name];
    						if (namescope) name = namescope + "[" + name + "]";
    						ret.push(process(v, name));
    					}
    				}
    			}
    			else {
    				stringifyStack.pop();
    				return encodeURIComponent(namescope) + "=" + encodeURIComponent(value)
    			}
    			
    			stringifyStack.pop();
    			return ret.join("&");
    		}
    		
    		return process(value);
    	}
    };
    Für (konstruktive) Kritik, Verbesserungsvorschläge und v.A. beobachtete Bugs bin ich euch sehr dankbar.

    EDIT: rekursive Objekte jetzt "erlaubt"... es kommt hald eine Fehlermeldung...
    Geändert von kkapsner (20-09-2011 um 03:00 Uhr)

  2. #2
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.702

    AW: queryString Parser und Stringifier

    MIST - ich hab' natürlich das is-Objekt vergessen:
    Code:
    var OptS = Object.prototype.toString;
    var is = {
    	array: function(obj){
    		return OptS.call(obj) == "[object Array]";
    	},
    	object: function(obj){
    		return (typeof obj == "object" && obj !== null);
    	},
    	number: function(num){
    		switch (typeof num){
    			case "number": return !isNaN(num);
    			case "object": return OptS.call(num) == "[object Number]" && !isNaN(num);
    			default: return false;
    		}
    	},
    	string: function(str){
    		switch (typeof str){
    			case "string": return true;
    			case "object": return OptS.call(str) == "[object String]";
    			default: return false;
    		}
    	},
    	'boolean': function(bool){
    		switch (typeof bool){
    			case "boolean": return true;
    			case "object": return OptS.call(bool) == "[object Boolean]";
    			default: return false;
    		}
    	},
    	'function': function(func){
    		switch (typeof func){
    			case "function": return true;
    			case "object": return OptS.call(func) == "[object Function]";
    			default: return false;
    		}
    	},
    	'true': function(tr){
    		return (tr && is['boolean'](tr));
    	},
    	'false': function(fl){
    		return (!fl && is['boolean'](fl));
    	},
    	'undefined': function(un){
    		return (un === null || (typeof un == "undefined"));
    	},
    	defined: function(def){
    		return !is.undefined(def);
    	},
    	'null': function(nu){
    		return (nu === null);
    	},
    	key: function(array, key){
    		if (is['undefined'](array)) return false;
    		if (key in array) return true;
    		return (typeof array[key] != "undefined");
    	},
    	node: function(node){
    		if (!is.object(node)) return false;
    		try {
    			/*problem in IE6 with DOM.compatible created Element*/
    			if (typeof Element != "undefined" && node instanceof Element) return true;
    		}catch(e){}
    		return (
    			is.key(node, "nodeName") &&
    			is.key(node, "nodeType") &&
    			is.key(node, "nodeValue")
    		);
    	},
    	opera: !!window.opera && window.opera.toString() == "[object Opera]", // /opera/i.test(navigator.userAgent),
    	safari: /safari/i.test(navigator.userAgent),
    	ie: /*@cc_on @if (@_jscript) true, @else @*/ (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)), /*@end @*/
    	version: (/(msie|firefox|opera)[\/\s]((\d+\.?)+)/i.exec(navigator.userAgent))?/(msie|firefox|opera)[\/\s]((\d+\.?)+)/i.exec(navigator.userAgent)[2]: Number.NaN,
    	gecko: /gecko/i.test(navigator.userAgent),
    	ff: /firefox/i.test(navigator.userAgent)
    };
    - ohne das wird's natürlich schwer mit testen...

    Hab' euch noch eine Testumgebung gebastelt: http://kkjs.kkapsner.de/tests/QueryString_test.html

  3. #3
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.702

    AW: queryString Parser und Stringifier

    Nicht mal einer eine Meinung dazu?

  4. #4
    Avatar von Albu
    Albu ist offline Foren-Gott
    registriert
    04-07-2001
    Beiträge
    13.501

    AW: queryString Parser und Stringifier

    Also mir fehlt im Moment so der Use-Case hinter der Sache, bislang habe ich eine solche Funktionalität noch nicht wirklich vermisst.
    Und ich vermute vielen Benutzern fehlen konkrete Beispiele, wie sie den Code überhaupt zum Einsatz bringen können.
    1. Get people to play Space Taxi
    2. Sell real estates on neptun
    3. Profit!

    IE is not a browser, it is a scream.


    Outside of a dog, a book is man's best friend. Inside of a dog, it's too dark to read.

  5. #5
    Avatar von kkapsner
    kkapsner ist offline Super Moderator
    registriert
    28-03-2008
    Beiträge
    17.702

    AW: queryString Parser und Stringifier

    OK - ich hab' sowas ähnliches schon öfter gebaut (nur nicht so explizit mit den eckigen Klammern).
    Man kann mit der .parse-Funktion beliebige GET-Parameter ins JS holen (z.B. s. http://forum.jswelt.de/javascript/55...speichern.html (URL Parameter in Variable speichern) oder ich verwende das auch in meinem Framework um Module zu laden: .../modules/kkjs.load.js?modules=QueryString) und man muss sich nicht serverseitig darum kümmern, dass kompliziertere Strukturen auch ins JS kommen.
    Bei der .stringify-Funktion hab' ich v.A. an AJAX gedacht: ich empfinde es im Quelltext lesbarer, die übergebenen POST-Parameter in einem Objekt zu schreiben, als in einem String - aber man kann damit natürlich auch location.query sehr elegant manipulieren (mal angenommen, man will einen Parameter key=value haben, dann muss man sich keine Gedanken machen, ob dieser schon vorhanden ist - einfach ein .parse(location.query), im Objekt .key = value (wenn schon vorhanden wird's einfach überschrieben) und dann location.query = .stringify(Objekt) - sollte theoretisch nicht einmal die Seite neu laden, wenn key=value schon vorhanden ist, da die meisten Browser im for...in die Eintragsreihenfolge beibehalten).

Ähnliche Themen

  1. Variablen per QueryString übergeben
    Von Hendrik1992 im Forum JavaScript
    Antworten: 14
    Letzter Beitrag: 10-06-2010, 13:20
  2. '#' im Querystring
    Von KFlash im Forum Allgemeines
    Antworten: 5
    Letzter Beitrag: 21-09-2006, 17:04
  3. neues fenster + querystring
    Von tux_muc im Forum JavaScript
    Antworten: 4
    Letzter Beitrag: 12-05-2006, 15:52
  4. QueryString abfragen
    Von the-one im Forum JavaScript
    Antworten: 4
    Letzter Beitrag: 04-08-2005, 10:46
  5. Problem mit QueryString Codierung
    Von hupfer im Forum JavaScript
    Antworten: 1
    Letzter Beitrag: 24-03-2005, 11:58

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •