【问题标题】:Search Nested JSON with jQuery or Javascript使用 jQuery 或 Javascript 搜索嵌套的 JSON
【发布时间】:2016-03-24 07:45:17
【问题描述】:

我有一个大的嵌套 JSON 文件,用于绑定到树视图。我想通过文本搜索这个树视图数据源并获取所有匹配的节点,直到它的父节点,这样我就可以保留树结构。所以假设我有一个如下所示的 JSON:

[
  {
    "x": "Root-1",
    "y": "000001",
    "c": [
      {
        "x": "child-1",
        "y": "000001.1"
      },
      {
        "x": "child-2",
        "y": "000001.2",
        "c": [
          {
            "x": "child-3",
            "y": "000001.3"
          }
        ]
      }
    ]
  },
  {
    "x": "Root-2",
    "y": "000002",
    "c": [
      {
        "x": "child-4",
        "y": "000002.1"
      },
      {
        "x": "child-5",
        "y": "000002.2",
        "c": [
          {
            "x": "child-6",
            "y": "000002.3",
            "c": [
              {
                "x": "child-7",
                "y": "000002.4"
              }
            ]
          }
        ]
      }
    ]
  }
]

现在在一个文本框中,我想做一个包含搜索:“1.3”,它应该在具有相同嵌套的对象下面返回我:

child-3(因为这个匹配),child-2(child-3 的父母)和 root-1(child-2 的父母)。

现在我可以使用这个 JSON 绑定到我的树视图。

【问题讨论】:

  • 古老而邪恶的问题:你尝试了什么,给我们一些代码
  • 请添加所需返回值的示例。
  • 最简单的方法:在迭代时 JSON.stringify 每个数组元素,然后将您的术语与 JSON 匹配。 r.filter(x=>JSON.stringify(x).match(term))

标签: javascript jquery json treeview


【解决方案1】:

实际上与任意文本字符串不同,一旦字符串化,JSON 数据会产生一个非常规则的结构化字符串,因此我们可以应用很酷的正则表达式,将代码缩减为 2~3 行。我不确定这个或递归或迭代是否更有效。稍后我会试一试。

TL&DR 代码是这样的。 F12 是你的朋友。

function regExpEscape(literal_string) {
  return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}
// assuming that your json data is assigned to a variable jd
var js = JSON.stringify(jd),
    sd = 1.3.toString(), //this input value should be supplied as string
   rx1 = new RegExp('{"x":"([\\w-]+)[",:\\w]+(?=' + regExpEscape(sd) + ')',"g"),
   rar = [],
result = [];

rar = rx1.exec(js); // < ["{"x":"child-3","y":"00000", "child-3"]
rar.length && result.push(rar[1]); // if rar is not empty save rar[1] to result 
var rx2 = new RegExp('{"x":"([\\w-]+)(?=[":,\\.\\w-]+\\[{[\\[{}":,\\.\\w-]+'  + regExpEscape(result[0]) + ')',"g");
while (!!(rar = rx2.exec(js))){result.push(rar[1])} // ["child-3", "Root-1", "child-2"]

讲故事的部分:

只需两步,我们就可以得到我们想要的结果。让我们看看

为了检查 1.3 是否存在并获取 x 属性的值(名称),我们可以使用 /{"x":"([\w-]+)[",:\w]+(?=1\.3)/g 正则表达式。但接下来让我们想办法让这个正则表达式可重用。

// assuming that your search data is assigned to a variable sd
function regExpEscape(literal_string) {
  return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}
var rx = '/{"x":"([\w-]+)[",:\w]+(?=' + regExpEscape(sd) + ')/g');

好的,现在我们有了任何给定搜索数据的正则表达式。让我们从离开的地方继续……

// assuming that your json data is assigned to a variable jd
var js = JSON.stringify(jd),
    sd = 1.3.toString(), //this input value should be supplied as string
   rx1 = new RegExp('{"x":"([\\w-]+)[",:\\w]+(?=' + regExpEscape(sd) + ')',"g"),
   rar = [],
result = [];

rar = rx1.exec(js); // < ["{"x":"child-3","y":"00000", "child-3"]
rar.length && result.push(rar[1]); // if rar is not empty save rar[1] to result 

到目前为止一切顺利。我们有我们正在搜索的结果的对象的名称。现在为了从它的父母那里获得相同的信息,我们将使用这两个事实

  1. 在孩子和它的父母之间不应该有任何] 字符。
  2. 遇到[ 字符时到达父元素。

酷让我们继续。我对此有点动脑筋,想出了/{"x":"([\w-]+)(?=[":,\.\w-]+\[{[\[{}":,\.\w-]+child-3)/g 好吧,它看起来有点神秘,但实际上很简单。让我过去。它由两部分组成 xxx(yyy) 必须在 (?= [允许的字符] 后跟 [{ 然后 [更多允许的字符] 后跟 "child-3"。)。由于我们不允许 ] 字符我们永远不会得到任何人的孩子,但只有父母和兄弟姐妹。我们不想要兄弟姐妹.. 因此我们有\[{ 这就是我们到达父母并绕过兄弟姐妹的方式。我们得到了通缉链。

让我们完成它;

var rx2 = new RegExp('{"x":"([\\w-]+)(?=[":,\\.\\w-]+\\[{[\\[{}":,\\.\\w-]+'  + regExpEscape(result[0]) + ')',"g");
while (!!(rar = rx2.exec(js))){result.push(rar[1])}

好像是这样。无论您的 JSON 对象有多深。

【讨论】:

  • 感谢大家的建议。我们将相同的 JSON 数据存储在带有父 ID 和其他信息的 SQL 表中。我们实际上是使用现有的 SQL 存储过程来搜索数据库中的数据并将记录作为关系数据返回。我们比使用 C# 代码将这些关系数据转换为 JSON 字符串并使用它来显示搜索结果。
【解决方案2】:

这个提议迭代一个可能的数组,并为每个级别构建一个包含其前驱节点的数组,如果找到search,则将路径推送到结果。迭代适用于短路。对于下一个级别,再次调用该函数,并使用新的基础和实际节点的先前路径。

function getNodes(tree, search) {
    function n(a, t) {
        return Array.isArray(a) && a.some(function (b) {
            return b.y.match(search) && r.push([].concat(b, t)) || n(b.c, [].concat(b, t));
        });
    }

    var r = [];
    n(tree, []);
    return r;
}

var tree = [{ "x": "Root-1", "y": "000001", "c": [{ "x": "child-1", "y": "000001.1" }, { "x": "child-2", "y": "000001.2", "c": [{ "x": "child-3", "y": "000001.3" }] }] }, { "x": "Root-2", "y": "000002", "c": [{ "x": "child-4", "y": "000002.1" }, { "x": "child-5", "y": "000002.2", "c": [{ "x": "child-6", "y": "000002.3", "c": [{ "x": "child-7", "y": "000002.4" }] }] }] }];

document.write('<pre>' + JSON.stringify(getNodes(tree, '1.3'), 0, 4) + '</pre>');

【讨论】:

    【解决方案3】:

    您可以使用这些递归函数:

    var result = find( data, 1, 1, 0, 0 );
    
    function find() {
        var args = [].slice.call( arguments );
        var root = args.shift();
        if( args.length == 0 ) return [];
        var index = args.shift();
        root = nthChild( root, index );
        if( typeof root  === 'undefined' ) {
            throw Error( "Invalid index " + index + " at level " + args.length + " from the tail!" );
        }
        args.unshift( root );
        return [root].concat( find.apply( undefined, args ) );
    }
    
    
    function nthChild( root, index ) {
        // If we are not in an array, let take the "c" attribute.
        if( !Array.isArray( root ) ) root = root.c;
        return root[index];
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-11
      • 2014-11-13
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      相关资源
      最近更新 更多