我有一个大的嵌套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绑定到我的树视图。
答案 0 :(得分: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
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');
好了,现在我们有任何给定搜索数据的正则表达式。让我们从我们离开的地方继续......
// 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)必须先于(?= [允许的字符]后跟[{then [一些更多允许的字符]后跟“child-3”。)因为我们从不允许]
字符永远不会找到任何一个孩子,但只有父母和兄弟姐妹。我们不想要兄弟姐妹..因此我们有\[{
这就是我们如何找到父母并绕过兄弟姐妹。我们有了通缉链。
让我们完成它;
var rx2 = new RegExp('{"x":"([\\w-]+)(?=[":,\\.\\w-]+\\[{[\\[{}":,\\.\\w-]+' + regExpEscape(result[0]) + ')',"g");
while (!!(rar = rx2.exec(js))){result.push(rar[1])}
这似乎就是这样。无论您的JSON对象有多深,都可以获得。
答案 1 :(得分:0)
此提议迭代一个可能的数组,并为具有其前任节点的数组构建每个级别,如果找到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>');
&#13;
答案 2 :(得分:0)
您可以使用这些递归函数:
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];
}