有没有一种方法可以找到键的值,它可以出现在任何对象下的任何级别,并使用Ramda更新它?
例如,
JSON-1
{
"query": {
"boundary": {
"type": "polygon",
"coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
}
}JSON-2
{
"query": {
"nearby": {
"radius": "30mi",
"coordinates": "[-121.40019800,38.55378300]"
}
}
}在这两个JSON中,我想做一些类似的事情:
query.nearby.coordinates = JSON.parse(query.nearby.coordinates)
和
query.boundary.coordinates = JSON.parse(query.boundary.coordinates)
只有一种功能。
发布于 2018-08-02 19:21:00
一种方法是遍历对象树,并尝试将找到的任何字符串解析为JSON。
const parseNestedJSON = R.cond([
[R.is(String), R.tryCatch(JSON.parse, R.nthArg(1))],
[R.is(Object), obj => R.map(parseNestedJSON, obj)],
[R.T, R.identity],
])请注意,这可能会执行一些不需要的转换,例如将{foo: '1'}转换为{foo: 1} (string to number)。
只针对名为coordinates的嵌套键可能更安全
const parseNestedJSON = R.cond([
[R.has('coordinates'), R.over(R.lensProp('coordinates'), JSON.parse)],
[R.is(Object), obj => R.map(parseNestedJSON, obj)],
[R.T, R.identity],
])编辑:如果coordinates可能不是json,您也可以在这里使用tryCatch。
[R.has('coordinates'), R.over(R.lensProp('coordinates'), R.tryCatch(JSON.parse, R.nthArg(1)))]用法:
parseNestedJSON({"nearby": {"coordinates": "[-121.40019800,38.55378300]"}})
=> { nearby: { coordinates: [ -121.400198, 38.553783 ] } }发布于 2018-08-02 21:40:54
另一种选择是定义一个可以负责更新值的镜头。
第一种方法假设可以找到坐标的已知路径的数量是有限的。
// Creates a lens that accepts a list of paths and chooses the first
// matching path that exists in the target object
const somePathLens = paths => toFunctor => target => {
const path = R.find(
p => R.pathSatisfies(x => x != null, p, target),
paths
)
return R.map(
value => R.assocPath(path, value, target),
toFunctor(R.path(path, target))
)
}
// R.over can then be used with JSON.parse to parse the first
// matching path that is found.
const parseCoords = R.over(
somePathLens([
['query', 'boundary', 'coordinates'],
['query', 'nearby', 'coordinates']
]),
JSON.parse
)
console.log(parseCoords({
"query": {
"boundary": {
"type": "polygon",
"coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
}
}
}))
console.log(parseCoords({
"query": {
"nearby": {
"radius": "30mi",
"coordinates": "[-121.40019800,38.55378300]"
}
}
}))<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
如果实际路径未知,并且您只需要通过给定的键找到第一个值,则可以使用第二种方法。
// Recursively search for the given key in an object, returning the
// first matching path if found.
const findKeyInPath = (keyToFind, obj) => {
const findKeyInPath_ = o =>
R.has(keyToFind, o)
// if found, return this key as the path
? [keyToFind]
// otherwise find all keys with objects and recursively
// call this function.
: R.reduceRight((k, acc) => {
// find either the subpath of this key, or the subpath
// found in the remaining keys
const subPath = R.when(R.isEmpty, _ => acc, findKeyInPath_(o[k]))
// if the subpath contains a key, prepend it with the
// current key, otherwise return the empty list
return R.unless(R.isEmpty, R.prepend(k), subPath)
}, [], R.filter(k => R.propIs(Object, k, o), R.keys(o)))
return findKeyInPath_(obj)
}
// Create a lens that recursively searches for the first matching
// key within a target object.
const someKeyLens = key => toFunctor => target => {
// find the path using our new `findKeyInPath` function
const path = findKeyInPath(key, target)
return R.map(
value => R.assocPath(path, value, target),
toFunctor(R.path(path, target))
)
}
const parseCoords = R.over(
someKeyLens('coordinates'),
JSON.parse
)
console.log(parseCoords({
"query": {
"boundary": {
"type": "polygon",
"coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
}
}
}))
console.log(parseCoords({
"query": {
"nearby": {
"radius": "30mi",
"coordinates": "[-121.40019800,38.55378300]"
}
}
}))<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
值得一提的是,只有在保证在目标对象中找到路径的情况下,这些才是有效的镜头,否则行为是未定义的。
https://stackoverflow.com/questions/51651438
复制相似问题