本篇旨在測試 Streamlit 輸出 JSON 資料的方法. JSON 源自 Javascript 物件, 因其輕量級的資料表示格式受到跨平台與跨語言支持, 已取代 XML 成為網路中最受歡迎與普遍接受的前後端資料交換格式, 其副檔名為 .json.
本系列之前的文章參考 :
JSON 支援兩種資料格式 :
- 物件 :
以大括號 {} 包住的鍵值對 (key-value pairs), 鍵必須是字串, 值可以是數值, 字串, 布林值 (true/false), 空值 (null), 陣列, 或其他物件. 不論鍵或值的字串必須用雙引號括起來, 不可使用單引號. - 陣列 :
以 [] 括起來的數值, 字串, 布林值 (true/false), 空值 (null), 陣列, 或其他物件.
JSON 的物件格式類似 Python 的字典 (但布林值與空值表示法不同), 陣列格式則相當於 Python 的串列. 最常用的是物件格式, Python 的內建模組 json 提供字典與 JSON 字串之間互轉的函式 :
- json.loads() : 傳入 JSON 字串, 傳回 Python 字典
- json.dumps() : 傳入 Python 字典, 傳回 JSON 字串
參考 :
例如 :
>>> import json
>>> json_str='{"姓名": "金智媛", "性別": "女", "年齡": 32, "身高": 172.5, "已婚": false, "宗教": null}'
>>> obj=json.loads(json_str)
>>> type(obj)
<class 'dict'>
>>> obj
{'姓名': '金智媛', '性別': '女', '年齡': 32, '身高': 172.5, '已婚': False, '宗教': None}
可見 loads() 會將 Javascript 的 true/false 轉成 Python 的 True/False; 將 Javascript 的 null 轉成 Python 的 None.
將此 obj 字典傳給 json.dumps() 則會轉回 JSON 字串 :
>>> json.dumps(obj)
'{"\\u59d3\\u540d": "\\u91d1\\u667a\\u5a9b", "\\u6027\\u5225": "\\u5973", "\\u5e74\\u9f61": 32, "\\u8eab\\u9ad8": 172.5, "\\u5df2\\u5a5a": false, "\\u5b97\\u6559": null}'
可見非 ASCII 字元都被轉成 Unicode 表示了, 這是因為 json.dumps() 為了確保跨平台兼容性, 預設會把中文轉成 Unicode 的跳脫序列 (\uXXXX), 如果要顯示為中文就不要跳脫, 可傳入 ensure_ascii=False 參數值 (預設 True) 來設定 :
>>> json.dumps(obj, ensure_ascii=False)
'{"姓名": "金智媛", "性別": "女", "年齡": 32, "身高": 172.5, "已婚": false, "宗教": null}'
注意, JSON 要求所有字串 (key 和 value) 都必須用雙引號, 用單引號是不合語法的, 呼叫 json.loads() 時會拋出例外, 例如我們將上面的 JSON 字串改成鍵值都用單引號 :
>>> json_str="{'姓名': '金智媛', '性別': '女', '年齡': 32, '身高': 172.5, '已婚': false, '宗教': null}"
>>> obj=json.loads(json_str)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\tony1\AppData\Local\Programs\Thonny\lib\json\__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "C:\Users\tony1\AppData\Local\Programs\Thonny\lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\tony1\AppData\Local\Programs\Thonny\lib\json\decoder.py", line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
可見用單引號會出現 JSONDecodeError 例外.
Streamlit 提供了 json() 函式來顯示 JSON 資料 :
st.json(body, expanded=True)
參數 body 為要顯示的 JSON 內容 (必要), 可以是 dict, list, 或合法的 JSON 字串; expanded 參數用來設定是否要展開 JSON 樹狀結構 (預設為展開), 例如顯示上面的 json_str 字串 :
測試 1 : 顯示 JSON 字串與 Python 字典 [看原始碼]
# st-json-test-1.py
import json
import streamlit as st
st.subheader("顯示 JSON 字串")
json_str='{"姓名": "金智媛", "性別": "女", "年齡": 32, "身高": 172.5, "已婚": false, "宗教": null}'
st.json(json_str)
obj=json.loads(json_str)
st.subheader("顯示 Python 字典")
st.json(obj, expanded=False)
此例呼叫兩次 json() 函式, 第一次是顯示 JSON 字串; 第二次是顯示用 json.loads() 轉成的 Python 字典 (設為布展開), 執行結果如下 :
可見 Python 字典因為傳入 expanded=False 是收合的, 點左方的小三角按鈕可展開, 滑鼠移到每一個鍵旁邊會出現一個複製按鈕, 可將該鍵的值甚至整個 JSON 資料複製到剪貼簿 :
可見不論是 JSON 字串還是用 json.loads() 轉換成 Python 字典, st.json() 輸出的結果都是一樣的 (Python 字典的 True/False 與 None 會自動轉換為 true/false 與 NULL).
下面範例是用 st.json() 顯示陣列形式的 JSON 資料 (用 Python 串列) :
測試 2 : 顯示 Python 串列 [看原始碼]
# st-json-test-2.py
import json
import streamlit as st
st.subheader('顯示 Python 串列')
data=['台積電', '中碳', '台泥', '玉山金']
st.json(data)
結果如下 :
可見每一個元素前面都會顯示其索引.
除了 st.json() 外, 當然也可以用超級函式 write() 來輸出 JSON 資料, 例如 :
測試 3 : 呼叫 write() 顯示 JSON 資料 [看原始碼]
# st-json-test-3.py
import json
import streamlit as st
st.subheader("顯示 JSON 字串")
json_str='{"姓名": "金智媛", "性別": "女", "年齡": 32, "身高": 172.5, "已婚": false, "宗教": null}'
st.write(json_str)
obj=json.loads(json_str)
st.subheader("顯示 Python 字典")
st.write(obj, expanded=False)
st.subheader('顯示 Python 串列')
data=['台積電', '中碳', '台泥', '玉山金']
st.write(data)
結果如下 :
可見 st.write() 只能於傳入 Python 字典時像 st.json() 那樣顯示 JSON 樹狀結構, 如果傳入 JSON 字串它就直接輸出字串, 所以 JSON 字串必須傳給 st.json() 顯示為宜.




沒有留言 :
張貼留言