给定一个JSON对象:{"a": {"b": [{"c": "123"}]}}
和一个包含JSON ["a", "b", "0", "c"]
路径的数组,如何修改“123”的最终值?
json["a"]["b"][0]["c"] = "abc"
是我想要完成的,但带路径的数组是完全可变的。路径数组中的每个项目将始终位于JSON对象中。
我正在使用CoffeeScript,但psuedo代码同样有用
答案 0 :(得分:3)
您需要使用除最后一个路径项之外的所有项目钻取对象。然后使用最后一个路径项来设置值。在JavaScript中,您可以创建以下函数来设置值...
function setValue(obj, path, value) {
var i;
for (i = 0; i < path.length - 1; i++) {
obj = obj[path[i]];
}
obj[path[i]] = value;
}
然后您可以使用...
调用该函数var obj = {"a": {"b": [{"c": "123"}]}};
var path = ["a", "b", "0", "c"];
var value = "abc";
setValue(obj, path, value);
答案 1 :(得分:0)
我改进了Bobby的答案并用CoffeeScript编写了它。效果很好。
setValue = (obj, path, value) ->
path.forEach (val, index, path) ->
if path.length - 1 != index
obj = obj[val]
else
obj[val] = value
json = "a": "b": ["c": "123"]
path = ["a", "b", "0", "c"]
value = "abc"
setValue json, path, value
console.log json["a"]["b"][0]["c"] # => "abc"
我希望它对你有所帮助。
答案 2 :(得分:0)
一个更通用,更复杂的答案怎么样?这就是我在excel-as-json中使用的内容。请参阅下面的链接或测试用例,了解json点字符串键路径语法的示例。
BOOLTEXT = ['true', 'false']
BOOLVALS = {'true': true, 'false': false}
isArray = (obj) ->
Object.prototype.toString.call(obj) is '[object Array]'
# Extract key name and array index from names[1] or names[]
# return [keyIsList, keyName, index]
# for names[1] return [true, keyName, index]
# for names[] return [true, keyName, undefined]
# for names return [false, keyName, undefined]
parseKeyName = (key) ->
index = key.match(/\[(\d+)\]$/)
switch
when index then [true, key.split('[')[0], Number(index[1])]
when key[-2..] is '[]' then [true, key[...-2], undefined]
else [false, key, undefined]
# Convert a list of values to a list of more native forms
convertValueList = (list) ->
(convertValue(item) for item in list)
# Convert values to native types
# Assume: all values from the excel module are text
convertValue = (value) ->
if isFinite(value)
Number(value)
else
testVal = value.toLowerCase()
if testVal in BOOLTEXT
BOOLVALS[testVal]
else
value
# Assign a value to a dotted property key - set values on sub-objects
assign = (obj, key, value) ->
# On first call, a key is a string. Recursed calls, a key is an array
key = key.split '.' unless typeof key is 'object'
# Array element accessors look like phones[0].type or aliases[]
[keyIsList, keyName, index] = parseKeyName key.shift()
if key.length
if keyIsList
# if our object is already an array, ensure an object exists for this index
if isArray obj[keyName]
unless obj[keyName][index]
obj[keyName].push({}) for i in [obj[keyName].length..index]
# else set this value to an array large enough to contain this index
else
obj[keyName] = ({} for i in [0..index])
assign obj[keyName][index], key, value
else
obj[keyName] ?= {}
assign obj[keyName], key, value
else
if keyIsList and index?
console.error "WARNING: Unexpected key path terminal containing an indexed list for <#{keyName}>"
console.error "WARNING: Indexed arrays indicate a list of objects and should not be the last element in a key path"
console.error "WARNING: The last element of a key path should be a key name or flat array. E.g. alias, aliases[]"
if (keyIsList and not index?)
obj[keyName] = convertValueList(value.split ';')
else
obj[keyName] = convertValue value
# Test cases
obj = {}
assign obj, 'firstName', 'Jihad'
assign obj, 'lastName', 'Saladin'
assign obj, 'address.street', '12 Beaver Court'
assign obj, 'address.city', 'Snowmass'
assign obj, 'address.state', 'CO'
assign obj, 'address.zip', '81615'
assign obj, 'isEmployee', 'true'
assign obj, 'phones[0].type', 'home'
assign obj, 'phones[0].number', '123.456.7890'
assign obj, 'phones[1].type', 'work'
assign obj, 'phones[1].number', '098.765.4321'
assign obj, 'aliases[]', 'stormagedden;bob'
console.log JSON.stringify obj, null, 2
产生
{
"firstName": "Jihad",
"lastName": "Saladin",
"address": {
"street": "12 Beaver Court",
"city": "Snowmass",
"state": "CO",
"zip": 81615
},
"isEmployee": true,
"phones": [
{
"type": "home",
"number": "123.456.7890"
},
{
"type": "work",
"number": "098.765.4321"
}
],
"aliases": [
"stormagedden",
"bob"
]
}