Я пытаюсь выделить часть JSON в Javascript, найденную в следующей константе namespace
, используя второй параметр JS JSON.strigify() replacer
. Поэтому, когда ключ равен пространству имен, он увеличивает индекс в пространстве имен для продвижения. Наконец, я окружаю значение клавишами 0 и Z.
const dataTree = {
"styles": {
"elements": {
"heading": {
"typography": {
"fontFamily": "Volkorn",
"fontSize": "16px"
},
},
},
"typography": {
"fontFamily": "Vollkorn",
"fontSize": "16px",
"lineHeight": "1.7"
}
}
}
const namespace = "styles.typography.fontSize".split('.')
let i = 0
const replacer = (k, v) => {
if (namespace[i] === k){
i++
if (i === namespace.length-1){
if (Object.keys(v).includes(namespace.at(-1))){
v[0] = 'before'
v["Z"] = 'after'
return v
}
}
}
if (v["Z"]) {
delete v["Z"]
delete v[0]
}
return v
}
const strV = JSON.stringify(dataTree, replacer, 2)
Проблема не в том, чтобы идти по правильному пути. В приведенном выше примере он идет к styles.elements.heading.typography.fontSize
вместо styles.typography.fontSize
.
Есть идеи ?
Также покажите ожидаемый результат.
dataTree
— это объект JS, да. strV
— это версия строки JSON, включающая в себя некоторые специальные ключи для окружения значений, которые я хотел бы выделить.
Я ожидал, что метод stringify будет иметь более точный контроль над функцией замены, которая предоставляет только ключ и значение, но не путь или пространство имен, чтобы точно идентифицировать обрабатываемую часть объекта. Если вы запустите его, вы получите результат, аналогичный тому, что я ожидаю. Проблема в том, что он изменяет styles.elements.heading.typography.fontSize
вместо styles.typography.fontSize
. Наконец, я собираюсь внести эти изменения, чтобы сделать это до преобразования в JSON, так как нет возможности проверить путь, по которому находится функция-заменитель.
Если вы используете заменитель, он вызывается рекурсивно для измененного объекта, который возвращает заменитель.
Если заменитель вставляет в дерево новые свойства, это затрудняет отслеживание позиции в дереве, над которой работает текущий вызов заменителя.
Вместо этого вы можете сделать это с объектами:
const dataTree = {"styles":{"elements":{"heading":{"typography":{"fontFamily":"Volkorn","fontSize":"16px"}}},"typography":{"fontFamily":"Vollkorn","fontSize":"16px","lineHeight":"1.7"}}};
const namespace = 'styles.typography.fontSize'.split('.');
const replaceAtLocation = (tree, [p,...rest], replacer) => rest.length ?
Object.fromEntries(Object.entries(tree).map(([k,v])=>k===p ?
[k,replaceAtLocation(v, rest, replacer)] : [k,v])) : replacer(tree);
const result = replaceAtLocation(dataTree,namespace,tree=>Object.fromEntries(
Object.entries(tree).flatMap(([k,v])=>k===[...namespace].pop()?
[['A','before'],[k,v],['Z','after']]:[[k,v]])));
console.info(JSON.stringify(result, null, 2));
Обратите внимание, что я заменил «0» на «A», так как «0» всегда будет располагаться первым свойством в объекте, а не непосредственно перед желаемым свойством.
Что ж, ваш ответ полностью рабочий. Тем не менее, это очень компактно, мне потребуется некоторое время, чтобы понять все это. Спасибо!
Вы сказали, что хотите сделать это в «JSON», но то, что вы показали, является объектом JavaScript. JSON — это текстовая запись для обмена данными. (Подробнее здесь.) Если вы имеете дело с исходным кодом JavaScript, а не со строкой, вы не имеете дело с JSON. Вы пытаетесь сделать это в объекте JavaScript, который затем сериализуете в JSON? Потому что это сложно (возможно, невозможно) сделать с помощью функции-заменителя, но довольно легко сделать это до преобразования в JSON.