1

I've seen multiple of examples of this online, but I've not found anything that helps me solve the problem I'm faced with. I'm trying to convert a JSON object into an HTML table, but I'm faced with a couple of issues.

Suppose I have the following object, call it tableJson, which is essentially representative of a table with only column headers:

[
  {
    "firstColumn": []
  },
  {
    "secondColumn": []
  },
  {
    "thirdColumn": []
  }
]

In trying to convert this into an HTML table, I have done the following:

jsonDumps = json.dumps(jsonTable)
htmlTable = json2html.convert(json = jsonDumps)

Seems pretty simply. However, the result of htmlTable gives me two issues:

  1. The output is in a bullet point list format
  2. Each column header is treated as a separate table

For example, the result of htmlTable above is:

<ul>
  <li>
    <table border="1">
      <tr><th>firstColumn</th><td></td></tr>
    </table>
  </li>
  <li>
    <table border="1">
      <tr><th>secondColumn</th><td></td></tr>
    </table>
  </li>
  <li>
    <table border="1">
      <tr><th>thirdColumn</th><td></td></tr>
    </table>
  </li>
</ul>

What is the simply way of creating a table (correctly) so that I don't have it in a bullet point list and so that each column is treated as a correct column rather than a table?

Is there a problem with the way the JSON object is represented? If so, what is the correct syntax so that json2html converts it correctly into a table?

martineau
  • 119,623
  • 25
  • 170
  • 301
Adam
  • 2,384
  • 7
  • 29
  • 66
  • what should the resulting table be? you may find a Pandas DataFrame's [`.to_html()` method](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html) works well for you and provides a nicer opportunity to massage the data early – ti7 Sep 21 '21 at 12:04
  • I guess my idea would have just a regular HTML table. For example, something along the lines of `
    firstRow
    secondRow
    thridRow
    `
    – Adam Sep 21 '21 at 12:07

1 Answers1

1

There's some issue with the original structure if your table, which is clearer when you attempt to create a DataFrame from it; if you restructure it as a single dict first, you may find it much easier to work with and can directly use Pandas to render your table

Starting Values

>>> import pandas as pd
>>> src_table = [
...   {
...     "firstColumn": []
...   },
...   {
...     "secondColumn": []
...   },
...   {
...     "thirdColumn": []
...   }
... ]

Demo of issue

(each column is unique, rather than being in the same collection)

>>> pd.DataFrame(src_table)
  firstColumn secondColumn thirdColumn
0          []          NaN         NaN
1         NaN           []         NaN
2         NaN          NaN          []

Flatten list of dicts and Display

See How do I merge a list of dicts into a single dict?

>>> src_flattened = dict(pair for d in src_table for pair in d.items())
>>> src_flattened
{'firstColumn': [], 'secondColumn': [], 'thirdColumn': []}
>>> df = pd.DataFrame(src_flattened)
>>> df
Empty DataFrame
Columns: [firstColumn, secondColumn, thirdColumn]
Index: []
>>> print(df.to_html())
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>firstColumn</th>
      <th>secondColumn</th>
      <th>thirdColumn</th>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

Rendered

table headers render

With a few values inserted

>>> pd.DataFrame({"col1": [1,2,3], "col2": [4,5,6], "col3": ['a', None, False]}).to_html()
'<table border="1" class="dataframe">\n  <thead>\n    <tr style="text-align: right;">\n      <th></th>\n      <th>col1</th>\n      <th>col2</th>\n      <th>col3</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>1</td>\n      <td>4</td>\n      <td>a</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>2</td>\n      <td>5</td>\n      <td>None</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3</td>\n      <td>6</td>\n      <td>False</td>\n    </tr>\n  </tbody>\n</table>'

Rendered

rendered filled table

You can use different arguments to the .to_html() method to omit major table features like the index and do the rest in CSS

ti7
  • 16,375
  • 6
  • 40
  • 68
  • Thank you so much for this! What would be the correct syntax if there were rows in the JSON object? How should `src_table` look like if I were to add one row under each column for example? – Adam Sep 21 '21 at 12:24
  • @Adam: What does adding a row under each column even mean? – martineau Sep 21 '21 at 12:40
  • @martineau sorry, I just meant adding new rows (similar to the example in this answer) – Adam Sep 21 '21 at 12:41
  • @ti7 for some reason, my outputted table has a blank column between each of the filled columns. Any idea why that may be the case? – Adam Sep 23 '21 at 08:36
  • @Adam .. hmm, that may make a good second question! .. but could it just be the styling? I'd expect the initial input to be exactly a dictionary of lists, where each key is the column name and each list is the collection of data .. if this is not the case, you can massage it to be so (`filter(None, iterable)` may work to remove empty values) .. you can also use `.T` to get a transposed view (fold diagonally) if your data is in the "wrong" orientation for you https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html – ti7 Sep 23 '21 at 14:57
  • Thank you! Out of curiosity, how would I massage the dataset using filter in your example? My data set should be in the way that you’ve specified it in any case. If this doesn’t work, I’ll create another question for it. – Adam Sep 23 '21 at 16:06
  • @Adam literally `filter(None, iterable)` will throw out Falsey members of the source iterable .. however, when I actually tried it, it doesn't seem to matter in the way I'd posed because the DataFrame constructor won't actually create one with mismatched column lengths so something similar is _necessary_ to avoid an Exception if you have empty columns ie. `pd.DataFrame(filter(None, {"foo": [], "bar": [1,2,3]}))` .. this can also just as easily be done in some loop that calls `del` or creates a new dict-like – ti7 Sep 23 '21 at 16:14
  • Thanks so much! I’ll give that a try – Adam Sep 24 '21 at 08:03