3434 text_types = [str ]
3535
3636class Json2Html :
37- def convert (self , json = "" , table_attributes = 'border="1"' , clubbing = True ):
37+ def convert (self , json = "" , table_attributes = 'border="1"' , clubbing = True , encode = False ):
3838 """
3939 Convert JSON to HTML Table format
4040 """
41-
4241 # table attributes such as class, id, data-attr-*, etc.
4342 # eg: table_attributes = 'class = "table table-bordered sortable"'
4443 self .table_init_markup = "<table %s>" % table_attributes
4544 self .clubbing = clubbing
46-
45+ json_input = None
4746 if not json :
4847 json_input = {}
4948 elif type (json ) in text_types :
5049 json_input = json_parser .loads (json , object_pairs_hook = OrderedDict )
5150 else :
5251 json_input = json
52+ converted = self .convert_json_node (json_input )
53+ if encode :
54+ return converted .encode ('ascii' , 'xmlcharrefreplace' )
55+ return converted
56+
57+ def column_headers_from_list_of_dicts (self , json_input ):
58+ """
59+ This method is required to implement clubbing.
60+ It tries to come up with column headers for your input
61+ """
62+ if not json_input \
63+ or not hasattr (json_input , '__getitem__' ) \
64+ or not hasattr (json_input [0 ], 'keys' ):
65+ return None
66+ column_headers = json_input [0 ].keys ()
67+ for entry in json_input :
68+ if not hasattr (entry , 'keys' ) \
69+ or not hasattr (entry , '__iter__' ) \
70+ or len (entry .keys ()) != len (column_headers ):
71+ return None
72+ for header in column_headers :
73+ if header not in entry :
74+ return None
75+ return column_headers
5376
54- if isinstance (json_input , list ):
77+ def convert_json_node (self , json_input ):
78+ """
79+ Dispatch JSON input according to the outermost type and process it
80+ to generate the super awesome HTML format.
81+ We try to adhere to duck typing such that users can just pass all kinds
82+ of funky objects to json2html that *behave* like dicts and lists and other
83+ basic JSON types.
84+ """
85+ if type (json_input ) in text_types :
86+ return text (json_input )
87+ if hasattr (json_input , 'items' ):
88+ return self .convert_object (json_input )
89+ if hasattr (json_input , '__iter__' ) and hasattr (json_input , '__getitem__' ):
5590 return self .convert_list (json_input )
56- return self . convert_json (json_input )
91+ return text (json_input )
5792
58- def column_headers_from_list_of_dicts (self , json_input ):
93+ def convert_list (self , list_input ):
5994 """
95+ Iterate over the JSON list and process it
96+ to generate either an HTML table or a HTML list, depending on what's inside.
6097 If suppose some key has array of objects and all the keys are same,
6198 instead of creating a new row for each such entry,
6299 club such values, thus it makes more sense and more readable table.
@@ -79,44 +116,8 @@ def column_headers_from_list_of_dicts(self, json_input):
79116
80117 @contributed by: @muellermichel
81118 """
82- if not json_input or not isinstance (json_input [0 ], dict ):
83- return None
84-
85- column_headers = json_input [0 ].keys ()
86- for entry in json_input :
87- if not isinstance (entry , dict ) or (len (entry .keys ()) != len (column_headers )):
88- return None
89- for header in column_headers :
90- if header not in entry :
91- return None
92- return column_headers
93-
94- def convert_json (self , json_input ):
95- """
96- Iterate over the JSON input and process it
97- to generate the super awesome HTML format
98- """
99- if type (json_input ) in text_types + [int , float ]:
100- return text (json_input )
101- if isinstance (json_input , list ) and len (json_input ) == 0 :
102- return ''
103- if isinstance (json_input , list ):
104- list_markup = '<ul><li>'
105- list_markup += '</li><li>' .join ([self .convert_json (child ) for child in json_input ])
106- list_markup += '</li></ul>'
107- return list_markup
108- if isinstance (json_input , dict ):
109- return self .convert_object (json_input )
110-
111- # safety: don't do recursion over anything that we don't know about
112- # - iteritems() will most probably fail
113- return ''
114-
115- def convert_list (self , list_input ):
116- """
117- Iterate over the JSON list and process it
118- to generate either an HTML table or a HTML list, depending on what's inside.
119- """
119+ if not list_input :
120+ return ""
120121 converted_output = ""
121122 column_headers = None
122123 if self .clubbing :
@@ -126,35 +127,35 @@ def convert_list(self, list_input):
126127 converted_output += '<tr><th>' + '</th><th>' .join (column_headers ) + '</th></tr>'
127128 for list_entry in list_input :
128129 converted_output += '<tr><td>'
129- converted_output += '</td><td>' .join ([self .convert_json (list_entry [column_header ]) for column_header in
130+ converted_output += '</td><td>' .join ([self .convert_json_node (list_entry [column_header ]) for column_header in
130131 column_headers ])
131132 converted_output += '</td></tr>'
132133 converted_output += '</table>'
133- else :
134- converted_output += self .convert_json (list_input )
135- return converted_output
134+ return converted_output
136135
137- def convert_cell_content (self , cell_input ):
138- """
139- Wrap content in <td> markup
140- """
141- return '<td>' + self .convert_json (cell_input ) + '</td>'
136+ #so you don't want or need clubbing eh? This makes @muellermichel very sad... ;(
137+ #alright, let's fall back to a basic list here...
138+ converted_output = '<ul><li>'
139+ converted_output += '</li><li>' .join ([self .convert_json_node (child ) for child in list_input ])
140+ converted_output += '</li></ul>'
141+ return converted_output
142142
143143 def convert_object (self , json_input ):
144144 """
145145 Iterate over the JSON object and process it
146146 to generate the super awesome HTML Table format
147147 """
148- converted_output = self .table_init_markup
149- for k , v in json_input .items ():
150- converted_output += '<tr><th>' + self .convert_json (k ) + '</th>'
151- if v is None :
152- v = text ("" )
153- if isinstance (v , list ):
154- converted_output += self .convert_cell_content (self .convert_list (v )) + "</tr>"
155- else :
156- converted_output += self .convert_cell_content (v ) + "</tr>"
157- converted_output += '</table>'
148+ if not json_input :
149+ return "" #avoid empty tables
150+ converted_output = self .table_init_markup + "<tr>"
151+ converted_output += "</tr><tr>" .join ([
152+ "<th>%s</th><td>%s</td>" % (
153+ self .convert_json_node (k ),
154+ self .convert_json_node (v )
155+ )
156+ for k , v in json_input .items ()
157+ ])
158+ converted_output += '</tr></table>'
158159 return converted_output
159160
160161json2html = Json2Html ()
0 commit comments