Javascript 如何从Json.NET序列化的Json恢复循环引用(例如“$id”)?
是否有一个现有的javascript库可以使用引用循环处理反序列化Json.NetJavascript 如何从Json.NET序列化的Json恢复循环引用(例如“$id”)?,javascript,json,serialization,circular-reference,Javascript,Json,Serialization,Circular Reference,是否有一个现有的javascript库可以使用引用循环处理反序列化Json.Net { "$id": "1", "AppViewColumns": [ { "$id": "2", "AppView": {"$ref":"1"}, "ColumnID": 1, } ] } 这应该反序列化到一个对象,该对象在数组中的对象和外部对象之间有一个引用循环,但是可以使用标准的JS
{
"$id": "1",
"AppViewColumns": [
{
"$id": "2",
"AppView": {"$ref":"1"},
"ColumnID": 1,
}
]
}
这应该反序列化到一个对象,该对象在数组中的对象和外部对象之间有一个引用循环,但是可以使用标准的
JSON.parse
方法,然后手动遍历恢复循环引用的结果——这只是一个基于$id属性的简单存储/查找。(类似的方法可用于逆转过程。)
下面是一些使用这种方法的示例代码。这段代码假设JSON已经被解析为相关的JS对象图——它还修改了提供的数据。YMMV
function restoreJsonNetCR(g) {
var ids = {};
function relink (s) {
// we care naught about primitives
if (s === null || typeof s !== "object") { return s; }
var id = s['$id'];
delete s['$id'];
// either return previously known object, or
// remember this object linking for later
if (ids[id]) {
return ids[id];
}
ids[id] = s;
// then, recursively for each key/index, relink the sub-graph
if (s.hasOwnProperty('length')) {
// array or array-like; a different guard may be more appropriate
for (var i = 0; i < s.length; i++) {
s[i] = relink(s[i]);
}
} else {
// other objects
for (var p in s) {
if (s.hasOwnProperty(p)) {
s[p] = relink(s[p]);
}
}
}
return s;
}
return relink(g);
}
DrSammyD创建了一个下划线插件变体。好的,所以我创建了一个更健壮的方法,它将使用$id和$ref,因为json.net实际上就是这样处理循环引用的。此外,您必须在注册id后获取引用,否则它将找不到被引用的对象,因此我还必须保留请求引用的对象,以及它们要设置的属性和它们请求的id 这在很大程度上是基于lodash/下划线的
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['lodash'], factory);
} else {
factory(_);
}
})(function (_) {
var opts = {
refProp: '$ref',
idProp: '$id',
clone: true
};
_.mixin({
relink: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.relink.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var ids = {};
var refs = [];
function rl(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
if (s[options.refProp]) {
return null;
}
if (s[options.idProp] === 0 || s[options.idProp]) {
ids[s[options.idProp]] = s;
}
delete s[options.idProp];
_(s).pairs().each(function (pair) {
if (pair[1]) {
s[pair[0]] = rl(pair[1]);
if (s[pair[0]] === null) {
if (pair[1][options.refProp] !== undefined) {
refs.push({ 'parent': s, 'prop': pair[0], 'ref': pair[1][options.refProp] });
}
}
}
});
return s;
}
var partialLink = rl(obj);
_(refs).each(function (recordedRef) {
recordedRef['parent'][recordedRef['prop']] = ids[recordedRef['ref']] || {};
});
return partialLink;
},
resolve: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.resolve.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var objs = [{}];
function rs(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
var replacementObj = {};
if (objs.indexOf(s) != -1) {
replacementObj[options.refProp] = objs.indexOf(s);
return replacementObj;
}
objs.push(s);
s[options.idProp] = objs.indexOf(s);
_(s).pairs().each(function (pair) {
s[pair[0]] = rs(pair[1]);
});
return s;
}
return rs(obj);
}
});
_(_.resolve.prototype).assign({ opts: opts });
_(_.relink.prototype).assign({ opts: opts });
});
我创建了一个,给出的答案几乎对我有用,但最新版本的MVC、JSON.Net和DNX使用了“$ref”和“$id”,它们可能不符合顺序。所以我修改了user2864740的答案 我应该注意,这段代码不处理数组引用,这也是可能的
函数RestoreJsonNetReferences(g){
变量id={};
函数getID(s){
//我们根本不关心原语
如果(s===null | | typeof s!==“object”){返回s;}
var id=s['$id'];
如果(id的类型!=“未定义”){
删除s['$id'];
//返回以前已知的对象,或
//请记住此对象链接供以后使用
if(id[id]){
抛出“找到重复ID”+ID+”;
}
id[id]=s;
}
//然后,递归地为每个键/索引重新链接子图
如果(s.hasOwnProperty('length')){
//阵列或类似阵列;不同的防护可能更合适
对于(变量i=0;i }
是的,在浏览器中,我还希望它以相同的方式再次序列化。这是我正在使用的要点的最终版本相关或重复:。我想我们还需要一个重新序列化程序。。。我可能会让它成为lodash的插件/underscore@DrSammyD如果你想从另一个方向回去,那么是的。但是-也许您不需要这两个方向的额外数据?我刚刚创建了一个双向的JSFIDLE。你愿意把它包括在你的答案里吗@DrSammyD可以随意编辑答案(或添加您自己的答案)。我加入了fiddle链接,以便更方便地使用。对于dnx中最新版本的JSON.Net,这对我来说不起作用。它同时使用“$id”和“$ref”,它们可能出现故障。我已经修改了你的答案。数组引用是指“$values”
?我遇到了这个问题,通过检查p==“$values”
,然后用重新链接替换s
,而不是更新s[p]
(即s[“$values”]
)似乎可以解决这个问题。。如果这有道理的话。
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['lodash'], factory);
} else {
factory(_);
}
})(function (_) {
var opts = {
refProp: '$ref',
idProp: '$id',
clone: true
};
_.mixin({
relink: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.relink.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var ids = {};
var refs = [];
function rl(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
if (s[options.refProp]) {
return null;
}
if (s[options.idProp] === 0 || s[options.idProp]) {
ids[s[options.idProp]] = s;
}
delete s[options.idProp];
_(s).pairs().each(function (pair) {
if (pair[1]) {
s[pair[0]] = rl(pair[1]);
if (s[pair[0]] === null) {
if (pair[1][options.refProp] !== undefined) {
refs.push({ 'parent': s, 'prop': pair[0], 'ref': pair[1][options.refProp] });
}
}
}
});
return s;
}
var partialLink = rl(obj);
_(refs).each(function (recordedRef) {
recordedRef['parent'][recordedRef['prop']] = ids[recordedRef['ref']] || {};
});
return partialLink;
},
resolve: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.resolve.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var objs = [{}];
function rs(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
var replacementObj = {};
if (objs.indexOf(s) != -1) {
replacementObj[options.refProp] = objs.indexOf(s);
return replacementObj;
}
objs.push(s);
s[options.idProp] = objs.indexOf(s);
_(s).pairs().each(function (pair) {
s[pair[0]] = rs(pair[1]);
});
return s;
}
return rs(obj);
}
});
_(_.resolve.prototype).assign({ opts: opts });
_(_.relink.prototype).assign({ opts: opts });
});