Reputation: 471
I currently have a nested dictionary object in Python that I want to loop through to essentially create an html table. I already know the basics on what to do, but need help with determining the number of rows each column should span. Let me explain more with an example:
Input:
{
"system":{
"System Apps":{
"SystemEnv":[
'App Test',
'App Memory',
'App Test']
"SystemEnv2":{
"System Test":[
'App Test']
}},
"System Memory":{
"Memeory Test":[
'Memory Func',
'Apes Test']
}
}
}
}
}
The problem lies in putting the rowspan attribute and having the correct number of rows to span. I understand that it is the number of children the parent has, but I can seem to figure out how to code it.
Also second priority, but if someone sees a more efficient way of doing this, please let me know.
for level1 in dictObj:
html += "<tr>"
html += '<td>{}</td>'.format(level1)
for level2 in dictObj[level1]:
if not first_run:
html += "<tr>"
html += '<td>{}</td>'.format(level2)
first_run = True
for level3 in dictObj[level1][level2]:
if not first_run:
html += "<tr>"
html += '<td>{}</td>'.format(level3)
first_run = True
for app in dictObj[level1][level2][level3]:
if not first_run:
html += "<tr>"
first_run = True
for test in dictObj[level1][level2][level3][app]:
if not first_run:
html += "<tr>"
html += '<td>{}</td>'.format(test)
html += '<td>{}</td>'.format(app)
html += '<td>{}</td>'.format('mb')
html += '<td>{}</td>'.format(1)
html += '</tr>'
first_run = False
Upvotes: 3
Views: 13326
Reputation: 1
<tr>
<td>Level1</td>
<td>Level2</td>
<td>Level3</td>
<td>Info</td>
<td>Name</td>
</tr>
<tr>
<td rowspan="6">System</td>
<td rowspan="4">System Apps</td>
<td rowspan="3">SystemEnv</td>
<td>App Test</td>
<td>Foo</td>
</tr>
<tr>
<td>App Memory</td>
<td>Foo</td>
</tr>
<tr>
<td>App Test</td>
<td>bar</td>
</tr>
<tr>
<td>SystemEnv2</td>
<td>App Test</td>
<td>bar</td>
</tr>
<tr>
<td rowspan="2">System Memory</td>
<td rowspan="2">Memory Test</td>
<td>Memory func</td>
<td>foo</td>
</tr>
<tr>
<td>App Test</td>
<td>Foo</td>
</tr>
</table>
</div>
Upvotes: 0
Reputation: 195438
The data you provided seems incomplete, so key [System][System Apps][SystemEnv2][System Test][App Test]
sticks out (its longest, every other key's shorter by 1):
data = {
"system":{
"System Apps":{
"SystemEnv":[
'App Test',
'App Memory',
'App Test'],
"SystemEnv2":{
"System Test":[
'App Test']
}
},
"System Memory":{
"Memeory Test":[
'Memory Func',
'Apes Test']
}
}
}
# }
# }
def num_items(d):
if isinstance(d, list):
for i in d:
for ii in num_items(i):
yield ii
elif isinstance(d, dict):
for k, v in d.items():
for ii in num_items(v):
yield ii
else:
yield 1
def traverse(d, cur=[]):
if isinstance(d, list):
for i in d:
cur.append( (i, sum(num_items(i))) )
for ii in traverse(i, cur):
yield ii
elif isinstance(d, dict):
for k, v in d.items():
cur.append( (k, sum(num_items(v))) )
for ii in traverse(v, cur):
yield ii
else:
yield cur
del cur[:]
print('<table border=4>')
for row in traverse(data):
print('<tr>')
for td, rowspan in row:
print('<td rowspan={}>{}</td>'.format(rowspan, td))
print('</tr>')
print('</table>')
Prints:
<table border=4>
<tr>
<td rowspan=6>system</td>
<td rowspan=4>System Apps</td>
<td rowspan=3>SystemEnv</td>
<td rowspan=1>App Test</td>
</tr>
<tr>
<td rowspan=1>App Memory</td>
</tr>
<tr>
<td rowspan=1>App Test</td>
</tr>
<tr>
<td rowspan=1>SystemEnv2</td>
<td rowspan=1>System Test</td>
<td rowspan=1>App Test</td>
</tr>
<tr>
<td rowspan=2>System Memory</td>
<td rowspan=2>Memeory Test</td>
<td rowspan=1>Memory Func</td>
</tr>
<tr>
<td rowspan=1>Apes Test</td>
</tr>
In browser it's like this:
Upvotes: 4
Reputation: 344
I suggest that for each cell, with the cell name as the key, you set the row span equal to the number of items values at the further value of the dictionary in the corresponding value.
For example,
Input:
{
"system":{ # span = 5 since system_apps(2) + SystemEnv(1) + System_Memory(2) = 5
"system_apps":{ # span = 2 since it only contains systemEnv with span of 2
"SystemEnv":{ # span = 2 since there are 2 items (test1 object, test2 object)
test1 object,
test2 object
},
"SystemEnv2":{ # span = 1 since it only contains system test which has span of 1
"System Test":{ # span = 1 (test1 object)
test1 object
},
"System Memory":{ # span = 2 since it only contains memory test which contains span of 2
"Memory Test":{ # span = 2 (corresponds with test3 object and test4 object)
test3 object,
test4 object
}
}
}
}
}
If you know the level (assuming they all contain the same number of levels), set the row span to the sum of the spans of the immediate children, starting at the furthest child. Any item that is not a dictionary will automatically have a span of 1, and you just add the row spans, and then proceed to the next level until you get to the top.
Upvotes: 1