Is there a javascript serializer for JSON.Net? - javascript

I am using Newtonsoft JSON.Net to deserialize an object with PreserveReferencesHandling enabled. jQuery does not support relinking references based on the $ref and $id syntax JSON.Net uses (I don't know if jQuery supports this functionality in any capacity).
I tried using Douglas Crockford's cycle.js but that does not seem to work with my objects, the returned object is identical to the object which got passed in.
I am not incredibly familiar with JSON.Net, but I cannot seem to find any javascript libraries which would serialize (or parse) the JSON their .NET component outputs.
How can I accomplish putting back together object references?

I was looking for a solution to this problem as well, and ended up hacking Douglas Crockford's JSON.retrocycle function. His function does not work for the $ref=some number, but it looks for something like an xpath.
This is my quick and dirty version - don't use this as is - I'm not doing any cleanup, and it probably should be a plugin, but it does the job and is good enough to get going:
function retrocycle(o) {
var self = this;
self.identifiers = [];
self.refs = [];
self.rez = function (value) {
// The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by
// the path.
var i, item, name, path;
if (value && typeof value === 'object') {
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (i = 0; i < value.length; i += 1) {
item = value[i];
if (item && typeof item === 'object') {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[i] = self.identifiers[parseInt(path)]
} else {
self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
} else {
for (name in value) {
if (typeof value[name] === 'object') {
item = value[name];
if (item) {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[name] = self.identifiers[parseInt(path)]
} else {
self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
}
}
}
};
self.rez(o);
self.identifiers = [];
}
Use it like this:
$.post("url/function", { ID: params.ID }, function (data) {
retrocycle(data)
// data references should be fixed up now
}, "json");

You would have to write in a double look-up into your js parser. Technically preserving reference handling is to get around circular references, which is to say what would normally cause a stack overflow during parsing.
JSON does not have a native syntax for handling this. Newtonsoft version is a custom implementation, thus parsing the JSON will be a custom implementation.
If you really have to preserve such references, XML may be a better solution. There are some json->xml libraries out there.
Here is one solution for parsing that may be of use, or at least a guide:
https://blogs.oracle.com/sundararajan/entry/a_convention_for_circular_reference

This is my enhanced version of #Dimitri. #Dimitri code sometimes isn't able to rebuild the references. If anyone improves the code, please, tell me.
Regards,
Marco Alves.
if (typeof JSON.retrocycle !== 'function') {
JSON.retrocycle = function retrocycle(o) {
//debugger;
var self = this;
self.identifiers = [];
self.refs = [];
self.buildIdentifiers = function (value) {
//debugger;
if (!value || typeof value !== 'object') {
return;
}
var item;
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (var i = 0; i < value.length; i += 1) {
item = value[i];
if (!item || !item.$id || isNaN(item.$id)) {
if (item) {
self.buildIdentifiers(item);
}
continue;
}
self.identifiers[parseInt(item.$id)] = item;
self.buildIdentifiers(item);
}
return;
}
for (var name in value) {
if (typeof value[name] !== 'object') {
continue;
}
item = value[name];
if (!item || !item.$id || isNaN(item.$id)) {
if (item) {
self.buildIdentifiers(item);
}
continue;
}
self.identifiers[parseInt(item.$id)] = item;
self.buildIdentifiers(item);
}
};
self.rez = function (value) {
// The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by
// the path.
var i, item, name, path;
if (value && typeof value === 'object') {
if (Object.prototype.toString.apply(value) === '[object Array]') {
for (i = 0; i < value.length; i += 1) {
item = value[i];
if (item && typeof item === 'object') {
if (item.$ref)
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[i] = self.identifiers[parseInt(path)];
continue;
}
//self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
} else {
for (name in value) {
if (typeof value[name] === 'object') {
item = value[name];
if (item) {
path = item.$ref;
if (typeof path === 'string' && path != null) {
//self.refs[parseInt(path)] = {};
value[name] = self.identifiers[parseInt(path)];
continue;
}
//self.identifiers[parseInt(item.$id)] = item;
self.rez(item);
}
}
}
}
}
};
self.buildIdentifiers(o);
self.rez(o);
self.identifiers = []; // Clears the array
};
}

Related

copy object in javascript

I want to copy object from "xwalk.utils.converter" to "xwalk.converter"
the converter has these functions.
Is it available copy of object? otherwise alias?
xwalk.utils.converter.toArray
xwalk.utils.converter.toBoolean
xwalk.utils.converter.toByte
xwalk.utils.converter.toDictionary
xwalk.utils.converter.toDouble
xwalk.utils.converter.toEnum
xwalk.utils.converter.toFunction
xwalk.utils.converter.toLong
xwalk.utils.converter.toLongLong
xwalk.utils.converter.toOctet
xwalk.utils.converter.toPlatformObject
xwalk.utils.converter.toShort
xwalk.utils.converter.toUnsignedLong
xwalk.utils.converter.toUnsignedLongLong
xwalk.utils.converter.toUnsignedShort
Untested code, which recursively copies the elements:
function copy(src) {
var destination = {};
for (var index in src) {
if (typeof src[index] === "object") {
destination[index] = copy(src[index]);
} else if (Array.isArray(src[index])) {
destination[index] = [];
for (var arrIndex in src[index]) {
if ((typeof src[index][arrIndex] === "object") || (Array.isArray(src[index][arrIndex]))) {
destination[index][arrIndex] = copy(src[index][arrIndex]);
} else {
destination[index][arrIndex] = src[index];
}
}
} else {
destination[index] = src[index];
}
}
return destination;
}
Usage:
xwalk.converter = xwalk.utils.converter;
Use this function:
var copy = function(from, to) {
for (var prop in from) {
if (from.hasOwnProperty(prop)) {
to[prop] = from[prop];
}
}
};
copy(xwalk.utils.converter,xwalk.converter);

Javascript creating object in if not carrying over

This is my code:
var cleanname = v.name.replace(/\s/g, "_").toLowerCase();
if(typeof(kpiValues[v.category]) === "undefined") {
kpiValues[v.category] = {};
if(typeof(kpiValues[v.category][cleanname] === "undefined")) {
kpiValues[v.category][cleanname] = [];
}
}
if(departments !== "default") {
if(typeof(kpiValues[v.category][cleanname][0]) === "undefined") {
kpiValues[v.category][cleanname][0] = {};
kpiValues[v.category][cleanname][0].value = 0;
}
}
This line:
if(typeof(kpiValues[v.category][cleanname][0]) === "undefined") {
throws me an error, and I am completely confused on why. In the first if-block, I ensure it builds out the object/array, but for some reason that I can't understand, it throws this error:
TypeError: Cannot read property '0' of undefined
Any suggestions?
typeof is not a function in Javascript so you can use like
typeof oprand
Consider this:
if(typeof kpiValues[v.category][cleanname][0] === "undefined") {

Traverse nested object and change values

I've got an object containing user-data alongside some dates. I'd like to format these dates (as they are delivered like this 2015-02-13T18:25:37+01:00).
I'd like to have the values of the object changed in-place but how can I do this?
I traverse the object like this:
$.each(myObject, formatDates)
var isDate = function(value) {
return (value!==null && !isNaN(new Date(value)))
}
var formatDates = function(key, value){
if (isDate(value)) {
// Change value here
console.log("key:" + key + " value: " + value)
}
// Recursive into child objects
if (value !== null && typeof value === "object") {
$.each(value, formatDates)
}
}
You can use this
function iterate(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property]);
} else {
// do your date thing
}
}
}
return obj;
}
iterate(object)

Node WebDriverJS executeScript behaviour

I have a WebDriverJS Node script with the following in the global scope of the application:
var helperFunctions = {
'getElementEssentials': function get(orig, tmp, level) {
var tmp = tmp || {};
var level = level || 0;
for(var i in orig) {
if(!orig[i]) { continue; }
if(typeof(orig[i]) === 'function' || typeof(orig[i]) === 'object' || level > 1) { continue; }
if(typeof(orig[i]) === 'array') { level++; get(orig[i], tmp, level); continue; }
tmp[i] = orig[i]; continue;
}
return tmp;
}
};
I want to pass this function in to driver.executeScript using something like this:
var evalSelectAll = function(selector, getElementEssentials) {
var els = document.querySelectorAll(selector);
var els2 = [];
for(var i in els) {
els2.push(getElementEssentials(els[i]));
}
var elsStringified = JSON.stringify(els2);
return elsStringified;
};
driver.executeScript(evalSelectAll, selector, helperFunctions.getElementEssentials).then( function(data) {
// things
});
selector relates to a CSS selector expression, so "a" or "div > h1" for example.
My understanding of executeScript is that for the first argument it can accept either a string or a function - a string will be evaluated on the target page, and a function will be executed on the target page, and that all subsequent arguments are additional data?
I get the following error when trying to run this (note that to keep things simple I just passed in a test object of {test: true}:
D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:1643
throw error;
^
UnknownError: {"errorMessage":"'function get(orig, tmp, level) {\r\n\t var tmp = tmp || {};\r\n\t var level = level || 0;\r\n\t for(var i in orig) {\r\n\t if(!orig[i]) { continue; }\r\n\t if(typeof(orig[i]) === 'function' || typeof(orig[i]) === 'object' || level > 1) { continue; }\r\n\t if(typeof(orig[i]) === 'array') { level++; get(orig[i], tmp, level); continue; }\r\n\t tmp[i] = orig[i]; continue;\r\n\t }\r\n\t return tmp;\r\n\t}' is not a function (evaluating 'getElementEssentials({test: true})')","request":{"headers":{"Accept":"application/json; charset=utf-8","Connection":"keep-alive","Content-Length":"903","Content-Type":"application/json;charset=UTF-8","Host":"192.168.0.7:56849"},"httpVersion":"1.1","method":"POST","post":"{\"script\":\"return (function (selector, getElementEssentials) {\\r\\n\\r\\n\\t\\t\\treturn getElementEssentials({test: true});\\r\\n\\r\\n\\t\\t\\tvar els = document.querySelectorAll(selector);\\r\\n\\t\\t\\t\\r\\n\\t\\t\\t/*var els2 = [];\\r\\n\\t\\t\\tfor(var i in els) {\\r\\n\\t\\t\\t\\tels2.push(getElementEssentials(els[i]));\\r\\n\\t\\t\\t}\\r\\n\\r\\n\\t\\t\\tvar elsStringified = JSON.stringify(els2);\\r\\n\\r\\n\\t\\t\\treturn elsStringified;*/\\r\\n\\r\\n\\t\\t}).apply(null, arguments);\",\"args\":[\"h1\",\"function get(orig, tmp, level) {\\r\\n\\t var tmp = tmp || {};\\r\\n\\t var level = level || 0;\\r\\n\\t for(var i in orig) {\\r\\n\\t
if(!orig[i]) { continue; }\\r\\n\\t if(typeof(orig[i]) === 'function' || typeof(orig[i]) === 'object' || level > 1) { continue; }\\r\\n\\t if(typeof(orig[i]) === 'array') { level++; get(orig[i], tmp, level); continue; }\\r\\n\\t tmp[i] = orig[i]; continue;\\r\\n\\t }\\r\\n\\t return tmp;\\r\\n\\t}\"]}","url":"/execute","urlParsed":{"anchor":"","query":"","file":"execute","directory":"/","path":"/execute","relative":"/execute","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/execute","queryKey":{},"chunks":["execute"]},"urlOriginal":"/session/c18c1ff0-0f25-11e4-a90e-a36273e3866b/execute"}}
at new bot.Error (D:\Git\mateserver\node_modules\selenium-webdriver\lib\atoms\error.js:109:18)
at Object.bot.response.checkResponse (D:\Git\mateserver\node_modules\selenium-webdriver\lib\atoms\response.js:106:9)
at D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:277:20
at D:\Git\mateserver\node_modules\selenium-webdriver\lib\goog\base.js:1243:15
at webdriver.promise.ControlFlow.runInNewFrame_ (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:1539:20)
at notify (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:362:12)
at notifyAll (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:331:7)
at resolve (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:309:7)
at fulfill (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:429:5)
at D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:1406:10
==== async task ====
WebDriver.executeScript()
at webdriver.WebDriver.schedule (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:268:15)
at webdriver.WebDriver.executeScript (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\webdriver.js:404:15)
at D:\Git\mateserver\main.js:174:11
at D:\Git\mateserver\node_modules\selenium-webdriver\lib\goog\base.js:1243:15
at webdriver.promise.ControlFlow.runInNewFrame_ (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:1539:20)
at notify (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:362:12)
at notifyAll (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:331:7)
at resolve (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:309:7)
at fulfill (D:\Git\mateserver\node_modules\selenium-webdriver\lib\webdriver\promise.js:429:5)
Any thoughts on this? Am I using executeScript correctly? Thanks.
Update: It seems that if I put the get function inside the evalSelectAll function then it works. It seems as though passing functions as arguments to executeScript is not supported. Can anybody confirm this? It would be nice to have the code be more reusable by staying outside the eval function.

Jath.js Xml parsing IE Error

I'm using jath.js to parse XML with Xpath selectors.
But in IE Version 10/9, I am getting the below error:
Object doesn't support property or method setProperty
Below is the jath source code which I'm using. I also tried the current version of the library and got the same error. My suspicion is that MS changed something in IEs XML Object. I hope you can help me.
(function() {
Jath = {};
Jath.parse = parse;
Jath.resolver = null;
// values prefixed with literal charactar marker will not be
// treated as xpath expressions and will be output directly
Jath.literalChar = ":";
/**
* Rudimentary check for IE
* Also added support for WSH, uses the same API as IE
*/
var m_browser;
if (typeof WScript != "undefined") {
m_browser = 'msie';
}
// TODO: is there a better way to detect node.js?
else if (typeof process != "undefined") {
// running under node.js
m_browser = 'node';
var xmljs = require('libxmljs');
exports.parse = parse;
}
else if (navigator.userAgent.toLowerCase().indexOf('msie') > -1) {
m_browser = 'msie';
}
else {
m_browser = 'standards';
}
/**
* parse:
* process xml doc according to the given json template
* #template - output spec as a json template
* #xmldoc - input xml document
* #node - the starting node to use in the document. xpath
* expressions will be evaluated relative to this node.
* If not given, root will be used.
*/
function parse(template, xmldoc, node) {
if (node === undefined) {
node = xmldoc;
}
if (typeOf(template) === 'array') {
return parseArray(template, xmldoc, node);
}
else if (typeOf(template) === 'object') {
return parseObject(template, xmldoc, node);
}
else {
return parseItem(template, xmldoc, node);
}
}
function parseArray(template, xmldoc, node) {
var retVal = [];
if (template[0] != null) {
if (m_browser == 'msie') {
xmldoc.setProperty("SelectionLanguage", "XPath");
var nodeList = node.selectNodes(template[0]);
var thisNode;
while (thisNode = nodeList.nextNode()) {
retVal.push(parse(template[1], xmldoc, thisNode));
}
}
else if (m_browser == 'node') {
var nodeList = node.find(template[0]);
for (var i = 0; i < nodeList.length; i++) {
retVal.push(parse(template[1], xmldoc, nodeList[i]));
}
}
else {
var xpathResult = xmldoc.evaluate(template[0], node, Jath.resolver, XPathResult.ANY_TYPE, null);
var thisNode;
while (thisNode = xpathResult.iterateNext()) {
retVal.push(parse(template[1], xmldoc, thisNode));
}
}
}
// we can have an array output without iterating over the source
// data - in this case, current node is static
else {
for (var i = 1; i < template.length; i++) {
retVal.push(parse(template[i], xmldoc, node));
}
}
return retVal;
}
function parseObject(template, xmldoc, node) {
var item;
var newitem = {};
for (item in template) {
newitem[item] = parse(template[item], xmldoc, node);
}
return newitem;
}
function parseItem(template, xmldoc, node) {
if (m_browser == 'msie') {
xmldoc.setProperty("SelectionLanguage", "XPath");
if (typeOf(template) == 'string' && template.substring(0, 1) != Jath.literalChar) {
return node.selectSingleNode(template).text;
}
else {
return template.substring(1);
}
}
else if (m_browser == 'node') {
require('util').puts(template);
return node.get(template).text();
}
else {
if (typeOf(template) == 'string' && template[0] != Jath.literalChar) {
return xmldoc.evaluate(template, node, Jath.resolver, XPathResult.STRING_TYPE, null).stringValue;
}
else {
return template.substring(1);
}
}
}
/**
* typeOf function published by Douglas Crockford in ECMAScript recommendations
* http://www.crockford.com/javascript/recommend.html
*/
function typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (typeof value.length === 'number' &&
!(value.propertyIsEnumerable('length')) &&
typeof value.splice === 'function') {
s = 'array';
}
} else {
s = 'null';
}
}
return s;
}
})();

Categories

Resources