Javascript: 将嵌套对象转换为以值作为路径的对象
Javascript: Convert nested object to object with values as path
这道题不是Fastest way to flatten / un-flatten nested JSON objects的重复题,因为附加值变成键,顺序变化很大,我的对象不是简单的"in a line".
我已经更新了问题描述以使其更清楚。
我有一个嵌套对象,代表控制器映射的多语言路径:
{
"welcome": {
"news": {
"de": "nachrichten",
"en": "news"
},
"de": "willkommen",
"en": "welcome"
},
"applications": {
"application1": {
"de": "anwendung1",
"en": "application1"
},
"application2": {
"features": {
"de": "funktionen",
"en": "features"
},
"de": "anwendung2",
"en": "application2"
},
"de": "anwendungen",
"en": "applications"
}
}
应将其转换为接受路径作为键的易于使用的对象:
{
"/de/willkommen/": "welcome",
"/en/welcome/": "welcome",
"/de/willkommen/nachrichten/": "news",
"/en/welcome/news/": "news",
"/de/anwendungen/": "applications",
"/en/applications/": "applications",
"/de/anwendungen/anwendung1/": "application1",
"/en/applications/application1/": "application1",
"/de/anwendungen/anwendung2/": "application2",
"/en/applications/application2/": "application2",
"/de/anwendungen/anwendung2/funktionen/": "features",
"/en/applications/application2/features/": "features",
}
现在,初始语言特定值("de":"willkommen" 等)构建路径并且是键,初始键是值。但是请看一下,它有点复杂。
我已经构建了一个函数,但它们仅适用于第一级,如“/de/anwendungen/”,不适用于“/de/anwendungen/anwendung1/”及更低级别。
convertToPath(OldObject, NewObject = {})
{
for(let SecondObject in OldObject)
{
for(let Key in OldObject[SecondObject])
{
NewObject["/" + Key + "/" + OldObject[SecondObject][Key] + "/"] = SecondObject;
}
}
return NewObject;
}
嗯,你可以通过使用递归遍历来创建你的对象
数据树,像这样:
var data = {
"welcome": {
"news": {
"de": "nachrichten",
"en": "news"
},
"de": "willkommen",
"en": "welcome"
},
"applications": {
"application1": {
"de": "anwendung1",
"en": "application1"
},
"application2": {
"features": {
"de": "funktionen",
"en": "features"
},
"de": "anwendung2",
"en": "application2"
},
"de": "anwendungen",
"en": "applications"
}
};
var langs = ['en', 'de'];
var path_to_controller = function(data, paths, pathsofar){
paths = paths || {};
pathsofar = pathsofar || {};
Object.keys(data).forEach(function(key){
var newpathsofar;
if(langs.some(function(lang){ return key === lang; })){
return;
}
newpathsofar = langs.reduce(function(p, lang){
p[lang] = pathsofar[lang] || '/' + lang + '/';
p[lang] += data[key][lang] + '/';
paths[p[lang]] = key;
return p;
}, {});
path_to_controller(data[key], paths, newpathsofar)
});
return paths;
};
var paths = path_to_controller(data);
var pre = document.createElement('pre');
pre.innerHTML = JSON.stringify(paths, null, 4);
document.body.appendChild(pre);
您的嵌套对象似乎很难使用,所以我可以理解您想转换成另一种格式。也许您可以安排以更易于使用的格式提供路径数据。
编辑: 推广到任意数量的语言。
和答案 1 的一个小替代方案。虽然我完全同意 'King Mob' 这个结构是有缺陷的并且容易出错。如果您需要名为 "en" 的资源(例如在荷兰语中的意思是 'AND'),请前往 Bantha poodoo's creek。
// target hold the desired output
var target = {};
// languages to distinguish between "a translated resource" and "a resource".
var ls = [ "en", "de" ];
var path = [];
var recurse = function(a,n) {
// can be made pretty by using ls.
if (a.hasOwnProperty("de") || a.hasOwnProperty("en"))
{
path.push(a);
}
var keys = Object.keys(a);
keys.forEach(
function(o) {
if (ls.indexOf(o) > -1) {
var spath = path.reduce( function(pV, cV) { return pV + "/" + cV[o]; }, o);
target[spath] = n;
} else {
recurse(a[o], o);
}
}
);
// can be made pretty by using ls.
if (a.hasOwnProperty("de") || a.hasOwnProperty("en"))
{
path.pop();
}
};
// your example data.
var source = {..use your example data.};
// start the recursion
recurse( source );
// output the result
JSON.stringify(target);
这道题不是Fastest way to flatten / un-flatten nested JSON objects的重复题,因为附加值变成键,顺序变化很大,我的对象不是简单的"in a line".
我已经更新了问题描述以使其更清楚。
我有一个嵌套对象,代表控制器映射的多语言路径:
{
"welcome": {
"news": {
"de": "nachrichten",
"en": "news"
},
"de": "willkommen",
"en": "welcome"
},
"applications": {
"application1": {
"de": "anwendung1",
"en": "application1"
},
"application2": {
"features": {
"de": "funktionen",
"en": "features"
},
"de": "anwendung2",
"en": "application2"
},
"de": "anwendungen",
"en": "applications"
}
}
应将其转换为接受路径作为键的易于使用的对象:
{
"/de/willkommen/": "welcome",
"/en/welcome/": "welcome",
"/de/willkommen/nachrichten/": "news",
"/en/welcome/news/": "news",
"/de/anwendungen/": "applications",
"/en/applications/": "applications",
"/de/anwendungen/anwendung1/": "application1",
"/en/applications/application1/": "application1",
"/de/anwendungen/anwendung2/": "application2",
"/en/applications/application2/": "application2",
"/de/anwendungen/anwendung2/funktionen/": "features",
"/en/applications/application2/features/": "features",
}
现在,初始语言特定值("de":"willkommen" 等)构建路径并且是键,初始键是值。但是请看一下,它有点复杂。
我已经构建了一个函数,但它们仅适用于第一级,如“/de/anwendungen/”,不适用于“/de/anwendungen/anwendung1/”及更低级别。
convertToPath(OldObject, NewObject = {})
{
for(let SecondObject in OldObject)
{
for(let Key in OldObject[SecondObject])
{
NewObject["/" + Key + "/" + OldObject[SecondObject][Key] + "/"] = SecondObject;
}
}
return NewObject;
}
嗯,你可以通过使用递归遍历来创建你的对象 数据树,像这样:
var data = {
"welcome": {
"news": {
"de": "nachrichten",
"en": "news"
},
"de": "willkommen",
"en": "welcome"
},
"applications": {
"application1": {
"de": "anwendung1",
"en": "application1"
},
"application2": {
"features": {
"de": "funktionen",
"en": "features"
},
"de": "anwendung2",
"en": "application2"
},
"de": "anwendungen",
"en": "applications"
}
};
var langs = ['en', 'de'];
var path_to_controller = function(data, paths, pathsofar){
paths = paths || {};
pathsofar = pathsofar || {};
Object.keys(data).forEach(function(key){
var newpathsofar;
if(langs.some(function(lang){ return key === lang; })){
return;
}
newpathsofar = langs.reduce(function(p, lang){
p[lang] = pathsofar[lang] || '/' + lang + '/';
p[lang] += data[key][lang] + '/';
paths[p[lang]] = key;
return p;
}, {});
path_to_controller(data[key], paths, newpathsofar)
});
return paths;
};
var paths = path_to_controller(data);
var pre = document.createElement('pre');
pre.innerHTML = JSON.stringify(paths, null, 4);
document.body.appendChild(pre);
您的嵌套对象似乎很难使用,所以我可以理解您想转换成另一种格式。也许您可以安排以更易于使用的格式提供路径数据。
编辑: 推广到任意数量的语言。
和答案 1 的一个小替代方案。虽然我完全同意 'King Mob' 这个结构是有缺陷的并且容易出错。如果您需要名为 "en" 的资源(例如在荷兰语中的意思是 'AND'),请前往 Bantha poodoo's creek。
// target hold the desired output
var target = {};
// languages to distinguish between "a translated resource" and "a resource".
var ls = [ "en", "de" ];
var path = [];
var recurse = function(a,n) {
// can be made pretty by using ls.
if (a.hasOwnProperty("de") || a.hasOwnProperty("en"))
{
path.push(a);
}
var keys = Object.keys(a);
keys.forEach(
function(o) {
if (ls.indexOf(o) > -1) {
var spath = path.reduce( function(pV, cV) { return pV + "/" + cV[o]; }, o);
target[spath] = n;
} else {
recurse(a[o], o);
}
}
);
// can be made pretty by using ls.
if (a.hasOwnProperty("de") || a.hasOwnProperty("en"))
{
path.pop();
}
};
// your example data.
var source = {..use your example data.};
// start the recursion
recurse( source );
// output the result
JSON.stringify(target);