本文輸出JSON搜索和JSON轉換相關的內容,是對前兩篇文章的補充,
JSON搜索
在特定的開發場景中,如果服務器端回傳的JSON資料例外復雜(可能超過上萬行),那么必然就有對JSON檔案進行搜索的需求,在對JSON檔案進行搜索的時候,建議使用專業的JSON搜索類別庫和工具來實作,這可以極大的簡化JSON檔案搜索的作業并降低作業難度,
JSON搜索的具體適用場景:對于某次API呼叫,我們只需要其中的部分資料,這種情況我們就可以根據某個標準來對回傳的JSON內容進行搜索和過濾,
本文將會先后介紹多款處理JSON搜索的類別庫(工具),包括但不限于JSONPath、JSON Pointer、jq等,在對各種方案進行介紹的時候將會從方案的優缺點、具體的使用方式等角度切入,開發中可以根據實際的開發場景和各工具自身的特點來進行選擇,
工具001 → jq
jq 是一個提供了命令列界面的JSON搜索工具,
功能 可使用自身特定的查詢語法來過濾JSON和截取陣列,類似于JSON中的sed,
生態 除命令列外,擁有優秀的基于Web的jq測驗器,甚至Node社區還以npm模塊形式發布了教程,
優勢
- 提供豐富的搜索和過濾功能,
- 大多數編程語言都對jq提供良好的支持,
- jq相關檔案質量較高,且擁有友好的互動式教程,
- 擁有優秀的在線測驗工具,能夠對查詢提供快速反饋,
- 在命令列中能夠很好的與cURL以及管道操作等協同作業,
- 使用C語言撰寫的,沒有運行時依賴,可運行在Linux,OS X和Windows等平臺,
資料 官網 、Github倉庫 、 Ubuntu-jq手冊 、 Hyperpolyglot JSON工具、Jackson類別庫、Ruby-jq gem
語法
======基本語法======
. 輸出所有的檔案內容,
| 管道符,傳遞資料流,
.key 輸出指定key對應的部分檔案,
.[ ] 輸出陣列中指定索引對應的元素,
======查詢語法示例========
.person[0] 獲取JSON檔案person陣列中的第一個元素,
.person[-1] 獲取JSON檔案person陣列中的最后一個元素,
.person[0:3] 獲取JSON檔案person陣列中的前面三個元素,
.person[] | select (.age>20 ) 獲取JSON檔案中滿足要求(age > 20)的所有資料,
安裝
- OSX系統 建議使用Homebrew來安裝,具體命令為:
$ brew install jq - windows系統 建議使用Chocolatey NuGet來安裝,具體命令為:
$ chocolatey install jq - 當然也可以通過
git clone倉庫原始碼來進行安裝,具體細節以及其它系統處理請參考Download jq
這里給出OSX系統中通過命令列安裝jq的具體細節和示例,
wendingding$ brew install jq
Updating Homebrew...
==> Installing dependencies for jq: oniguruma
==> Installing jq dependency: oniguruma
==> Downloading https://homebrew.bintray.com/bottles/oniguruma-6.8.2.high_sierra
######################################################################## 100.0%
==> Pouring oniguruma-6.8.2.high_sierra.bottle.tar.gz
?? /usr/local/Cellar/oniguruma/6.8.2: 17 files, 1.2MB
==> Installing jq
==> Downloading https://homebrew.bintray.com/bottles/jq-1.5_3.high_sierra.bottle
######################################################################## 100.0%
==> Pouring jq-1.5_3.high_sierra.bottle.tar.gz
?? /usr/local/Cellar/jq/1.5_3: 19 files, 946.6KB
wendingding$ jq --version
jq-1.5
在安裝jq的時候,如果命令列報Error: Failure while executing: git config --local --replace-all homebrew.private true錯誤,可以嘗試先執行`$ xcode-select --install `命令然后重新安裝,在安裝的時候如果總是卡在Updating Homebrew...可以`control + C`停止更新,
工具(jq-tutorial)
jq-tutorial是node社區以npm模塊的形式發布的jq教程,是學習jq使用的一個比較好用的工具,這里簡單列出該模塊的安裝和使用示例,并對命令進行簡單的說明,
wendingding$ npm search jq-tutorial
NAME | DESCRIPTION | AUTHOR | DATE
jq-tutorial | Exercises for… | =rjz | 2016-09-29
wendingding$ npm install -g jq-tutorial
npm WARN notice [SECURITY] lodash has the following vulnerability: 1 low.
Go here for more details: https://nodesecurity.io/advisories?search=lodash version=2.4.2
-Run `npm i npm@latest -g` to upgrade npm version, and then `npm audit` to get more info.
/usr/local/bin/jq-tutorial -> /usr/local/lib/node_modules/jq-tutorial/bin/jq-tutorial
+ [email protected]
added 4 packages in 20.012s
wendingding$ jq-tutorial
Run jq-tutorial with one of the following:
* pick
* objects
* mapping
* filtering
* output
* reduce
wendingding$ jq-tutorial pick
Pick
========================================
### Pick fields from an object
`jq` retrieves named properties from objects by using `.` syntax:
$ echo '{"foo": { "bar": "a value" }}' | jq .foo
Nested values are accessible as well:
$ echo '{"foo": { "bar": "a value" }}' | jq .foo.bar
### Pick elements from an array:
Elements in an array may be extracted by index:
$ echo '["snap","crackle","pop"]' | jq .[1]
More than one index? No problem!
$ echo '["snap","crackle","pop"]' | jq .[1, 2]
We can even extract *all* elements at once by omitting the indices:
$ echo '["snap","crackle","pop"]' | jq .[]
type "data?" to see dataset or "help?" for more options
--------------------------------
Given: 'product' (type "data?" to view)
Challenge: Select the entire item (hint: don't overthink this!):
>
工具(jqPlay)
jqPlay是一個基于web的jq在線測驗游樂場,它提供了對JSON資料進行jq查詢的基本功能,而且提供了簡單的jq查詢語法示例,能夠對查詢進行快速反饋,

基本用法演示
這里我先提供一個稍復雜的JSON資料,資料保存在/JSON-Demo/data.json路徑(您可以點擊此鏈接獲取該資料),為了演示方便,這里我將會把該檔案的資料部署為RESTful API,從而創建一個模擬的API服務,在具體的處理中,將使用到名為json-server的Node模塊,下面列出具體的細節,
wendingding$ pwd
/Users/文頂頂/Desktop/JSON-Demo
wendingding$ npm install -g json-server
/usr/local/bin/json-server -> /usr/local/lib/node_modules/json-server/bin/index.js
+ [email protected]
added 223 packages in 23.03s
wendingding$ json-server -p 5000 ./data.json
\{^_^}/ hi!
Loading ./data.json
Done
Resources
http://localhost:5000/person
Home
http://localhost:5000
Type s + enter at any time to create a snapshot of the database
GET /person 304 16.355 ms - -
執行$json-server -p 5000 ./data.json命令之后,我們可以在瀏覽器中通過http://localhost:5000/person地址來訪問JSON檔案中的資料,下面是顯示結果,

備注:如果經常需要通過瀏覽器訪問和顯示JSON資料,建議安裝相應的JSON擴展插件,我電腦Chrome安裝的是JSON-handle,同型別的還有JSONView,
下面列出jq命令列工具的使用示例以及主要命令列的解讀說明,
wendingding$ curl http://localhost:5000/person | jq '.'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 169k 0 --:--:-- --:--:-- --:--:-- 255k
[
{
"age": 18,
"name": "mitaoer",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂",
"繪畫",
"IT"
],
"car": {
"type": "英菲尼迪",
"number": "京A 000001",
"price": 200012.66
}
},
{
"age": 28,
"name": "wendingding",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂"
],
"car": {
"type": "奧迪",
"number": "京A 000002",
"price": 200000.66
}
},
{
"age": 23,
"name": "xiaxiaoxia",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"IT"
],
"car": null
},
{
"age": 24,
"name": "LiuY",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂",
"繪畫",
"IT",
"閱讀",
"健身"
],
"car": {
"type": "ATS",
"number": "京A 000003",
"price": 888888.66
}
}
]
wendingding$ curl http://localhost:5000/person | jq '.[1]'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 140k 0 --:--:-- --:--:-- --:--:-- 255k
{
"age": 28,
"name": "wendingding",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂"
],
"car": {
"type": "奧迪",
"number": "京A 000002",
"price": 200000.66
}
}
wendingding$ curl http://localhost:5000/person | jq '.[1].name'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 171k 0 --:--:-- --:--:-- --:--:-- 255k
"wendingding"
wendingding$ curl http://localhost:5000/person | jq '.[1].email'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 106k 0 --:--:-- --:--:-- --:--:-- 127k
"[email protected]"
wendingding$ curl http://localhost:5000/person | jq '.[1] | {name,age}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 161k 0 --:--:-- --:--:-- --:--:-- 204k
{
"name": "wendingding",
"age": 28
}
wendingding$ curl http://localhost:5000/person | jq '.[1] | {newName:.name,newAge:.age}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 153k 0 --:--:-- --:--:-- --:--:-- 204k
{
"newName": "wendingding",
"newAge": 28
}
wendingding$ curl http://localhost:5000/person | jq '.[] | select (.age >=24)'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 167k 0 --:--:-- --:--:-- --:--:-- 255k
{
"age": 28,
"name": "wendingding",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂"
],
"car": {
"type": "奧迪",
"number": "京A 000002",
"price": 200000.66
}
}
{
"age": 24,
"name": "LiuY",
"hasBrother": true,
"email": "[email protected]",
"interest": [
"文學",
"音樂",
"繪畫",
"IT",
"閱讀",
"健身"
],
"car": {
"type": "ATS",
"number": "京A 000003",
"price": 888888.66
}
}
wendingding$ curl http://localhost:5000/person | jq '.[1,3] | {name,email}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 162k 0 --:--:-- --:--:-- --:--:-- 255k
{
"name": "wendingding",
"email": "[email protected]"
}
{
"name": "LiuY",
"email": "[email protected]"
}
wendingding$ curl http://localhost:5000/person | jq '.[1,3] | [{name,email}]'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 165k 0 --:--:-- --:--:-- --:--:-- 255k
[
{
"name": "wendingding",
"email": "[email protected]"
}
]
[
{
"name": "LiuY",
"email": "[email protected]"
}
]
wendingding$ touch test.json
wendingding$ curl http://localhost:5000/person | jq '.[1,3] | [{name,email}]' > test.json
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1047 100 1047 0 0 143k 0 --:--:-- --:--:-- --:--:-- 204k
wendingding$ cat test.json
[
{
"name": "wendingding",
"email": "[email protected]"
}
]
[
{
"name": "LiuY",
"email": "[email protected]"
}
]
主要命令說明[為方便閱讀,命令列中的xxx均代表的是http://localhost:5000/person路徑]
$ curl xxx | jq '.' 獲取API回傳的所有JSON資料,
$ curl xxx | jq '.[1]' 獲取JSON檔案中person陣列的第2個元素內容,
$ curl xxx | jq '.[1].name' 獲取JSON檔案中person陣列的第2個元素(物件)中的name屬性值,
$ curl xxx | jq '.[1] | {name,age}' 獲取陣列第2個元素(物件)的name和age鍵值對組成新物件,
$ curl xxx | jq '.[1,3] | {name,email}' 獲取陣列第2和第4個元素中的name和email值組成物件,
$ curl xxx | jq '.[] | select (.age >=24)' 獲取JSON檔案中所有age屬性值>=24的物件元素集合,
補充 如果需要在Node中使用jq,那么可以安裝并使用require匯入node-jq模塊,
工具002 → JSONPath
定位 是一款可用于對JSON檔案進行搜索和資料提取操作類別庫,
歷史 由Stefan Goessner于2007年開發,最開始的版本使用JavaScript實作,
功能 能夠對JSON檔案進行搜索和資料提取,它的查詢語法基于XPath實作,
生態 JSONPath沒有提供命令列操作實作,但提供了優秀的在線測驗工具和Node模塊,
優勢
- 具有豐富的查詢語法,
- 查詢陳述句可以回傳檔案中的多個元素,
- 大多數的主流平臺都對JSONPath提供支持,
- 擁有很高的社區使用率,優秀的在線測驗工具對開發者更友好,
資料 jsonpath Node模塊 、在線測驗網站 、Github倉庫、Stefan Goessner主頁
| 語法 | 描述 |
|---|---|
$ |
根節點 |
@ |
當前節點的篩選器屬性處理 |
* |
通配符,匹配任何屬性名稱 |
.. |
通配符,匹配任意層次的節點 |
[] |
迭代器標示,同陣列索引 |
[,] |
迭代器標示,迭代器多選 |
[start:end] |
陣列切片運算子 |
[?(<expression>)] |
過濾運算式,求值必須為布林值 |
查詢語法示例
//備注:參考的JSON資料為前文使用的data.json檔案
$ 獲取整個JSON檔案的內容
$.person 獲取JSON檔案中person陣列的內容
$.person.length 獲取JSON檔案中person陣列的長度(元素個數)
$.person[0] 獲取JSON檔案中person陣列第一個元素的內容
$.person[:1] 獲取JSON檔案中person陣列第一個元素的內容
$.person[-1:] 獲取JSON檔案中person陣列最后一個元素的內容
$.person[(@.length-1)] 獲取JSON檔案中person陣列最后一個元素的內容
$.person[:2] 獲取JSON檔案中person陣列前兩個元素的內容
$.person[0,3] 獲取JSON檔案中person陣列第1和4第個元素的內容
$.person[0::2] 獲取JSON檔案中person陣列指定元素的內容(隔一個元素抽取)
$.person[:2].name 獲取JSON檔案中person陣列前兩個元素中的name值
$..name 獲取JSON檔案中所有的name子元素內容
$.person[?(@.age >23)] 獲取JSON檔案中age值大于23的所有元素
$.person[?(@.age >23)].age 獲取JSON檔案中age值大于23的所有元素中的age值資訊
$.person[?(@.age >20 && @.interest.length == 2)].name 滿足多個條件的篩選
工具(jsonpath在線測驗網站)
jsonpath提供了對應的在線測驗網站,給指定JSON檔案輸入對應的jsonpath查詢陳述句能夠快速看到最終效果,使用該測驗工具來可以"重量級的"復雜JSON資料進行快速的篩選,輸入查詢陳述句后馬上就能夠在右側看到查詢后的結果,如果開發者原本不了解查詢語法,那也可以通過該工具來快速的學習,下面給出簡單的圖示,

工具(node模塊jsonpath)
JSONPath本身沒有命令列工具,除了上面介紹的在線測驗網站之外,我們還能在代碼中使用node社區發布的jsonpath模塊實作JSON的搜索任務,下面給出一個簡單的單元測驗示例(列出原始碼和執行情況),
001 先列出單元測驗相關的代碼
//jsonpath-test.js檔案內容
var unirest = require("unirest");
var jsonPath = require("jsonpath");
var expect = require("chai").expect;
describe("wendingding-test",function(){
var request ;
beforeEach(function(){
request = unirest.get("http://localhost:5000/person")
.header("Accept","application/json");
})
it("return 200 狀態碼",function(done){
request.end(function(response){
expect(response.statusCode).to.eql(200);
expect(response.headers["content-type"])
.to.eql("application/json; charset=utf-8");
done();
})
})
it("return 所有的JOSN資料",function(done){
request.end(function(response){
expect(response.body.length).to.eql(4);
done();
})
})
it("return 所有的JOSN資料中第一個元素 -- $[1]",function(done){
request.end(function(response){
var resultData = https://www.cnblogs.com/wendingding/p/jsonPath.query(response.body,"$[1]");
expect(resultData[0].name).to.eql("wendingding");
done();
})
})
it("return 所有的JOSN資料中最后一個元素[1] -- $[-1:]",function(done){
request.end(function(response){
var resultData = https://www.cnblogs.com/wendingding/p/jsonPath.query(response.body,"$[-1:]");
expect(resultData[0].email).to.eql("[email protected]");
done();
})
})
it("return 所有的JOSN資料中最后一個元素[2] -- $[(@.length-1)]",function(done){
request.end(function(response){
var resultData = https://www.cnblogs.com/wendingding/p/jsonPath.query(response.body,"$[(@.length-1)]");
expect(resultData[0].email).to.eql("[email protected]");
done();
})
})
it("return 所有的JOSN資料中滿足條件元素 -- $[?(@.age >= 23)]",function(done){
request.end(function(response){
var data = https://www.cnblogs.com/wendingding/p/response.body;
var resultData = jsonPath.query(data,"$[?(@.age >= 23)]");
//console.log(resultData)
expect(resultData.length).to.eql(3);
for(var i = 0 ;i<resultData.length;i++)
{
expect(resultData[i].age).to.be.at.least(23);
}
done();
})
})
})
002 列出代碼的具體執行細節
wendingding$ pwd
/Users/文頂頂/Desktop/jsonPath-demo
wendingding$ npm test
> [email protected] test /Users/文頂頂/Desktop/jsonPath-demo
> mocha
wendingding-test
? return 200 狀態碼
? return 所有的JOSN資料
? return 所有的JOSN資料中第一個元素 -- $[1]
? return 所有的JOSN資料中最后一個元素[1] -- $[-1:]
? return 所有的JOSN資料中最后一個元素[2] -- $[(@.length-1)]
? return 所有的JOSN資料中滿足條件元素 -- $[?(@.age >= 23)]
6 passing (92ms)
003 代碼說明
〇 示例代碼中使用了Mocha、Unirest測驗框架,jsonpath查詢模塊以及Chai模塊中的斷言結構,
① 示例代碼中的每一個it就代表著一個測驗用例,
② 示例代碼中我們在Mocha的beforeEach()方法中對請求資訊進行了配置,
③ 示例代碼中在describe陳述句定義的范圍內,每次執行測驗用例之前都會先運行一次beforeEach方法,
004 執行備注
這里簡單說明上面代碼的執行環境和處理程序,
[1] 在電腦中指定的路徑創建檔案夾,并通過命令列進入到該路徑,
$ mkdir JSON-TEST
$ cd JSON-TEST/
$ pwd
/Users/文頂頂/Desktop/JSON-TEST
[2] 初始化并安裝必要的node模塊,
$ npm init //默認回車即可
$ npm install -g mocha
$ npm install --save-dev mocha
$ npm install --save-dev unirest
$ npm install -save-dev jsonpath
$ npm install --save-dev chai
[3] 修改package.json檔案中的scripts項為"test": "mocha",
wendingding$ cat package.json
{
"name": "json-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "^4.2.0",
"jsonpath": "^1.0.0",
"mocha": "^5.2.0",
"unirest": "^0.5.1"
}
}
[4] 在當前目錄下創建test檔案夾,并在該檔案夾中創建測驗檔案(此處命名為json-test.js),
$ mkdir test
$ cd test/
$ touch json-test.js
[5] 編輯json-test.js檔案的內容(前文已經給出),列出檔案目錄,
.
├── node_modules
│ ├── JSONSelect
│ ...省略
│ ├── chai
│ ├── jsonpath
│ ├── mocha
│ ├── unirest
│ └── xtend
├── package-lock.json
├── package.json
└── test
└── json-test.js
[6] 執行測驗,
$ npm test
工具003 → JSON Pointer
JSON Pointer本身是一項用于獲取JSON檔案中特定值的標準,JSON Pointer設計的主要目標在于支持JSON Schema標準中的$ref(請參考JSON進階一文),
目前,大多數的主流平臺(包括Node\Ruby on Rails\Ptyhon\Java等)都已經包含JSON Pointer相關的類別庫,Java,Jackson已支持JSON Pointer查詢語法,javaEE 8將提供原生支持;Node中則可以在社區中找到并使用json-pointer模塊來對JSON檔案進行處理,
| 語法 | 描述 |
|---|---|
/data |
獲取JSON檔案中某個key對應的所有資料 |
/data/index |
獲取指定索引對應的資料 |
/data/index/key |
獲取指定索引對應的資料并通過key來取值 |
JSON Pointer的查詢語法簡潔高效,其作業機制是以/來表示路徑分隔,以索引|下標來獲取指定的內容,索引總是從0開始,下面給出簡短的查詢語法示例:
//備注:參考的JSON資料為前文使用的data.json檔案
/person 獲取JSON檔案中person的內容
/person/0 獲取JSON檔案中person陣列的第一項內容
/person/0/name 獲取JSON檔案中person陣列的第一項內容中的name值
**注意** JSON Pointer標準中,查詢操作的結果總只包含資料值而不會包含相關的鍵名,
這里將使用node社區的json-pointer模塊簡單演示node平臺中對JSON檔案的處理,下面列出核心單元測驗代碼(在測驗的時候需要先安裝對應的模塊),
var expect = require("chai").expect;
var pointer = require("json-pointer");
var unirest = require("unirest");
describe("wendingding-test",function(){
var request ;
beforeEach(function(){
request = unirest.get("http://localhost:5000/person")
.header("Accept","application/json");
})
it("return 200 狀態碼",function(done){
request.end(function(response){
expect(response.statusCode).to.eql(200);
expect(response.headers["content-type"])
.to.eql("application/json; charset=utf-8");
done();
})
})
it("return 所有的JOSN資料",function(done){
request.end(function(response){
expect(response.body.length).to.eql(4);
done();
})
})
it("return Person陣列中的第一個元素 /person/0",function(done){
request.end(function(response){
var resultData = https://www.cnblogs.com/wendingding/p/pointer.get(response.body,"/0");
console.log("\n",resultData,"\n");
expect(resultData.name).to.eql("mitaoer");
done();
})
})
it("return Person陣列中的第三個元素中interest的值 /person/2/interest",function(done){
request.end(function(response){
var resultData = https://www.cnblogs.com/wendingding/p/pointer.get(response.body,"/2/interest");
console.log("\t",resultData);
expect(resultData.length).to.eql(2);
done();
})
})
})
簡單列出執行情況:
wendingding$ npm test
> [email protected] test /Users/文頂頂/Desktop/JSON-Pointer
> mocha
wendingding-test
? return 200 狀態碼
? return 所有的JOSN資料
{ age: 18,
name: 'mitaoer',
hasBrother: true,
email: '[email protected]',
interest: [ '文學', '音樂', '繪畫', 'IT' ],
car: { type: '英菲尼迪', number: '京A 000001', price: 200012.66 }
}
? return Person陣列中的第一個元素 /person/0
[ '文學', 'IT' ]
? return Person陣列中的第三個元素中interest的值 /person/2/interest
4 passing (66ms)
JSON轉換
JSON → HTML結構(渲染)
將JSON資料轉換(處理)為HTML的操作我們應該都很熟悉,在前端開發和移動端開發領域中,這一部分的操作通常和網路請求緊密聯系,業務流程基本都是先發請求獲取服務器端回傳的(JSON)資料,然后通過序列化的方法來對資料進行決議,也就是反序列化處理(通常是將JSON資料轉換為編程語言中對應的資料結構比如陣列或者是物件),最終再根據得到的資料來更新UI,
現在前端開發中這都屬于基本操作,甚至像Vue這樣類似的框架中資料系結已經是其最最基礎的一部分了,雖然如此,為了文章的完整性,這里還是會簡單介紹Mustache和Handlebars兩個類別庫在JSON轉換中的運用,
Mustache
簡介 Mustache使用宣告式模板來轉換資料格,
資料 Mustache、Mustache Github、Mustache 5說明檔案
優勢 使用模板可以從代碼中抽取具體的資料資訊,并將資料保存在外部的檔案中,實作關注點分離,
接下來我將通過一個簡短的示例來說明Mustache的語法以及其使用方式,您可以點擊該鏈接獲取完整的專案內容,為了對介紹Mustache的使用,這里我列出專案中的部分內容并做簡要說明,
001 列出模板核心內容
//備注:../Tem-TEST/src/index.mustache檔案的核心內容
<div id="app">
<table id="tb">
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
<th>interest</th>
<th>car-type</th>
<th>car-number</th>
</tr>
{{#person}}
<tr>
<td>{{name}}</td>
<td>{{age}}</td>
<td>{{email}}</td>
<td>{{interest.1}}</td>
{{#car}}
<td>{{type}}</td>
<td>{{number}}</td>
{{/car}}
</tr>
{{/person}}
</table>
</div>
002 列出單元測驗代碼
//備注:../Tem-TEST/test/mustache-test.js檔案內容
var fs = require("fs");
var expect = require("chai").expect;
var jsonfile = require("jsonfile");
var mustache = require("mustache");
describe("wendingding-mustache-test",function(){
//檔案的目錄結構:json檔案路徑 + 模板檔案路徑 + 目標檔案路徑
var jsonFileFullPath = __dirname + "/../src/data.json";
var templateFileFullPath = __dirname + "/../src/index.mustache";
var targetFileFunllPath = __dirname + "/../src/index.html";
it("JSON -> HTML",function(done){
jsonfile.readFile(jsonFileFullPath,function(readJsonFileError,jsonData){
if(!readJsonFileError)
{
fs.readFile(templateFileFullPath,"utf8",function(readTemplateFileError,templateData){
if(!readTemplateFileError)
{
var template = templateData.toString();
var html = mustache.render(template,jsonData);
fs.writeFile(targetFileFunllPath, html, function(errorStatus) {
if (!errorStatus) {
console.log("轉換成功并保存為HTML檔案!");
done();
}else
{
done(errorStatus);
}
});
}else
{
done(readTemplateFileError)
}
})
}else
{
done(readJsonFileError)
}
})
})
})
通過$ npm test執行單元測驗代碼,將會執行JSON陣列到HTML的轉換,處理完畢后結果保存到index.html檔案中,下面貼出該頁面的效果圖,

Mustache模板作業機制
? 模板基于HTML, Mustache使用JSON資料來決議標簽,
? 模板中的標簽可以表示單個欄位,使用雙大括號的形式來包裹,
? 模板中的區塊都需要由開始標簽和結尾標簽組成,例如上例中的person,
? 模板中的區塊對應JSON資料中的陣列或者是物件,例如上例中的person和car,
? 模板中的區塊可以為內部的標簽定義背景關系,比如car區塊內部的type和number,
Mustache工具(命令列 && 在線網站)
Mustache除上面演示的使用方式之外,還能直接在命令列中使用,下面給出簡短的使用示例,
(1) 全域安裝Mustache模塊,
$ npm install -g mustache
(2) 執行mustache命令轉換,
$ mustache /Users/文頂頂/Desktop/Tem-TEST/src/data.json /Users/文頂頂/Desktop/Tem-TEST/src/index.mustache > target.html
$ open target.html

這里再推薦一款好用的在線模板編輯器Architect,使用該工具可以有效的簡化測驗和開發模板的作業,當修改模板的時候,可以實時的看到渲染的結果,該網站支持多款主流模板引擎(包括doT.js、Dustjs、EJS、Handlebars.js、Hogan.js、Jade、Mustache、Nunjucks和Underscore.js等)的編輯和渲染,可以有效的加速開發和除錯作業,
Handlebars
簡介 Handlebars是Mustache的擴展,使用hash或物件來渲染模板中的標簽,
資料 Handlebars、Handlebars Github、Architect、在線測驗網站、Handlebars的Node模塊
說明 Handlebars與Mustache高度兼容,相對而言Handlebars自身增加了一些特性來增強轉換操作,它們的差異主要在于Handlebars提供了if和unless等行內的輔助陳述句且允許開發者通過注冊自定義輔助語意的方式來進行擴展,功能更加強大,
優勢
- 模板語言豐富,能滿足大多數的轉換需求,
- 擁有優秀的在線編輯和測驗工具用起來更加方便,
- 采用宣告式,但也支持在自定義輔助指令中撰寫邏輯代碼,
- 因為擁有內置的條件邏輯,所以在渲染的時候幾乎可以不用撰寫額外的處理代碼,
- 跨平臺的支持度很好,支持
JavaScript、Node.js、Java和Ruby on Rails等平臺,
這里將簡單介紹Handlebars在Node中的使用,并提供node和命令列兩種執行示例供參考,更多的細節請自行參考其官網檔案,
001 列出模板檔案的核心代碼
//備注(1):/Users/文頂頂/Desktop/Handlebars-Test/index.hbs檔案的核心內容
//備注(2):轉換程序中使用的json資料為前文中的data.json檔案
<div id="app">
<table id="tb">
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
<th>car-type</th>
<th>car-Other</th>
</tr>
{{#each person}}
{{#if car}}
<tr>
<td>{{name}}</td>
<td>{{age}}</td>
<td>{{email}}</td>
<td>{{car.type}}</td>
<td>號碼:{{car.number}} | 價格:{{car.price}}</td>
</tr>
{{/if}}
{{/each}}
</table>
</div>
002 列出命令列執行的細節
(1) 先通過命令列全域安裝hb-interpolate模塊
$ npm install -g hb-interpolate
(2) 執行渲染命令,
$ hb-interpolate -j /Users/文頂頂/Desktop/Handlebars-Test/data.json -t /Users/文頂頂/Desktop/Handlebars-Test/index.hbs > target.html
說明 上面的命令列中-j表示后面跟的是json檔案,-t表示后面跟的是模板檔案,轉換后的結果被輸出并保存到target.html檔案中,在模板檔案中的#each表示遍歷陣列,#if是邏輯控制指令,在渲染的時候過濾了car為null的資料情況,瀏覽器打開target.html檔案可以看到下面的顯示結果,

003 Handlebars在Node中的使用
//備注:handlebars-test.js檔案的內容
//001 匯入node模板
var fs = require("fs");
var jsonfile = require("jsonfile");
var handlebars = require("handlebars");
//002 處理檔案路徑
var jsonFullPath = __dirname + "/data.json";
var templateFullPath = __dirname + "/index.hbs";
var outPutFullPath = __dirname + "/output.html";
//003 讀取JSON檔案的內容
jsonfile.readFile(jsonFullPath,function(readJsonError,jsonData){
if(!readJsonError)
{
//004 讀取模板檔案的內容
fs.readFile(templateFullPath,"utf8",function(readTemplateError,templateData){
if(!readTemplateError)
{
//005 JSON資料 + 模板 = > 渲染
var template = handlebars.compile(templateData);
var html = template(jsonData);
//006 把渲染后的結果保存到指定檔案中
fs.writeFile(outPutFullPath, html, function(errorStatus) {
if(! errorStatus)
{
console.log("渲染成功!請打開"+outPutFullPath+"查看結果!");
}
})
}
})
}
})
說明 在指定檔案目錄中(我這里是/Users/文頂頂/Desktop/Handlebars-Test)創建handlebars-test.js檔案,并撰寫上述對應的代碼,通過命令列安裝必要的Node模塊,執行即可得到前文所示的圖片結果,下面給出命令列執行的細節:
(1) 切換到當前目錄
$ cd Handlebars-Test/
$ pwd
/Users/文頂頂/Desktop/Handlebars-Test
(2) 使用npm初始化并安裝必要的Node模塊,
$ npm init
$ npm install --save-dev jsonfile
$ npm install --save-dev handlebars
(3) 執行,
$ node handlebars-test.js
補充 Mustache和Handlebars除用來把JSON轉換為HTML(渲染)之外,還能夠對JSON資料本身的格式進行轉換作業(主要是對JSON資料進行二次處理,譬如刪級訓結構調整等),但Mustache在具體進行格式化的時候因為無法確定當前所處理的元素是否為陣列或物件的最后一個元素,所以可能存在"無謂逗號"的問題,Handlebars可以通過使用#unless 和@last的形式對"無謂逗號"的問題進行規避,具體的細節請參考其官方檔案說明,另外,JSON格式轉換的工具在Node環境中推薦使用Json2Json和jsonapter,也可以參考JSON Patch和JSON-T的實作,這里不再展開,
JSON資料 ←→ XML檔案
最后簡單介紹JSON資料和XML資料之間的相互轉換,雖然這種場景通常可能很少出現(因為開發中常見的場景一般是對JSON或XML資料進行序列化或反序列化處理,JSON和XML兩種資料格式之間直接相互轉換的情況真的很少見),
XML全稱Extensible Markup Language(可擴展標記語言),主要流行于(1998~2008年),同JSON類似,XML也能用于表示和傳輸資料,現在很多大公司的API都提供XML和JSON兩種格式的資料回應,
XML資料和JSON資料的轉換難易程度主要看XML檔案的結構,如果檔案中所有的資料都以XML元素和文本的方式保存那么轉換為JSON資料是比較簡單的,如果XML檔案的元素上存在這大量的屬性節點(早年的時候很多XML的設計人員把資料保存在XML的屬性節點上,這樣有助于減少檔案體積和簡化多平臺之間的轉換作業),那么這種轉換就會比較困難,不過,好在我們可以使用很多現成的工具(譬如:Parker和JsonML以及Badgerfish等)來完成這種具體的轉換作業,
對于上面這些工具的具體使用情況,大家可以自行了解,需要說明的是即便如此,這些工具仍然存在很大的局限性(譬如檔案不全、缺乏跨平臺的支持和完整實作以及有損轉換等等),所以,在實際的使用程序中其實可以考慮先把JSON|XML轉換為當前編程語言中的資料結構形式,然后再轉換成XML|JSON),下面以JavaScript(Node)平臺為例加以簡單說明,
XML檔案 → JSON資料
- 先把XML資料決議為JavaScript中的物件|陣列(
xml2js模塊), - 把JavaScript的物件|陣列序列化為JSON格式的資料(
JSON.stringify方法),
列出核心示例代碼
var xmlFullPath = __dirname + "/data.xml";
fs.readFile(xmlFullPath,"utf8",function(readFileError,xmlData){
var parser = new xml2js.Parser();
parser.parseString(xmlData,function(error,xmlObj){
console.log(JSON.stringify(xmlObj,null,2));
})
})
JSON資料 → XML檔案
- 先將JSON資料決議(反序列化)為JavaScript中的物件|陣列資料(
eval函式或者是JSON.parse方法), - 根據JavaScript資料來生成(marshaling)對應的XML檔案(
xml2js模塊)
這里列出json資料轉換為xml資料的代碼示例,
//001 匯入node模板
var fs = require("fs");
var xml2js = require("xml2js");
var jsonfile = require("jsonfile");
//002 處理檔案路徑
var jsonFullPath = __dirname + "/data.json";
var xmlFullPath = __dirname + "/data.xml";
//003 讀取JSON檔案的內容并決議為JavaScript物件(jsonData)
jsonfile.readFile(jsonFullPath,function(readJsonError,jsonData){
if(!readJsonError)
{
//004 創建并回傳bulider實體物件
var bulider = new xml2js.Builder();
//005 使用bulider物件將jsonData轉換為xml格式的字串
var xml = bulider.buildObject(jsonData);
//006 寫檔案操作(把最終的資料保存到指定的檔案中)
fs.writeFile(xmlFullPath, xml, function(errorStatus) {
if(! errorStatus)
{
console.log("json->XML 轉換成功");
console.log(xml);
}
})
}
})
列出用于轉換的初始json資料,
{
"person": [
{
"age": 18,
"name": "mitaoer",
"hasBrother": true,
"email": "[email protected]",
"car": {
"type": "英菲尼迪",
"number": "京A 000001",
"price": 200012.66
}
},
{
"age": 28,
"name": "wendingding",
"hasBrother": true,
"email": "[email protected]",
"car": {
"type": "奧迪",
"number": "京A 000002",
"price": 200000.66
}
}
]
}
列出最終輸出的xml資料內容,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<age>18</age>
<name>mitaoer</name>
<hasBrother>true</hasBrother>
<email>[email protected]</email>
<car>
<type>英菲尼迪</type>
<number>京A 000001</number>
<price>200012.66</price>
</car>
<age>28</age>
<name>wendingding</name>
<hasBrother>true</hasBrother>
<email>[email protected]</email>
<car>
<type>奧迪</type>
<number>京A 000002</number>
<price>200000.66</price>
</car>
</person>
注意:如果JSON資料中存在陣列這種結構那么使用xml2js模塊的處理其實不甚理想,更新資訊請參考[官方檔案說明](https://www.npmjs.com/package/xml2js),
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/400317.html
標籤:Html/Css
上一篇:從檔案中拆分符號
