【问题标题】:Json: edit deeply nested valueJson:编辑深度嵌套的值
【发布时间】:2017-07-02 19:34:31
【问题描述】:

我有一个这样的 json 数组:

var tree = [
      {
        text: "Parent 1",
        id: 1,
        nodes: [
          {
            text: "Child 1",
            id: 2,
            nodes: [
              {
                text: "Grandchild 1"
                id: 3,
              },
              {
                text: "Grandchild 2"
                id: 4,
                nodes: [
                  {
                    text: "Grandchild 3"
                    id: 10,
                  },
                  {
                    text: "Grandchild 4"
                    id: 11,
                    nodes: [
                      {
                        text: "Grandchild 5"
                        id: 12,
                      },
                      {
                        text: "Grandchild 6"
                        id: 13,
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            text: "Child 2"
            id: 5,
          }
        ]
      },
      {
        text: "Parent 2"
        id: 6,
      },
      {
        text: "Parent 3"
        id: 7,
      },
      {
        text: "Parent 4"
        id: 8,
      },
      {
        text: "Parent 5"
        id: 9,
      }
    ];

我正在尝试创建一个函数,它将树、id 和 newText 参数作为参数,它将找到具有给定 id 的节点,用 newText 替换文本,并返回修改后的 json。

例如:

editTree(tree, 11, "Granchild 13435")

有没有办法做到这一点? 我不知道如何解决这个问题,因为我需要密钥的路径才能编辑树。

【问题讨论】:

标签: javascript json


【解决方案1】:

您可以为此使用递归函数。

var tree = [{"text":"Parent 1","id":1,"nodes":[{"text":"Child 1","id":2,"nodes":[{"text":"Grandchild 1","id":3},{"text":"Grandchild 2","id":4,"nodes":[{"text":"Grandchild 3","id":10},{"text":"Grandchild 4","id":11,"nodes":[{"text":"Grandchild 5","id":12},{"text":"Grandchild 6","id":13}]}]}]},{"text":"Child 2","id":5}]},{"text":"Parent 2","id":6},{"text":"Parent 3","id":7},{"text":"Parent 4","id":8},{"text":"Parent 5","id":9}]

function editTree(tree, id, val) {
  for (var i in tree) {
    if (i == 'id') {
      if (tree[i] == id) {
        tree.text = val
        return 1;
      }
    }
    if (typeof tree[i] == 'object') editTree(tree[i], id, val)
  }
  return tree;
}


console.log(editTree(tree, 11, "Granchild 13435"))

【讨论】:

    【解决方案2】:

    您可以使用迭代和递归方法来搜索节点。如果找到则停止迭代并返回。

    此提案使用Array#some,允许退出迭代。

    如果存在来自实际nodenode 并且该节点是一个数组,则该节点将被迭代。

    function editTree(tree, id, text) {
        tree.some(function iter(o) {
            if (o.id === id) {
                o.text = text;
                return true;
            }
            return Array.isArray(o.nodes) && o.nodes.some(iter);
        });
    }
    
    var tree = [{ text: "Parent 1", id: 1, nodes: [{ text: "Child 1", id: 2, nodes: [{ text: "Grandchild 1", id: 3, }, { text: "Grandchild 2", id: 4, nodes: [{ text: "Grandchild 3", id: 10, }, { text: "Grandchild 4", id: 11, nodes: [{ text: "Grandchild 5", id: 12, }, { text: "Grandchild 6", id: 13, }] }] }] }, { text: "Child 2", id: 5, }] }, { text: "Parent 2", id: 6, }, { text: "Parent 3", id: 7, }, { text: "Parent 4", id: 8, }, { text: "Parent 5", id: 9, }];
    
    editTree(tree, 11, "Granchild 13435");    
    console.log(tree);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      【解决方案3】:

      这是一个简单的函数来查找匹配属性和值的节点:

      function findNode(nodes, prop, value) {
        if(!value || !(nodes instanceof Array)) return;
        for(var i=0; i<nodes.length; i++) {
            if(node = (value == nodes[i][prop]) ? nodes[i] : findNode(nodes[i]['nodes'], value)) {
              return node;
            }
        }
      }
      

      然后简单地调用:

      // Find node with id = 10
      var node = findNode(tree, 'id', 10);
      if(node) {
        // Yeah! we found it, now change its text
        node['text'] = 'Changed!';
      }
      
      // Ensure tree has been updated
      console.log(tree);
      

      示例 sn-p(检查 id = 10 的节点的文本是否已更改):

      var tree=[{text:"Parent 1",id:1,nodes:[{text:"Child 1",id:2,nodes:[{text:"Grandchild 1",id:3},{text:"Grandchild 2",id:4,nodes:[{text:"Grandchild 3",id:10},{text:"Grandchild 4",id:11,nodes:[{text:"Grandchild 5",id:12},{text:"Grandchild 6",id:13}]}]}]},{text:"Child 2",id:5}]},{text:"Parent 2",id:6},{text:"Parent 3",id:7},{text:"Parent 4",id:8},{text:"Parent 5",id:9}];
      
      
      function findNode(nodes, prop, value) {
        if(!value || !(nodes instanceof Array)) return;
        for(var i=0; i<nodes.length; i++) {
            var node = (value == nodes[i][prop]) ? nodes[i] : findNode(nodes[i]['nodes'], prop, value);
            if(node ) {
              return node;
            }
        }
      }
      
      var node = findNode(tree, 'id', 10);
      if(node) {
        node['text'] = 'Changed!';
      }
      
      console.log(tree)

      【讨论】:

        【解决方案4】:

        我创建了使用递归遍历的库,其中一种方法正是您所需要的。

        https://github.com/dominik791/obj-traverse

        使用findFirst() 方法。第一个参数是根对象,不是数组,所以你应该先创建它:

        var tree = {
          text: 'rootObj',
          nodes: [
          {
            text: 'Parent 1',
            id: 1,
            nodes: [
              {
                'text': 'Child 1',
                id: 2,
                nodes: [ ... ]
              },
              {
                'name': 'Child 2',
                id: 3,
                nodes: [ ... ]
              }
            ]
          },
          {
            text: 'Parent2',
            id: 6
          }
        };
        

        然后:

        var objToEdit = findFirst(tree, 'nodes', { id: 11 });
        

        现在objToEdit 是对您要编辑的对象的引用。所以你可以:

        objToEdit.text = 'Granchild 13435';
        

        您的tree 已更新。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多