我正在使用 SignalR 向我的 JavaScript 客户端返回一个复杂的对象图。此对象图对同一个对象有多个引用,因此 SignalR/Json.NET 返回的 JSON 看起来很像这样:
{
"$id": "57",
"Name": "_default",
"User": {
"$id": "58",
"UserTag": "ken",
"Sessions": [{
"$id": "59",
"SessionId": "0ca7474e-273c-4eb2-a0c1-1eba2f1a711c",
"User": {
"$ref": "58"
},
"Room": {
"$ref": "57"
}
}],
},
"Sessions": [{
"$ref": "59"
}]
}
(当然,在现实生活中要复杂得多,但你明白了。)
当然,当 Json.NET 通过引用而不是通过值进行序列化时,它会为每个对象分配一个 $id 值(例如,"$id":"57",然后稍后只是使用该 id 引用该对象(例如,"$ref":"57"。据我所知,当它是 Json.NET(使用 C#/.NET)时反序列化这些引用,它将对象的适当实例放在适当的位置。
到目前为止一切都很好 - 但在 JavaScript 中反序列化这些 的最佳方法是什么,以便我实际上在适当的位置获得适当的对象实例,而不仅仅是奇怪的 $ref 字段?
我大概可以编写我自己的通用反序列化器,但我必须想象其他人已经解决了这个问题,我不会重新发明任何轮子。不幸的是,我的 Google 技能显然不足以找到该解决方案:-)。
编辑:
我看到有一个 IETF draft proposal关于这种事情应该如何运作。看起来总是乐于助人的道格拉斯克罗克福德有一个 tentative implementation它的。遗憾的是,IETF 提案使用的架构与 Json.NET 使用的架构不同。
最佳答案
嗯,我想这就可以了。我修改了 Crockford 的 cycle.js处理 Json.NET 使用的引用格式。而且因为 TypeScript 是一种无法形容的比 JavaScript 更好的语言,所以我用 TS 重写了它。我当然不会发誓它没有错误(如果有人指出它们,我会尝试修复它们),但它似乎可以处理我到目前为止抛给它的复杂对象图。
export function retrocycle(obj: any): void {
var catalog: any[] = [];
catalogObject(obj, catalog);
resolveReferences(obj, catalog);
}
function catalogObject(obj, catalog: any[]):void {
// The catalogObject function walks recursively through an object graph
// looking for $id properties. When it finds an object with that property, then
// it adds it to the catalog under that key.
var i: number;
if (obj && typeof obj === 'object') {
var id:string = obj.$id;
if (typeof id === 'string') {
catalog[id] = obj;
}
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
catalogObject(obj[i], catalog);
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
catalogObject(obj[name], catalog);
}
}
}
}
}
function resolveReferences(obj: any, catalog: any[]) {
// The resolveReferences function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is an id, then it
// replaces the $ref object with a reference to the object that is found in the catalog under
// that id.
var i:number, item:any, name:string, id:string;
if (obj && typeof obj === 'object') {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
item = obj[i];
if (item && typeof item === 'object') {
id = item.$ref;
if (typeof id === 'string') {
obj[i] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
item = obj[name];
if (item) {
id = item.$ref;
if (typeof id === 'string') {
obj[name] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
}
}
}
}
和等效的 JS:
function retrocycle(obj) {
var catalog = [];
catalogObject(obj, catalog);
resolveReferences(obj, catalog);
}
function catalogObject(obj, catalog) {
var i;
if (obj && typeof obj === 'object') {
var id = obj.$id;
if (typeof id === 'string') {
catalog[id] = obj;
}
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
catalogObject(obj[i], catalog);
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
catalogObject(obj[name], catalog);
}
}
}
}
}
function resolveReferences(obj, catalog) {
var i, item, name, id;
if (obj && typeof obj === 'object') {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
item = obj[i];
if (item && typeof item === 'object') {
id = item.$ref;
if (typeof id === 'string') {
obj[i] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
item = obj[name];
if (item) {
id = item.$ref;
if (typeof id === 'string') {
obj[name] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
}
}
}
}
您可以像这样使用它(假设您已连接 SignalR 集线器):
$.connection.roomHub.server.joinRoom()
.done(function(room) {
retrocycle(room);
});
我还在 BitBucket 上为它创建了一个快速而简单的小存储库: https://bitbucket.org/smithkl42/jsonnetdecycle .
关于javascript - 使用 JavaScript 反序列化来自 SignalR/Json.NET 的复杂对象图中的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13782052/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h