我有一个很大的嵌套JSON文件,我用它绑定到treeview。我希望通过文本搜索此treeview数据源,并获取匹配到其父节点的所有节点,以便我可以保留树结构。假设我有一个如下所示的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(子节点2的父节点)。
现在我可以使用这个JSON绑定到我的树视图了。
发布于 2016-03-25 01:45:45
实际上,与任意文本字符串不同,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 regexp。但是,让我们找到一种方法来使这个正则表达式可重用。
// 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');好了,现在我们有了针对任何给定搜索数据的regexp。让我们从我们离开的地方继续……
// 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 到目前一切尚好。我们有对象的名称和我们要搜索的结果。现在,为了从它的父母那里获得相同的信息,我们将使用以下两个事实
]字符。[字符时,将到达父元素。酷,让我们继续吧。我想了想,想出了/{"x":"([\w-]+)(?=[":,\.\w-]+\[{[\[{}":,\.\w-]+child-3)/g,好吧,它看起来有点神秘,但实际上相当简单。让我过去。它由两部分组成,前面必须是xxx(yyy) (子级允许的字符后跟[{,然后是一些更多允许的字符,后跟“?=-3”。)因为我们从来不允许使用]字符,所以我们永远不会访问任何人的孩子,而只能访问父母和兄弟姐妹。我们不想要兄弟姐妹..因此,我们有了\[{,这就是我们如何到达父级并绕过兄弟级的。我们拿到通缉链了。
让我们完成它;
var rx2 = new RegExp('{"x":"([\\w-]+)(?=[":,\\.\\w-]+\\[{[\\[{}":,\\.\\w-]+' + regExpEscape(result[0]) + ')',"g");
while (!!(rar = rx2.exec(js))){result.push(rar[1])}看起来就是这样了。不管你的JSON对象有多深。
发布于 2016-03-24 16:21:41
该建议遍历可能的数组,并为每个级别构建一个包含其前置节点的数组,如果找到search,则将路径推送到结果。迭代在短路情况下工作。对于下一级,使用新的base和到实际节点的前一个路径再次调用该函数。
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>');
发布于 2016-03-24 16:23:54
您可以使用以下递归函数:
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];
}https://stackoverflow.com/questions/36195321
复制相似问题