ArrayとかNumberとかStringとかネストの深さとか考えなくても大丈夫(のはず)。
input
var id = 'foo';
var data = {
"key101":"v201",
"key102":["a201","a202"],
"key103":{
"key201":"v301",
"key202":["a301","a302"],
"key203":{
"key301":"v401",
"key302":["a401","a402"],
"key303":{
"key401":"v501",
"key402":["a501","a502"],
"key403":{
"key501":"v601"
}
}
}
},
"key104":{
"key201":["a301","a302"]
},
"key105":{
"key201":{
"key301":"v401"
}
}
};
objToTbl(id, data);
output
見やすく整形済み。
<table id="foo">
<tr><td>key101</td><td colspan="5">v201</td></tr>
<tr><td>key102</td><td colspan="5">a201</td></tr>
<tr><td></td><td colspan="5">a202</td></tr>
<tr><td>key103</td><td>key201</td><td colspan="4">v301</td></tr>
<tr><td></td><td>key202</td><td colspan="4">a301</td></tr>
<tr><td colspan="2"></td><td colspan="4">a302</td></tr>
<tr><td></td><td>key203</td><td>key301</td><td colspan="3">v401</td></tr>
<tr><td colspan="2"></td><td>key302</td><td colspan="3">a401</td></tr>
<tr><td colspan="3"></td><td colspan="3">a402</td></tr>
<tr><td colspan="2"></td><td>key303</td><td>key401</td><td colspan="2">v501</td></tr>
<tr><td colspan="3"></td><td>key402</td><td colspan="2">a501</td></tr>
<tr><td colspan="4"></td><td colspan="2">a502</td></tr>
<tr><td colspan="3"></td><td>key403</td><td>key501</td><td colspan="1">v601</td></tr>
<tr><td>key104</td><td>key201</td><td colspan="4">a301</td></tr>
<tr><td colspan="2"></td><td colspan="4">a302</td></tr>
<tr><td>key105</td><td>key201</td><td>key301</td><td colspan="3">v401</td></tr>
</table>
処理
JSONのフォーマットを利用して整形されたテキストをひたすら置換する。
var data = {"key101":"v201","key102":["a201","a202"],"key103":{"key201":"v301","key202":["a301","a302"],"key203":{"key301":"v401","key302":["a401","a402"],"key303":{"key401":"v501","key402":["a501","a502"],"key403":{"key501":"v601"}}}},"key104":{"key201":["a301","a302"]},"key105":{"key201":{"key301":"v401"}}};
var id = 'foo';
// id: テーブルのID、 data: Object
objToTbl(id, data);
/* table を返却する @public*/
function objToTbl(id, data){
var reg = /(<td><\/td>){1,}/; // 前方の空td検出用
var depth = check_depth(data) + 1, arr = refact(data), txt = '';
arr.shift();
arr.pop();
for(var i = 0, l = arr.length; i < l; i++){
var row = arr[i].replace(/: /g, '\t').replace(/$/, '</td></tr>').replace(/^\t/, '<tr><td>').replace(/\t/g, '</td><td>');
var xx = $(row).find('td').length, len = depth - xx;
// value & 後方空td連結
var tmp = row.replace(/<td>(\w*<\/td>)<\/tr>$/, `<td colspan="${len}">$1</tr>`);
var fcols = reg.exec(tmp), fcollen = (fcols === null) ? 0 : fcols[0].split(fcols[1]).length - 1;
txt += tmp.replace(/(<td><\/td>){1,}/,`<td colspan="${fcollen}"></td>`);
}
return `<table id="${id}">${txt}</table>`;
}
/* オブジェクトの深さを探索する @private */
function check_depth(data) {
var jsonArr = JSON.stringify(data, null, '\t').replace(/(^(\{|\[)|(\{|\[)$)/g, '').split(',\n');
var jl = jsonArr.length, result = [];
for(var i = 0; i < jl; i++) {
jsonArr[i] = jsonArr[i].replace(/(\r|\n|\r\n)/g, '').replace(/\t{1,}(\}|\])/g, '$1');
var d = jsonArr[i].replace(/(\n|^\t|\t$)/g, '').trim();
//console.log(d);
result.push(d.split('\t').length);
}
return (result.length) ? Math.max.apply(null, result) : 0 ;
}
/* オブジェクトを表示用に整形する @private */
function refact(data) {
var txt = JSON.stringify(data, null, '\t').replace(/(^(\{|\[)|(\{|\[)$|(\{|\[|\t{1,}(\}|\]))|,|\}|(^\n|\n$))/g, '');
var splited = txt.replace(/(:[ ]{0,}(\r\n|\r|\n)\t{1,})/g,': ').replace(/(\r\n|\r|\n){1,}/g, '\n').replace(/\"/g, '').split('\n');
return splited;
}