Mi JSON podría tener "n" capas de subesquema. ¿Cómo puedo detectar si una clave tiene un subesquema debajo para evitar que se repita incorrectamente como lo está haciendo hoy? Como puede ver en mi código a continuación, estoy empezando a considerar mover los subesquemas a matrices, pero esto parece una solución, no el enfoque correcto. Por último, ¿es posible evitar múltiples bucles FOR para manejar mejor las capas "n" del subesquema?
HTML
<table></table>JavaScript
var data = { "THREE LEVEL": { "PRODUCTION": { "One": "http://one.com", "Two": "http://two.com" }, "LATEST": { "alpha": "http://alpha.com", "omega": "http://omega.com" }, "STAGE": { "Apha": "http://alpha.com", "Bravo": "http://bravo.com", "Charley": "http://charley.com" } }, "TWO LEVEL": { "PRODUCTION": "http://aaa.com", "LATEST": "http://bbb.com", "STAGE": "http://ccc.com" } } var table = document.querySelector('table'); var rows = ''; for (var lev_1 in data) { rows += '<tr><td>' + lev_1 + '</td><td></td></tr>' //if(Array.isArray(data[lev_1])){ for (var lev_2 in data[lev_1]) { rows += '<tr><td><a href="' + data[lev_1][lev_2] + '">' + lev_2 + '</td><td></td></tr>' //if(Array.isArray(data[lev_1][lev_2])) { for (var lev_3 in data[lev_1][lev_2]) { rows += '<tr><td><a href="' + data[lev_1][lev_2][lev_3] + '">' + lev_3 + '</td><td></td></tr>' } //} } //} } table.innerHTML = rows;Salida de corriente
THREE LEVEL PRODUCTION One Two LATEST alpha omega STAGE Apha Bravo Charley TWO LEVEL PRODUCTION 0 1 2 3 4 5 6 7 8 9 10 11 12 13 LATEST 0 1 2 3 4 5 6 7 8 9 10 11 12 13 STAGE 0 1 2 3 4 5 6 7 8 9 10 11 12 13Use typeof() para determinar con qué tipo de elemento está tratando.
Si es un objeto, use Object.keys() para obtener una matriz de todas las claves dentro del objeto. Luego iterar a través de las claves, probando cada una con typeof()...
Si es una matriz, itere a través de cada elemento de la matriz probando cada uno con typeof()
Enjuague y repita.
El siguiente ejemplo debería darle una mejor idea de cómo proceder.
var data = { "THREE LEVEL": { "PRODUCTION": { "One": "http://one.com", "Two": "http://two.com" }, "LATEST": { "alpha": "http://alpha.com", "omega": "http://omega.com" }, "STAGE": { "Apha": "http://alpha.com", "Bravo": "http://bravo.com", "Charley": "http://charley.com" } }, "TWO LEVEL": { "PRODUCTION": "http://aaa.com", "LATEST": "http://bbb.com", "STAGE": "http://ccc.com" } } var table = document.querySelector('table'); var rows = ''; var iterateObject = function(dataObject) { var keys = Object.keys(dataObject); keys.forEach(function(key) { var textArray = []; var element = dataObject[key]; switch (typeof(element)) { case 'object': textArray.push(key) dumpRow(textArray); iterateObject(element); break; case 'array': textArray.push(key) dumpRow(textArray); iterateArray(element); break; default: dumpElement(dataObject, key); break; } }); }; var iterateArray = function(dataArray) { dataArray.forEach(function(element) { switch (typeof(element)) { case 'object': iterateObject(element); break; case 'array': iterateArray(element); break; default: var textArray = []; textArray.push(element) dumpRow(textArray); break; } }); }; var dumpElement = function(obj, key) { var textArray = []; textArray.push(key); textArray.push(obj[key]); dumpRow(textArray); }; var dumpRow = function(textArray) { var dumpString = '<tr>'; textArray.forEach(function(text) { dumpString += dumpCell(text); }); dumpString += '</tr>'; rows += dumpString; }; var dumpCell = function(dumpText) { var dumpString = '<td>'; dumpString += dumpText; dumpString += '</td>'; return dumpString; }; switch (typeof(data)) { case 'object': iterateObject(data); break; case 'array': iterateArray(data); break; default: var textArray = []; textArray.push(data) dumpRow(textArray); break; } table.innerHTML = rows; <html> <body> </body> <table> </table> </html>Probablemente deberías hacer algún tipo de TableMaker :
//<![CDATA[ /* js/external.js */ let doc, htm, bod, nav, M, I, mobile, S, Q, TableMaker; // for use on other loads addEventListener('load', () => { doc = document; htm = doc.documentElement; bod = doc.body; nav = navigator; M = tag => doc.createElement(tag); I = id => doc.getElementById(id); mobile = /Mobi/i.test(nav.userAgent); S = (selector, within) => { let w = within || doc; return w.querySelector(selector); } Q = (selector, within) => { let w = within || doc; return w.querySelectorAll(selector); } TableMaker = function(object) { this.table = M('table'); this.thead = M('thead'); this.tbody = M('tbody'); this.tfoot = M('tfoot'); this.trMake = () => { return M('tr'); } this.thMake = textContent => { const th = M('th'); th.textContent = textContent; return th; } this.tdMake = textContent => { const td = M('td'); td.textContent = textContent; return td; } if (object !== undefined) { let tr, o, n, td; for (let k in object) { tr = this.trMake(); if (typeof k === 'string') { tr.appendChild(this.tdMake(k)); this.tbody.appendChild(tr); o = object[k]; if (typeof o === 'string') { tr.appendChild(this.tdMake(o)); } else { n = new TableMaker(object[k]); td = this.tdMake(); td.appendChild(n.table); tr.append(td); } } } } this.table.appendChild(this.thead); this.table.appendChild(this.tbody); this.table.appendChild(this.tfoot); } // magic below can be put on a separate page - except // end load line var data = { "THREE LEVEL": { "PRODUCTION": { "One": "http://one.com", "Two": "http://two.com" }, "LATEST": { "alpha": "http://alpha.com", "omega": "http://omega.com" }, "STAGE": { "Apha": "http://alpha.com", "Bravo": "http://bravo.com", "Charley": "http://charley.com" } }, "TWO LEVEL": { "PRODUCTION": "http://aaa.com", "LATEST": "http://bbb.com", "STAGE": "http://ccc.com" } } const tM = new TableMaker(data); bod.appendChild(tM.table); }); // end load //]]> table { border: 1px solid #000; } td { border: 1px solid #090; } Notarás que también he incluido una pequeña biblioteca. Tenga en cuenta la naturaleza recursiva de TableMaker .