2016-03-24 46 views
1

我有一個大的嵌套JSON文件,我用它來綁定到樹視圖。我想通過文本搜索這個treeview數據源,並獲得匹配的所有節點,直到它的父節點,所以我可以保留樹結構。因此,可以說我有一個JSON象下面這樣:用jQuery或Javascript搜索嵌套的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

古怪和邪惡的問題:你有什麼嘗試,給我們看一些代碼 – madalinivascu

+0

請添加一個想要的返回值的例子。 –

+0

簡單的方法:JSON.stringify每個數組元素,當你迭代,然後匹配你的術語到JSON。 'r.filter(x => JSON.stringify(x).match(term))' – dandavis

回答

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>');

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]; 
} 
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 

到目前爲止好。我們有了我們正在搜索的結果的對象的名稱。現在,爲了從它的父母得到相同的信息,我們將使用這兩個事實

  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對象有多深。

+0

感謝大家的建議。我們使用父ID和其他信息在SQL表中存儲相同的JSON數據。實際上,我們使用現有的SQL存儲過程來搜索數據庫中的數據,並將記錄作爲關係數據返回。我們比使用C#代碼將此關係數據轉換爲JSON字符串並使用它顯示搜索結果。 – user2272865