标签归档:json

Web API:Handling Circular Object References

By default, the JSON and XML formatters write all objects as values. If two properties refer to the same object, or if the same object appears twice in a collection, the formatter will serialize the object twice. This is a particular problem if your object graph contains cycles, because the serializer will throw an exception when it detects a loop in the graph.
Consider the following object models and controller.

public class Employee
{
    public string Name { get; set; }
    public Department Department { get; set; }
}
public class Department
{
    public string Name { get; set; }
    public Employee Manager { get; set; }
}
public class DepartmentsController : ApiController
{
    public Department Get(int id)
    {
        Department sales = new Department() { Name = "Sales" };
        Employee alice = new Employee() { Name = "Alice", Department = sales };
        sales.Manager = alice;
        return sales;
    }
}

Invoking this action will cause the formatter to thrown an exception, which translates to a status code 500 (Internal Server Error) response to the client.
To preserve object references in JSON, add the following code to?Application_Start?method in the Global.asax file:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
    Newtonsoft.Json.PreserveReferencesHandling.All;

Now the controller action will return JSON that looks like this:

{"$id":"1","Name":"Sales","Manager":{"$id":"2","Name":"Alice","Department":{"$ref":"1"}}}

Notice that the serializer adds an “$id” property to both objects. Also, it detects that the Employee.Department? property creates a loop, so it replaces the value with an object reference: {“$ref”:”1″}.
Object references are not standard in JSON. Before using this feature, consider whether your clients will be able to parse the results. It might be better simply to remove cycles from the graph. For example, the link from Employee back to Department is not really needed in this example.
To preserve object references in XML, you have two options. The simpler option is to add[DataContract(IsReference=true)]?to your model class. The?IsReference?parameter enables oibject references. Remember that?DataContract?makes serialization opt-in, so you will also need to add?DataMember?attributes to the properties:

[DataContract(IsReference=true)]
public class Department
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public Employee Manager { get; set; }
}

Now the formatter will produce XML similar to following:

<Department xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="i1"
            xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
            xmlns="http://schemas.datacontract.org/2004/07/Models">
  <Manager>
    <Department z:Ref="i1" />
    <Name>Alice</Name>
  </Manager>
  <Name>Sales</Name>
</Department>

If you want to avoid attributes on your model class, there is another option: Create a new type-specificDataContractSerializer?instance and set?preserveObjectReferences?to?true?in the constructor. Then set this instance as a per-type serializer on the XML media-type formatter. The following code show how to do this:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
var dcs = new DataContractSerializer(typeof(Department), null, int.MaxValue,
    false, /* preserveObjectReferences: */ true, null);
xml.SetSerializer<Department>(dcs);

在Json中查找 Javascript search inside a JSON object

var jsonObj ={"list": [
  {"name":"my Name","id":12,"type":"car owner"},
  {"name":"my Name2","id":13,"type":"car owner2"},
  {"name":"my Name4","id":14,"type":"car owner3"},
  {"name":"my Name4","id":15,"type":"car owner5"}
]};
var results = [];
var searchField = "name";
var searchVal = "my Name";
for (var i=0 ; i < jsonObj.list.length ; i++)
{
  if (jsonObj.list[i][searchField] == searchVal) {
    results.push(jsonObj.list[i]);
  }
}
alert(results[0]["id"]);

JS operations on JSON summary

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式。同时,JSON是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON数据不须要任何特殊的 API 或工具包。
本文主要是对JS操作JSON的要领做下总结。
在JSON中,有两种结构:对象和数组。

  1. 一个对象以{(左括号)开始,}(右括号)结束。每个“名称”后跟一个:(冒号);“‘名称/值’ 对”之间运用 ,(逗号)分隔。 名称用引号括起来;值如果是字符串则必须用括号,数值型则不须要。例如:
    var o = {
      "xlid": "cxh",
      "xldigitid": 123456,
      "topscore": 2000,
      "topplaytime": "2009-08-20"
    }
    
  2. 数组是值(value)的有序集合。一个数组以[(左中括号)开始,](右中括号)结束。值之间运用 ,(逗号)分隔。例如:
    var jsonranklist = [{
      "xlid": "cxh",
      "xldigitid": 123456,
      "topscore": 2000,
      "topplaytime": "2009-08-20"
    }, {
      "xlid": "zd",
      "xldigitid": 123456,
      "topscore": 1500,
      "topplaytime": "2009-11-20"
    }];
    

为了方便地处理JSON数据,JSON提供了json.js包,下载地址:http://www.json.org/json.js
在数据传输流程中,json是以文本,即字符串的形式传递的,而JS操作的是JSON对象,所以,JSON对象和JSON字符串之间的相互转换是关键。例如:

  • JSON字符串:
    var str1 = '{ "name": "cxh", "sex": "man" }';
    
  • JSON对象:
    var str2 = { "name": "cxh", "sex": "man" };
    
  1. JSON字符串转换为JSON对象,要运用上面的str1,必须运用下面的要领先转化为JSON对象:
    var obj = eval('(' + str + ')');//由JSON字符串转换为JSON对象
    

    或者

    var obj = str.parseJSON(); //由JSON字符串转换为JSON对象
    

    或者

    var obj = JSON.parse(str); //由JSON字符串转换为JSON对象
    

    然后,就可以这样读取:

    Alert(obj.name);
    Alert(obj.sex);
    

    特别留心:如果obj本来就是一个JSON对象,那么运用 eval()函数转换后(哪怕是多次转换)还是JSON对象,但是运用 parseJSON()函数处理后会有疑问(抛出语法异常)。

  2. 可以运用 toJSONString()或者全局要领 JSON.stringify()将JSON对象转化为JSON字符串。
    例如:

    var last=obj.toJSONString(); //将JSON对象转化为JSON字符
    

    或者

    var last=JSON.stringify(obj); //将JSON对象转化为JSON字符
    
    alert(last);
    

    留心:上面的多个要领中,除了eval()函数是js自带的之外,其他的多个要领都来自json.js包。新版本的 JSON 修改了 API,将 JSON.stringify()JSON.parse() 两个要领都注入到了 Javascript 的内建对象里面,前者变成了 Object.toJSONString(),而后者变成了 String.parseJSON()。如果提示找不到toJSONString()parseJSON()要领,则说明您的json包版本太低。