spidee
spidee

Reputation: 547

python: serialize a dictionary into a simple html output

using app engine - yes i know all about django templates and other template engines.

Lets say i have a dictionary or a simple object, i dont know its structure and i want to serialize it into html.

so if i had

{'data':{'id':1,'title':'home','address':{'street':'some road','city':'anycity','postal':'somepostal'}}}

want i want is that rendered in some form of readable html using lists or tables;

data:
   id:1
   title:home
   address:
           street: some road
           city: anycity
           postal:somepostal

now i know i can do

for key in dict.items
print dict[key]

but that wont dive into the child values and list each key, value pair when the key/value is a dictionary - ie the address dict.

Is their a module for python that is lightweight/fast that will do this nicely. or does anyone have any simple code they can paste that might do this.

Solution All the solutions here were useful. pprint is no doubt the more stable means of printing the dictionary, though it falls short of returning anything near html. Though still printable.

I ended up with this for now:

def printitems(dictObj, indent=0):
    p=[]
    p.append('<ul>\n')
    for k,v in dictObj.iteritems():
        if isinstance(v, dict):
            p.append('<li>'+ k+ ':')
            p.append(printitems(v))
            p.append('</li>')
        else:
            p.append('<li>'+ k+ ':'+ v+ '</li>')
    p.append('</ul>\n')
    return '\n'.join(p)

It converts the dict into unordered lists which is ok for now. some css and perhaps a little tweaking should make it readable.

Im going to reward the answer to the person that wrote the above code, i made a couple of small changes as the unordered lists were not nesting. I hope all agree that many of the solutions offered proved useful, But the above code renders a true html representation of a dictionary, even if crude.

Upvotes: 15

Views: 31318

Answers (9)

Vishal Gupta
Vishal Gupta

Reputation: 140

Here's my simple solution, It can handle any level of nested dictionary.

import json
temp_text = {'decision': {'date_time': None, 'decision_type': None},
             'not_received': {'date_time': '2019-04-15T19:18:43.825766'},
             'received': {'date_time': None},
             'rfi': {'date_time': None},
             'under_review': {'date_time': None}}
dict_text_for_html = json.dumps(
    temp_text, indent=4
).replace(' ', '&nbsp').replace(',\n', ',<br>').replace('\n', '<br>')

html view of python dict

Upvotes: 6

Mohammad Reza
Mohammad Reza

Reputation: 135

imagine we have this :{name: "a", children:[{name: "b", children: [] },{..},{..}]

def ConvertDictToUlLi():
    jsonResult = GetSomeRecursiveDict()

    def CreateHtml(DictItem, output):
        output = "<li>"+DictItem["name"] if jsonResult.has_key("name") else " "
        if len(DictItem["children"]) > 0:
           output = output + "<ul>"
           for item in DictItem["children"]:
              output = output + "  "+CreateHtml(item, output)+"  "
           output = output + "</ul>"
      return output+"</li>"
    result = "<ul class='tree'>"+CreateHtml(jsonResult, "")+"</ul>"

return result

Upvotes: 0

sorrat
sorrat

Reputation: 923

Here is my version with support of lists (labels are verbose names of keys in dictionary):

def render_value(value, labels):
    if isinstance(value, (list, tuple)):
        return render_list(value, labels)
    elif isinstance(value, dict):
        return render_dict(value, labels)
    else:
        return value


def render_list(lst, labels):
    items = [
        '<li>%s</li>' % render_value(value, labels)
        for value in lst
    ]
    return '\n'.join(['\n<ul>'] + items + ['</ul>\n'])


def render_dict(dct, labels):
    items = []
    for key, value in dct.items():
        if not value: continue

        key = labels.get(key, key)
        value = render_value(value, labels)
        items.append('<li><b>%s</b>: %s</li>' % (key, value))

    return '\n'.join(['\n<ul>'] + items + ['</ul>\n'])

Upvotes: 0

Sarang
Sarang

Reputation: 2723

None of the above examples give good results, so I wrote two of my own functions that create beautiful looking html output for dictionaries.

def dict_to_html(dd, level=0):
    """
    Convert dict to html using basic html tags
    """
    import simplejson
    text = ''
    for k, v in dd.iteritems():
        text += '<br>' + '&nbsp;'*(4*level) + '<b>%s</b>: %s' % (k, dict_to_html(v, level+1) if isinstance(v, dict) else (simplejson.dumps(v) if isinstance(v, list) else v))
    return text

def dict_to_html_ul(dd, level=0):
    """
    Convert dict to html using ul/li tags
    """
    import simplejson
    text = '<ul>'
    for k, v in dd.iteritems():
        text += '<li><b>%s</b>: %s</li>' % (k, dict_to_html_ul(v, level+1) if isinstance(v, dict) else (simplejson.dumps(v) if isinstance(v, list) else v))
    text += '</ul>'
    return text

Upvotes: 2

Sasha
Sasha

Reputation: 1072

I needed something similar, but also wanted to pretty print lists, and lists inside the dict. Here's what I came up:

def format(self, obj, indent = 1):
    if isinstance(obj, list):
        htmls = []
        for k in obj:
            htmls.append(self.format(k,indent+1))

        return '[<div style="margin-left: %dem">%s</div>]' % (indent, ',<br>'.join(htmls))

    if isinstance(obj, dict):
        htmls = []
        for k,v in obj.iteritems():
            htmls.append("<span style='font-style: italic; color: #888'>%s</span>: %s" % (k,self.format(v,indent+1)))

        return '{<div style="margin-left: %dem">%s</div>}' % (indent, ',<br>'.join(htmls))

    return str(obj)

Then, if you're using webapp on appengine, you can just do the following:

self.response.out.write(self.format(obj))

This is an example of the output:

enter image description here

Upvotes: 3

Mattias Nilsson
Mattias Nilsson

Reputation: 3757

The example made by pyfunc could easily be modified to generate simple nested html lists.

z = {'data':{'id':1,'title':'home','address':{'street':'some road','city':'anycity','postal':'somepostal'}}}

def printItems(dictObj, indent):
    print '  '*indent + '<ul>\n'
    for k,v in dictObj.iteritems():
        if isinstance(v, dict):
            print '  '*indent , '<li>', k, ':', '</li>'
            printItems(v, indent+1)
        else:
            print ' '*indent , '<li>', k, ':', v, '</li>'
    print '  '*indent + '</ul>\n'

printItems(z,0)

Not terribly pretty of course, but somewhere to start maybe. If all you want to do is visualize data, the pprint module really is good enough. You could just use the "pre" tag on the result from pprint and put that on your web page.

the pprint version would look something like this:

import pprint
z = {'data':{'id':1,'title':'home','address':{'street':'some road','city':'anycity','postal':'somepostal'}}}

print '<pre>', pprint.pformat(z), '</pre>'

And the html output look something like this:

{'data': {'address': {'city': 'anycity',
                      'postal': 'somepostal',
                      'street': 'some road'},
          'id': 1,
          'title': 'home'}}

Which isn't that pretty, but it at least shows the data in a more structured way.

Upvotes: 9

Rogerio Hilbert
Rogerio Hilbert

Reputation: 71

Look at my implementation:

def pretty_items(r, d, nametag="<strong>%s: </strong>", itemtag='<li>%s</li>',
             valuetag="%s", blocktag=('<ul>', '</ul>')):
if isinstance(d, dict):
    r.append(blocktag[0])
    for k, v in d.iteritems():
        name = nametag % k
        if isinstance(v, dict) or isinstance(v, list):
            r.append(itemtag % name)
            pretty_items(r, v)
        else:
            value = valuetag % v
            r.append(itemtag % (name + value))
    r.append(blocktag[1])
elif isinstance(d, list):
    r.append(blocktag[0])
    for i in d:
        if isinstance(i, dict) or isinstance(i, list):
            r.append(itemtag % " - ")
            pretty_items(r, i)
        else:
            r.append(itemtag % i)
    r.append(blocktag[1])

Will output all items in HTML format using <ul> and <li> tags. And is also optional to change the tags. And then, just use CSS to handle with the indentation.

Upvotes: 2

eumiro
eumiro

Reputation: 213005

import pprint


pprint.pprint(yourDict)

Well, no HTML, but similar to your for/print approach.

EDIT: or use:

niceText = pprint.pformat(yourDict)

this will give you the same nice output with all indents, etc. Now you can iterate over lines and format it into HTML:

htmlLines = []
for textLine in pprint.pformat(yourDict).splitlines():
    htmlLines.append('<br/>%s' % textLine) # or something even nicer
htmlText = '\n'.join(htmlLines)

Upvotes: 7

pyfunc
pyfunc

Reputation: 66729

You could use pretty print (pprint)

or if you want to do some further processing of display then you have to run through the dict yourself.

Be warned that the code is crude and will require numerous refinements. Solution uses recursion too, which is bad, if the recursion depth is higher.

z = {'data':{'id':1,'title':'home','address':{'street':'some road','city':'anycity','postal':'somepostal', 'telephone':{'home':'xxx','offie':'yyy'}}}}

def printItems(dictObj, indent):
    it = dictObj.iteritems()
    for k,v in it:
        if isinstance(v, dict):
            print ' '*indent , k, ':'
            printItems(v, indent+1)
        else:
            print ' '*indent , k, ':', v

printItems(z,0)

Output:

 data :
  address :
   city : anycity
   postal : somepostal
   street : some road
   telephone :
    home : xxx
    offie : yyy
  id : 1
  title : home

Upvotes: 1

Related Questions