【问题标题】:Javascript/JSON get path to given subnode?Javascript/JSON 获取给定子节点的路径?
【发布时间】:2012-02-06 02:48:24
【问题描述】:

如何获得一个对象的给定子节点的 JSON 路径?

例如:

var data = {
    key1: {
        children: {
            key2:'value',
            key3:'value',
            key4: { ... }
        }, 
    key5: 'value'
}

给出了一个引用 key4 的变量。现在我正在寻找绝对路径:

data.key1.children.key4

有没有办法在 JS 中完成这项工作?

提前谢谢你。

【问题讨论】:

  • 如果您的搜索变量指向一个字符串对象(如示例中),您将无法可靠地搜索该路径,因为(例如)data.key1.children.key3 === data.key4 也将是 true,可能不是你想要达到的目标。
  • 谢谢 Yoshi,我已经更新了代码示例。现在引用指向另一个对象。

标签: javascript json xpath


【解决方案1】:

所以你有一个值为“key3”的变量,你想知道如何根据这个字符串的值动态访问这个属性?

var str = "key3";
data["key1"]["children"][str];

编辑

哇,我不敢相信我第一次尝试就得到了这个。它可能存在一些错误,但它适用于您的测试用例

LIVE DEMO

var x = data.key1.children.key4;

var path = "data";
function search(path, obj, target) {
    for (var k in obj) {
        if (obj.hasOwnProperty(k))
            if (obj[k] === target)
                return path + "['" + k + "']"
            else if (typeof obj[k] === "object") {
                var result = search(path + "['" + k + "']", obj[k], target);
                if (result)
                    return result;
            }
    }
    return false;
}

var path = search(path, data, x);
console.log(path); //data['key1']['children']['key4']

【讨论】:

  • 嗨,亚当,感谢您的回复。我正在寻找完整的路径。 “key1”和“children”是未知的。我有一个对存储在变量中的 data.key1.children.key3 的引用,需要知道如何到达那里。
  • @user1138959 - 我不确定这是否可能。我的意思是,您可以对对象的每个成员进行递归搜索,但是如果您必须使用相同的值,仍然无法知道您的变量指向哪个成员
  • 我已经更新了我的代码示例。我正在寻找一个对象,而不是一个字符串值。我将如何递归地搜索每个成员并获得匹配孩子的路径?
  • @user1138959 - 正如 lwburk 所提到的,只要确保你没有像 children: { ... key6: data.key1 这样的东西 - 好吧,除非你真的喜欢无限循环,否则不要这样做;)
【解决方案2】:

我就是这样做的。

/**
 * Converts a string path to a value that is existing in a json object.
 * 
 * @param {Object} jsonData Json data to use for searching the value.
 * @param {Object} path the path to use to find the value.
 * @returns {valueOfThePath|null}
 */
function jsonPathToValue(jsonData, path) {
    if (!(jsonData instanceof Object) || typeof (path) === "undefined") {
        throw "Not valid argument:jsonData:" + jsonData + ", path:" + path;
    }
    path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    path = path.replace(/^\./, ''); // strip a leading dot
    var pathArray = path.split('.');
    for (var i = 0, n = pathArray.length; i < n; ++i) {
        var key = pathArray[i];
        if (key in jsonData) {
            if (jsonData[key] !== null) {
                jsonData = jsonData[key];
            } else {
                return null;
            }
        } else {
            return key;
        }
    }
    return jsonData;
}  

为了测试,

var obj = {d1:{d2:"a",d3:{d4:"b",d5:{d6:"c"}}}};
jsonPathToValue(obj, "d1.d2"); // a 
jsonPathToValue(obj, "d1.d3"); // {d4: "b", d5: Object}
jsonPathToValue(obj, "d1.d3.d4"); // b
jsonPathToValue(obj, "d1.d3.d5"); // {d6: "c"}
jsonPathToValue(obj, "d1.d3.d5.d6"); // c

希望对某人有所帮助。

【讨论】:

  • 感谢这段代码,正是我想要的,但它有一些小错误:它不会返回undefined,但null 或路径中的密钥,如果该密钥不是成立。只需替换 return nullreturn key 即可!
【解决方案3】:

var data = {
  // Your data is here
  a: {
    b: {
      c: {
        d: "Assalamu alal muslimin"
      }
    }
  },
  // Your function is here
  take: function(path) {
    var temp = this; // take a copy of object
    if(!path) return temp; // if path is undefined or empty return the copy
    path = path.split("/");
    for(var p in path) {
      if(!path[p]) continue; // means "a/" = "a"
      temp = temp[path[p]]; // new data is subdata of data
      if(!temp) return temp; 
    }
    return temp;
  }
};
<input placeholder="Please enter the path"/>
<button onclick="document.querySelector('div').innerText = JSON.stringify(data.take(document.querySelector('input').value))">
  Try it
</button>
<br><br>
Data: {a:{b:{c:{d:"Assalamu alal muslimin"}}}}
<br><br>
Code: data.take(path)
<br><br>
Result:
<div></div>

简而言之,函数是:

function getDataByPath(data, path) {
    if(!path) return data; // if path is undefined or empty return data
    path = path.split("/");
    for(var p in path) {
        if(!path[p]) continue; // "a/" = "a"
      . data = data[path[p]]; // new data is subdata of data
        if(!data) return data; // "a/b/d" = undefined
    }
    return data;
}

还有最短的函数,但是如果输入错误的路径可能会出错:

function getDataByPath(data, path) {
  for(var i in path.split("/")) data = data[path[i]];
  return data;
}

【讨论】:

    【解决方案4】:

    我的解决方案:

    • 基于给定参考的深度优先搜索
    • 使用递归
    • 处理数组

    (可以使用deep_value 函数检索结果。)

    var key4Ref = { abc: 123 }
    
    var data = {
        key1: {
            children: {
                key2:'value',
                key3:'value',
                key4: key4Ref
            }, 
            key5: 'value'
        }
    }
    
    // find the path to a 'ref' within an object 'data'.
    const pathTo = (ref, data, path = []) => {
      const found = data && Object.entries(data).find(([k,v]) => {
        if (v === ref) return path.push(k)
        if (typeof v === 'object') {
          const tmp = pathTo(ref, v, [...path, k])
          if (tmp) return path = tmp
        }
      })
      if (found) return path
    }
    
    console.log(pathTo(key4Ref, data).join('.'))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 2013-04-29
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多