Objects from streams

R

RebelGeekz

I am trying to create objects sent as streams over the wire but I am
no expert in javascript, can anybody lend me a hand please?

// this works, no problem at all
client = {name:'John Doe', age:35};
alert(client.name);

// this doesn't
stream = "{name:'Jane Doe', age:32}";
person = eval(stream);
alert(person.name);

The whole idea is to request data to a back-end, then the server will
produce streams in the javascript format that will be used to create
objects on the client side.

The question is: how to use the stream as object initializer? I tried
'eval' but didn't work, maybe I'm doing it wrong. Any other ideas?

Thanks in advance
 
M

Martin Honnen

RebelGeekz said:
I am trying to create objects sent as streams over the wire but I am
no expert in javascript, can anybody lend me a hand please?

// this works, no problem at all
client = {name:'John Doe', age:35};
alert(client.name);

// this doesn't
stream = "{name:'Jane Doe', age:32}";
person = eval(stream);
alert(person.name);

If you use

eval('person = ' + stream);

it should work. The problem is that {} is used both to delimit object
literals as well as statement blocks thus if you have some code starting
with { it is considered the start of a block and not the start of an
object literal.
 
L

Lasse Reichstein Nielsen

I am trying to create objects sent as streams over the wire but I am
no expert in javascript, can anybody lend me a hand please?

// this works, no problem at all
client = {name:'John Doe', age:35};
alert(client.name);

// this doesn't
stream = "{name:'Jane Doe', age:32}";
person = eval(stream);
alert(person.name);

You have found a use for eval, that isn't bad. Good job :) Anyway, the
content of the string sent to eval, is assumed to be Javascript
statements, not a single expression. When it sees a "{" in that
context, it assumes that it is the start of a block. To avoid this,
just wrap the expression in parentheses:
person = eval("("+stream+")");
or use the Function constructor:
person = Function("return "+stream+";")();
The question is: how to use the stream as object initializer? I tried
'eval' but didn't work, maybe I'm doing it wrong.

Yep. :)

/L
 
R

Rebel Geekz

Thanks for the tip Lasse,

I guess I would use it like this:

// stream will be sent from the server
stream = "Client = {name:'Jane Doe', age:32}";
eval(stream);

this way it would be easier for me to produce the streams from the
server and use them in the client.

I also found some code to convert the object to a stream like netscape
object.ToSource(), really cool stuff.

Thanks all
 
R

Rebel Geekz

Thanks again Martin,

The whole idea is to make httpRequests to my data server which is going
to produce javascript objects (jso), trying to implement an easier
architecture for sharing objects accross boundaries.

That way it would be easier to get/set objects from/to the data server
and use them in my web forms. No bloated xml parsing at all ;-)

With a simple call like this I could get any object I need:

xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("GET",
"http://myDataServer.com/GetObject.asp?invoice=123456", true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
invoice = eval(xmlhttp.responseText);
// do something with the invoice
alert(invoice.total);
}
}
xmlhttp.send(null)

then binding the object to the web form and sending it back to the
server without having to submit/reload the page

Sort of interactive web application with simple web services, if we can
call it that way ;-)

Don't know yet, just playing
 
L

Lasse Reichstein Nielsen

Rebel Geekz said:
Here is a sample for those who've been following:

http://georgenava.com/samples/sodascript.html

Feel free to share ideas ;-)

It appears to be IE only, so I haven't tested it.

Looking at the ToStream function, it has a problem with objects and
strings.

For objects, the properties can be any string, not only those that
are valid identifiers, for the object
{"foo bar":42}
you will generate
{foo bar:42}
which is a syntax error. Even worse is the object
{"foo:42,bar":43}
which has only one property with the name "foo:42,bar". You write
it as
{foo:42,bar:43}
a completely different, but syntactically legal object.

I recommend treating the key as a string and use the same transformation
as on strings. Perhaps test whether the key is a valid identifier,
/^[$_\w]+$/.test(key)&&!/^\d/.test(key), and only treat it as a string
otherwise.

That brings me to strings. You only replace backspace and quotes. You
alos need to escape the non-printable characters, newlines etc. Try
making this string into a stream: "hello\nworld". The newline is sent
verbatim, and newlines are not allowed inside string literals.

I made this recently:
---
var escapes = ["b","t","n","v","f","r"]

function LZ(str,n) {
n = n||2;
str = String(str);
while(str.length<n) {str = "0"+str;}
return str;
}

function stringToSource(string) {
var chars = string.split("");
for (var i=0;i<chars.length;i++) {
var code = chars.charCodeAt(0);
if (code<32) {
if (code >=8 && code <=13) {
chars="\\"+escapes[code-8];
} else {
chars="\\x"+LZ(code.toString(16));
}
} else if (chars=="\"" || chars=="\\") {
chars="\\"+chars;
} else if (code>=128 && code < 192) {
chars="\\x"+LZ(code.toString(16));
} else if (code >= 256) {
chars="\\u"+LZ(code.toString(16),4);
}
}
return "\""+chars.join("")+"\"";
}
---

I guess there could be problems with RegExps too, but I haven't looked
into it.

Good luck.

/L
 
S

Steve van Dongen

I am trying to create objects sent as streams over the wire but I am
no expert in javascript, can anybody lend me a hand please?

// this works, no problem at all
client = {name:'John Doe', age:35};
alert(client.name);

// this doesn't
stream = "{name:'Jane Doe', age:32}";
person = eval(stream);
alert(person.name);

The whole idea is to request data to a back-end, then the server will
produce streams in the javascript format that will be used to create
objects on the client side.

The question is: how to use the stream as object initializer? I tried
'eval' but didn't work, maybe I'm doing it wrong. Any other ideas?

XML parsing isn't that bad...

Anyways, I wrote this quite a while ago and for some reason never used
it. I'm pretty sure it correctly handles all native Javascript
datatypes. (My test code is commented out at the bottom.) It might
help.

Regards,
Steve

function Serialize(obj)
{
if (typeof navigator != "undefined" && navigator.appName ==
'Netscape')
{
return( obj.toSource() );
}

var strSource = "";

if (typeof(obj) == "undefined")
{
strSource = "undefined";
}

else if (obj == null)
{
strSource = "null";
}

else if (typeof(obj) == "boolean" || typeof(obj) == "number" ||
typeof(obj) == "function")
{
strSource = obj;
}

else if (typeof(obj) == "string")
{
strSource = "'" + obj.replace(/([\\'"])/g, "\\$1") + "'";
}

else if (typeof(obj) == "object")
{
if (obj.constructor == Boolean)
{
strSource = "new Boolean(" + obj.valueOf() + ")";
}

else if (obj.constructor == Number)
{
strSource = "new Number(" + obj.valueOf() + ")";
}

else if (obj.constructor == String)
{
strSource = "new String(" + Serialize(obj.toString()) +
")";
}

else if (obj.constructor == Date)
{
strSource = "new Date(" + obj.valueOf() + ")";
}

else if (obj.constructor == Array)
{
strSource = "[";
for (var i=0; i<obj.length; i++)
strSource += Serialize(obj) + ",";
if (i>0)
strSource = strSource.substring(0,
strSource.length-1);
strSource += "]";
}

else if (obj.constructor == RegExp)
{
strSource = obj.toString();
}

else if (obj.constructor == Object)
{
var strSource = "{"
for (var key in obj)
strSource = strSource + "" + key + ":" +
Serialize(obj[key]) + ","
if (strSource.length > 1)
strSource = strSource.substring(0,
strSource.length-1);
strSource += "}";
}
}

else
{
throw new Error(0, "Serialize encountered unexpected object
type: " + typeof(obj));
}

return strSource;
}

function Deserialize(strSource)
{
if (typeof strSource != "string")
throw new Error(0, "Deserialize expects a string
argument");

var x;
return eval("x = " + strSource);
}

/*
var anObject = {
a: null,
b: 3442,
c: 'aks\\\'ldf8',
d: /te\st/,
e: true,
f: function () { return 't\est' },
g: [],
h: ['asdf','sdf',2343],
i: new Boolean(),
j: new Number(-23),
k: new String('foo\\bar'),
l: new Date(),
m: undefined,
n: { a: 'abc' }
}

var x = Deserialize(Serialize(anObject));
var s = "";
for (var p in anObject)
{
s += p + ": " + anObject[p] + " == " + x[p] + "\n";
}
WScript.Echo(s);
*/
 
W

Willie Lau

Please take a look at Douglas Crockford's JavaScript Object Notation
(JSON) at http://www.json.org

The following function may help with your needs.

parseJSON = function(jsonString)
{
eval('function parseJSON(){return ' + jsonString + ';}');
return parseJSON();
};

In your case, it allows your stream to remain as "{name:'Jane Doe',
age:32}".
You can then assign to Client using:

Client = parseJSON(stream);

Regards,
Willie Lau
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top