如何修改 JSON string 中的值,只有改动部分产生 diff - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
molvqingtai

如何修改 JSON string 中的值,只有改动部分产生 diff

  •  1
     
  •   molvqingtai 2023 年 2 月 11 日 3558 次点击
    这是一个创建于 1162 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如我有这样一个 JSON

    { "pages": ["pages/index/index"], "subpackages": [ { "name": "A", "pages": ["innerModule/pages/index/index"] }, { "name": "B", "pages": ["innerModule/pages/index/index"] } ] } 

    需要实现一个函数找到 subpackages 下面 name === "xxx" 的 object ,然后替换当前的 object ,没有找到就 push 到 subpackages

    使用 JSON.parse 很简单,但是会丢失格式信息,导致在 CI 中产生额外的 diff ,有什么很好处理这种场景的 AST 库推荐也行

    第 1 条附言    2023 年 2 月 13 日
    感谢大家回复,已使用 #9 的 chatgpt 答案,改吧改吧解决了
    23 条回复    2023-02-13 10:35:16 +08:00
    justdoit123
        1
    justdoit123  
       2023 年 2 月 11 日   1
    预期的情况有两种:
    1. 当你需要改动的时候,一定会产生 diff
    2. 如果没有改动,则不能产生 diff

    我的方案:直接用 JSON.parse/stringify 。你说的那种情况应该只有在原本的 JSON 字符串不是用 JSON.stringify 的情况下会产生。你可以先统一把已存在的文件全部重新格式化一遍,后续就不会产生 diff 。
    bagel
        2
    bagel  
       2023 年 2 月 11 日
    key 排个序不就好了
    molvqingtai
        3
    molvqingtai  
    OP
       2023 年 2 月 11 日
    @mistkafka 我只想有改动的字段产生 diff ,因为一些流程的原因,没办法吧整个文件全部 parse 再 format 一遍
    v2er4241
        6
    v2er4241  
       2023 年 2 月 11 日   1
    他的锚点不好用,重发[笑哭]

    console.log(JSON.stringify({ a: 2 }, null, " "));
    /*
    {
    "a": 2
    }
    */

    console.log(JSON.stringify({ uno: 1, dos: 2 }, null, "\t"));
    /*
    {
    "uno": 1,
    "dos": 2
    }
    */
    molvqingtai
        7
    molvqingtai  
    OP
       2023 年 2 月 11 日
    @klo424 先 parse => stringify , 现在的问题是在 pasre 处就丢失格式信息了
    tool2d
        8
    tool2d  
       2023 年 2 月 11 日   1
    这种情况适合用 line parse 功能。

    先把{"name": "A" .. }这个对象片段包含的连续行提取出来,别的行号内容都保留下来。

    只序列化和反序列化这一小部分的文件内容,然后再拼装输出一个完整文件。相当于自己手动局部对象 JSON.parse/stringify ,而不是全局。
    zictos
        9
    zictos  
       2023 年 2 月 11 日   1
    chatgpt 的答案能参考吗?
    推荐使用 jsonc-parser 库,它可以解析带注释的 JSON ,然后根据需要更新 JSON 对象并生成新的 JSON string 。下面是一个示例代码,可以实现题目要求的功能:

    const { parseTree, findNodeAtLocation, applyEdits, modify } = require("jsonc-parser");

    function updatePackage(jsonStr, packageName, packageData) {
    const ast = parseTree(jsonStr);
    const subpackagesNode = findNodeAtLocation(ast, ["subpackages"]);
    const packageIndex = subpackagesNode.children.findIndex(
    (child) => findNodeAtLocation(child, ["value", "name"]).value === packageName
    );
    if (packageIndex !== -1) {
    const packageNode = subpackagesNode.children[packageIndex];
    const edits = modify(jsonStr, packageNode.offset, packageNode.length, JSON.stringify(packageData));
    return applyEdits(jsonStr, edits);
    } else {
    const edits = modify(jsonStr, subpackagesNode.offset + subpackagesNode.length - 1, 0, `,${JSON.stringify(packageData)}`);
    return applyEdits(jsonStr, edits);
    }
    }

    const jsOnStr= `{
    "pages": ["pages/index/index"],
    "subpackages": [
    {
    "name": "A",
    "pages": ["innerModule/pages/index/index"]
    },
    {
    "name": "B",
    "pages": ["innerModule/pages/index/index"]
    }
    ]
    }`;

    console.log(updatePackage(jsonStr, "C", { name: "C", pages: ["pages/C/index"] }));

    在上面的代码中,updatePackage 函数接收一个 JSON string 、需要更新的包名和包数据。它首先使用 jsonc-parser 解析 JSON string ,然后在 AST 中查找 subpackages 节点。然后它在 subpackages 的子节点中查找与给定包名匹配的节点,如果找到了就将它替换为给定的包数据,否则就将包数据添加到 subpackages 的末尾。最后,它将生成的新 JSON string 返回。

    由于使用 jsonc-parser 解析 JSON string 时可以保留格式信息,因此在 CI 中就不会产生额外的 diff 了。
    v2er4241
        10
    v2er4241  
       2023 年 2 月 11 日
    @molvqingtai #7 你好像没看懂我什么意思?你看#6 的代码,stringify 之前是没有格式的,加了后面的参数就有了格式。你手写的格式跟他一样就行了。
    molvqingtai
        11
    molvqingtai  
    OP
       2023 年 2 月 11 日
    @zictos 感谢,我试试这个代码,今天也用了 V 站上面免登录的 chatgpt ,问了半天也没问出你这样的结果,难道需要走什么流程
    v2er4241
        12
    v2er4241  
       2023 年 2 月 11 日   1
    你试一下好吧,根本不需要什么库[笑哭]

    console.log(JSON.stringify({uno:1,dos:[2,3],dns:{wf:{bbq:'5'},aec:4}}, null, "\t"))

    {
    "uno": 1,
    "dos": [
    2,
    3
    ],
    "dns": {
    "wf": {
    "bbq": "5"
    },
    "aec": 4
    }
    }
    v2er4241
        13
    v2er4241  
       2023 年 2 月 11 日
    v2 把格式过滤掉了,发不出格式。
    molvqingtai
        14
    molvqingtai  
    OP
       2023 年 2 月 11 日
    @klo424 感谢你的热情,但是我不能把已有的 JSON 都格式化一遍,而且输入的 object 格式也不一定和原 JSON 一致,总结就是想达到就像手动编辑一样的 diff 效果
    molvqingtai
        15
    molvqingtai  
    OP
       2023 年 2 月 11 日
    @klo424 v2 支持 markdown ....
    v2er4241
        16
    v2er4241  
       2023 年 2 月 11 日 via iPhone
    评论不支持
    v2er4241
        17
    v2er4241  
       2023 年 2 月 11 日 via iPhone
    那我觉得你只能用正则写了,其他的插件也会有自己的格式,都有相同的问题。
    zictos
        18
    zictos  
       2023 年 2 月 11 日
    @molvqingtai #11 别人做的是第三方的,调用 api 的,api 的跟目前官方网页版不一样,一点都不智能一点都不好用。反正我试了基本很多答案都没法用,而官方网页版每次的回答都很智能很有针对性
    lisongeee
        19
    lisongeee  
       2023 年 2 月 11 日   1
    <script src="https://gist.github.com/lisonge/51f6a7e6118a3412ecc226d20ea4fa0d.js"></script>

    实现了找到替换的功能,使用的库是 acorn(解析 ast 获取位置) 和 magic-string(更新字符)
    caotian
        21
    caotian  
       2023 年 2 月 12 日   1
    试试 json patch
    libook
        22
    libook  
       2023 年 2 月 13 日   1
    取决于你原 JSON 文本是如何产生的。

    如果你可以控制原 JSON 文本的生成过程,你可以给字段名进行递归排序,然后利用 stringify 的第 2 、3 位参数(去看一下 stringify 的文档)来格式化生成。后续修改也用相同方式处理,就可以得到除了修改部分一致的 JSON 文本。这个概念通常被称为 json stable stringify ,有一些现成的库可以用。

    如果你不能控制原 JSON 文本的生成过程,我没有想到什么好方法,可能只能用正则去匹配和修改文本中要改的那部分了。
    molvqingtai
        23
    molvqingtai  
    OP
       2023 年 2 月 13 日
    感谢大家回复,已使用 #9 的 chatgpt 答案,改吧改吧解决了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2440 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 67ms UTC 01:04 PVG 09:04 LAX 18:04 JFK 21:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86