JSON::PP - JSON::XS 相容的純 Perl 模組。
use JSON::PP;
# exported functions, they croak on error
# and expect/generate UTF-8
$utf8_encoded_json_text = encode_json $perl_hash_or_arrayref;
$perl_hash_or_arrayref = decode_json $utf8_encoded_json_text;
# OO-interface
$json = JSON::PP->new->ascii->pretty->allow_nonref;
$pretty_printed_json_text = $json->encode( $perl_scalar );
$perl_scalar = $json->decode( $json_text );
# Note that JSON version 2.0 and above will automatically use
# JSON::XS or JSON::PP, so you should be able to just:
use JSON;
JSON::PP 是純 perl JSON 解碼器/編碼器,且(幾乎)相容於 Marc Lehmann 用 C 編寫的更快速的 JSON::XS。當你在沒有安裝 JSON::XS 的情況下使用 JSON 模組時,JSON::PP 會作為備用模組運作。
由於 JSON.pm 的此項備援功能,JSON::PP 嘗試不要比 JSON::XS 更友善於 JavaScript(例如,不跳脫 U+2028 和 U+2029 等額外字元),以便您在使用 JSON.pm 時不會在不知不覺中失去此項 JavaScript 友善性,以及意外或為了速度而安裝 JSON::XS。如果您需要友善於 JavaScript 且符合 RFC7159 的純 Perl 模組,請嘗試 JSON::Tiny,它衍生自 Mojolicious 網路架構,而且比 JSON::PP 更小、更快。
JSON::PP 自 Perl 5.14 以來便已存在於 Perl 核心,主要是供 CPAN 工具鏈模組用於剖析 META.json。
此部分幾乎逐字取自 JSON::XS。encode_json
和 decode_json
預設為匯出。
$json_text = encode_json $perl_scalar
將給定的 Perl 資料結構轉換為 UTF-8 編碼的二進位字串(也就是說,字串只包含八位元組)。發生錯誤時會中斷。
此函數呼叫在功能上等同於
$json_text = JSON::PP->new->utf8->encode($perl_scalar)
只是速度較快。
$perl_scalar = decode_json $json_text
encode_json
的相反動作:預期為 UTF-8(二進位)字串,並嘗試將其剖析為 UTF-8 編碼的 JSON 文字,傳回產生的參照。發生錯誤時會中斷。
此函數呼叫在功能上等同於
$perl_scalar = JSON::PP->new->utf8->decode($json_text)
只是速度較快。
$is_boolean = JSON::PP::is_bool($scalar)
如果傳遞的純量表示 JSON::PP::true 或 JSON::PP::false(兩個分別作用如 1
和 0
的常數,且也用於在 Perl 字串中表示 JSON true
和 false
),則傳回 true。
在 perl 5.36 以上版本,如果給定 perl 的標準布林值(例如比較結果),也會傳回 true。
有關 JSON 值如何對應至 Perl 的詳細資訊,請參閱下方的 對應。
此部分也取自 JSON::XS。
物件導向介面讓您可以在受支援格式的限制下,設定您自己的編碼或解碼樣式。
$json = JSON::PP->new
建立新的 JSON::PP 物件,可用於解/編碼 JSON 字串。以下描述的所有布林旗標預設為已停用(allow_nonref
例外,自版本 4.0
起預設為已啟用)。
旗標的變異器都會傳回 JSON::PP 物件,因此呼叫可以串連
my $json = JSON::PP->new->utf8->space_after->encode({a => [1,2]})
=> {"a": [1, 2]}
$json = $json->ascii([$enable])
$enabled = $json->get_ascii
如果 $enable
為 true(或遺漏),則 encode
方法不會產生超出 0..127
(也就是 ASCII)程式碼範圍的字元。超出此範圍的任何 Unicode 字元都將使用單一 \uXXXX(BMP 字元)或雙重 \uHHHH\uLLLLL 逸出序列逸出,依據 RFC4627。產生的編碼 JSON 文字可以視為原生 Unicode 字串、ascii 編碼、latin1 編碼或 UTF-8 編碼字串,或任何 ASCII 的超集。
如果 $enable
為 false,則 encode
方法不會跳脫 Unicode 字元,除非 JSON 語法或其他旗標要求。這會產生更快速且更精簡的格式。
請參閱本文檔後面的 ENCODING/CODESET FLAG NOTES 區段。
此旗標的主要用途是產生可透過 7 位元通道傳輸的 JSON 文字,因為編碼後的 JSON 文字不會包含任何 8 位元字元。
JSON::PP->new->ascii(1)->encode([chr 0x10401])
=> ["\ud801\udc01"]
$json = $json->latin1([$enable])
$enabled = $json->get_latin1
如果 $enable
為 true (或遺失),則 encode
方法會將結果的 JSON 文字編碼為 latin1 (或 iso-8859-1),跳脫 0..255
碼範圍外的任何字元。結果的字串可以視為 latin1 編碼的 JSON 文字或原生 Unicode 字串。decode
方法不會受到此旗標影響,因為 decode
預設會預期 Unicode,這是 latin1 的嚴格超集。
如果 $enable
為 false,則 encode
方法不會跳脫 Unicode 字元,除非 JSON 語法或其他旗標要求。
請參閱本文檔後面的 ENCODING/CODESET FLAG NOTES 區段。
此旗標的主要用途是有效率地將二進位資料編碼為 JSON 文字,因為大多數八進位組不會被跳脫,產生較小的編碼大小。缺點是結果的 JSON 文字會編碼為 latin1 (儲存和傳輸時必須正確視為如此),這是 JSON 中罕見的編碼。因此,當您想要在檔案或資料庫中有效率地儲存已知包含二進位資料的資料結構時,此旗標最為有用,而不是與其他 JSON 編碼器/解碼器進行通訊時。
JSON::PP->new->latin1->encode (["\x{89}\x{abc}"]
=> ["\x{89}\\u0abc"] # (perl syntax, U+abc escaped, U+89 not)
$json = $json->utf8([$enable])
$enabled = $json->get_utf8
如果 $enable
為 true (或遺失),則 encode
方法會將 JSON 結果編碼為 UTF-8,這是許多通訊協定的要求,而 decode
方法會預期處理 UTF-8 編碼的字串。請注意,UTF-8 編碼的字串不包含 0..255
範圍外的任何字元,因此對於位元組/二進位 I/O 很有用。在未來的版本中,啟用此選項可能會啟用 UTF-16 和 UTF-32 編碼系列的自動偵測,如 RFC4627 中所述。
如果 $enable
為 false,則 encode
方法會將 JSON 字串傳回為 (未編碼的) Unicode 字串,而 decode
會預期 Unicode 字串。任何解碼或編碼 (例如,編碼為 UTF-8 或 UTF-16) 都需要自行執行,例如,使用 Encode 模組。
請參閱本文檔後面的 ENCODING/CODESET FLAG NOTES 區段。
範例,輸出 UTF-16BE 編碼的 JSON
use Encode;
$jsontext = encode "UTF-16BE", JSON::PP->new->encode ($object);
範例,解碼 UTF-32LE 編碼的 JSON
use Encode;
$object = JSON::PP->new->decode (decode "UTF-32LE", $jsontext);
$json = $json->pretty([$enable])
這會在一次呼叫中啟用(或停用)所有 indent
、space_before
和 space_after
(未來可能還有更多)旗標,以產生最易於閱讀(或最精簡)的形式。
$json = $json->indent([$enable])
$enabled = $json->get_indent
如果 $enable
為 true(或不存在),則 encode
方法會使用多行格式作為輸出,將每個陣列成員或物件/雜湊鍵值對放入其自己的行中,並適當地縮排。
如果 $enable
為 false,則不會產生任何換行或縮排,且產生的 JSON 文字保證不包含任何 換行
。
這個設定在解碼 JSON 文字時沒有作用。
預設的縮排空白長度為三個。你可以使用 indent_length
來變更長度。
$json = $json->space_before([$enable])
$enabled = $json->get_space_before
如果 $enable
為 true(或不存在),則 encode
方法會在 JSON 物件中分隔鍵與值的 :
之前加入一個額外的選用空白。
如果 $enable
為 false,則 encode
方法不會在那些地方加入任何額外的空白。
這個設定在解碼 JSON 文字時沒有作用。你很可能會將這個設定與 space_after
結合使用。
範例,啟用 space_before,停用 space_after 和 indent
{"key" :"value"}
$json = $json->space_after([$enable])
$enabled = $json->get_space_after
如果 $enable
為 true(或不存在),則 encode
方法會在 JSON 物件中分隔鍵與值的 :
之後加入一個額外的選用空白,以及在分隔鍵值對和陣列成員的 ,
之後加入額外的空白。
如果 $enable
為 false,則 encode
方法不會在那些地方加入任何額外的空白。
這個設定在解碼 JSON 文字時沒有作用。
範例,停用 space_before 和 indent,啟用 space_after
{"key": "value"}
$json = $json->relaxed([$enable])
$enabled = $json->get_relaxed
如果 $enable
為 true(或不存在),則 decode
會接受對一般 JSON 語法的一些擴充(請參閱下方)。encode
絕不會受到影響。請注意,這個選項會讓你接受無效的 JSON 文字,就像它們是有效的!。我建議只使用這個選項來剖析人類編寫的特定應用程式檔案(組態檔案、資源檔案等)。
如果 $enable
為 false(預設值),則 decode
只會接受有效的 JSON 文字。
目前接受的擴充功能有
清單項目可以有結尾逗號
JSON 分隔 陣列元素和鍵值對時會使用逗號。如果您手動撰寫 JSON 文字,並且想要快速新增元素時,這可能會令人困擾,因此此擴充功能接受此類項目結尾的逗號,而不僅僅是項目之間的逗號
[
1,
2, <- this comma not normally allowed
]
{
"k1": "v1",
"k2": "v2", <- this comma not normally allowed
}
shell 樣式「#」註解
只要 JSON 允許空白,就另外允許 shell 樣式註解。它們會在第一個回車或換行字元後終止,之後允許更多空白和註解。
[
1, # this comment not allowed in JSON
# neither this one...
]
C 樣式多行「/* */」註解 (僅限 JSON::PP)
只要 JSON 允許空白,就另外允許 C 樣式多行註解。/*
和 */
之間的所有內容都是註解,之後允許更多空白和註解。
[
1, /* this comment not allowed in JSON */
/* neither this one... */
]
C++ 樣式單行「//」註解 (僅限 JSON::PP)
只要 JSON 允許空白,就另外允許 C++ 樣式單行註解。它們會在第一個回車或換行字元後終止,之後允許更多空白和註解。
[
1, // this comment not allowed in JSON
// neither this one...
]
字串中的字面 ASCII TAB 字元
字串中現在允許使用字面 ASCII TAB 字元 (並視為 \t
)。
[
"Hello\tWorld",
"Hello<TAB>World", # literal <TAB> would not normally be allowed
]
$json = $json->canonical([$enable])
$enabled = $json->get_canonical
如果 $enable
為 true (或遺漏),則 encode
方法會透過排序其鍵來輸出 JSON 物件。這會增加相當高的負擔。
如果 $enable
為 false,則 encode
方法會按照 Perl 儲存它們的順序來輸出鍵值對 (這可能會在同一個指令碼的不同執行之間變更,甚至從 5.18 開始,在同一個執行中也會變更)。
如果您想要將相同的資料結構編碼為相同的 JSON 文字 (給定相同的整體設定),則此選項很有用。如果停用此選項,則即使包含相同的資料,相同的雜湊也可能會以不同的方式編碼,因為鍵值對在 Perl 中沒有固有的順序。
這個設定在解碼 JSON 文字時沒有作用。
此設定目前對繫結雜湊沒有影響。
$json = $json->allow_nonref([$enable])
$enabled = $json->get_allow_nonref
與其他布林選項不同,此選項從 4.0
版本開始預設啟用。
如果 $enable
為 true (或遺漏),則 encode
方法可以將非參照轉換為其對應的字串、數字或 null JSON 值,這是對 RFC4627 的擴充功能。同樣地,decode
會接受這些 JSON 值,而不是中斷執行。
如果 $enable
為 false,則如果 encode
方法沒有傳遞陣列參照或雜湊參照,則它會中斷執行,因為 JSON 文字必須是物件或陣列。同樣地,如果 decode
接收到的不是 JSON 物件或陣列,則它會中斷執行。
範例,在未啟用 allow_nonref
的情況下,將 Perl 標量編碼為 JSON 值,導致錯誤
JSON::PP->new->allow_nonref(0)->encode ("Hello, World!")
=> hash- or arrayref expected...
$json = $json->allow_unknown([$enable])
$enabled = $json->get_allow_unknown
如果 $enable
為 true (或遺漏),則當 encode
遇見它無法在 JSON 中表示的值 (例如檔案處理) 時,不會 擲回例外狀況,而是會編碼為 JSON null
值。請注意,受祝福的物件不包含在此,並且由 c<allow_blessed> 另外處理。
如果 $enable
為 false (預設值),則當 encode
遇見它無法編碼為 JSON 的任何內容時,它會擲回例外狀況。
此選項不會以任何方式影響 decode
,建議您在不了解通訊對象的情況下將其關閉。
$json = $json->allow_blessed([$enable])
$enabled = $json->get_allow_blessed
有關詳細資訊,請參閱 "物件序列化"。
如果 $enable
為 true (或遺失),則當 encode
方法遇到無法轉換的受祝福參考時,不會中斷。相反地,會編碼 JSON null
值,而不是物件。
如果 $enable
為 false (預設值),則當 encode
方法遇到無法轉換的受祝福物件時,會擲回例外狀況。
此設定對 decode
沒有影響。
$json = $json->convert_blessed([$enable])
$enabled = $json->get_convert_blessed
有關詳細資訊,請參閱 "物件序列化"。
如果 $enable
為 true (或遺失),則當 encode
方法遇到受祝福物件時,會檢查物件類別中是否有 TO_JSON
方法。如果找到,則會在純量內容中呼叫它,並編碼產生的純量,而不是物件。
TO_JSON
方法可以安全地呼叫 die,如果需要的話。如果 TO_JSON
傳回其他受祝福物件,則會以相同的方式處理。TO_JSON
必須小心,不要在這種情況下造成無限遞迴循環 (== 崩潰)。選擇 TO_JSON
這個名稱,是因為 Perl 核心呼叫的其他方法 (== 不是物件使用者) 通常使用大寫字母,且為了避免與任何 to_json
函數或方法衝突。
如果 $enable
為 false (預設值),則 encode
方法不會考慮這種轉換類型。
此設定對 decode
沒有影響。
$json = $json->allow_tags([$enable])
$enabled = $json->get_allow_tags
有關詳細資訊,請參閱 "物件序列化"。
如果 $enable
為 true (或遺失),則當 encode
方法遇到受祝福物件時,會檢查物件類別中是否有 FREEZE
方法。如果找到,則會使用它將物件序列化為非標準標記 JSON 值 (JSON 解碼器無法解碼)。
它也會導致 decode
分析此類標記 JSON 值,並透過呼叫 THAW
方法將它們反序列化。
如果 $enable
為 false (預設值),則 encode
方法不會考慮這種轉換類型,且標記 JSON 值會在 decode
中造成分析錯誤,就像標記不是語法的一部分一樣。
$json->boolean_values([$false, $true])
($false, $true) = $json->get_boolean_values
預設情況下,JSON 布林值會解碼為重載的 $JSON::PP::false
和 $JSON::PP::true
物件。
使用此方法,您可以指定自己的布林值進行解碼 - 在解碼時,JSON false
會解碼為 $false
的副本,且 JSON true
會解碼為 $true
(這裡的「副本」與將值指定給另一個變數相同,即 $copy = $false
)。
當您想要將解碼的資料結構直接傳遞給其他序列化器 (例如 YAML、Data::MessagePack 等) 時,這很有用。
請注意,這僅在您 decode
時才有效。您可以設定不相容的布林值物件 (例如 布林值),但當您使用此類布林值物件 encode
資料結構時,您仍需要啟用 convert_blessed
(並在必要時新增 TO_JSON
方法)。
不帶任何參數呼叫此方法將會將布林值重設為其預設值。
get_boolean_values
將會傳回 $false
和 $true
值,或者當它們設定為預設值時傳回空清單。
$json->core_bools([$enable]);
如果 $enable
為 true (或遺失),則 decode
將會產生標準 perl 布林值。等於呼叫
$json->boolean_values(!!1, !!0)
如果已設定,get_core_bools
將會傳回 true。在 perl 5.36 上,如果布林值已使用 boolean_values
方法設定為 perl 的核心布林值,它也會傳回 true。
方法 unblessed_bool
和 get_unblessed_bool
提供為別名,以與 Cpanel::JSON::XS 相容。
$json = $json->filter_json_object([$coderef])
當指定 $coderef
時,它將會在每次 decode
解碼 JSON 物件時從 decode
中呼叫。唯一的參數是對新建立的雜湊的參照。如果程式碼參照傳回單一純量 (不需要是參照),這個值 (或它的複本) 會插入到反序列化資料結構中。如果它傳回空清單 (注意:不是 undef
,它是一個有效的純量),原始的反序列化雜湊將會插入。這個設定可能會大幅減緩解碼速度。
當遺漏或未定義 $coderef
時,任何現有的回呼將會移除,而 decode
將不會以任何方式變更反序列化的雜湊。
範例,將所有 JSON 物件轉換為整數 5
my $js = JSON::PP->new->filter_json_object(sub { 5 });
# returns [5]
$js->decode('[{}]');
# returns 5
$js->decode('{"a":1, "b":2}');
$json = $json->filter_json_single_key_object($key [=> $coderef])
作用類似於 filter_json_object
,但只會呼叫具有單一鍵值為 $key
的 JSON 物件。
這個 $coderef
在透過 filter_json_object
指定的 $coderef
(如果有) 之前呼叫。它會傳遞 JSON 物件中的單一值。如果它傳回單一值,它將會插入到資料結構中。如果它沒有傳回任何值 (甚至不是 undef
而是空清單),來自 filter_json_object
的回呼將會接著呼叫,就像沒有指定單一鍵回呼一樣。
如果遺漏或未定義 $coderef
,對應的回呼將會停用。給定鍵值只能有一個回呼。
由於這個回呼呼叫的頻率低於 filter_json_object
,因此解碼速度通常不會受到太大影響。因此,單一鍵物件非常適合用來將 Perl 物件序列化,特別是單一鍵 JSON 物件與 JSON 中最接近類型標記值的概念 (它基本上是 ID/VALUE 組合)。當然,JSON 絕不支援這個,因此您需要確保您的資料永遠不會看起來像序列化的 Perl 雜湊。
單一物件鍵的典型名稱為 __class_whatever__
,或 $__dollars_are_rarely_used__$
或 }ugly_brace_placement
,甚至像 __class_md5sum(classname)__
,以降低與真實雜湊衝突的風險。
範例,將 { "__widget__" => <id> }
形式的 JSON 物件解碼成對應的 $WIDGET{<id>}
物件
# return whatever is in $WIDGET{5}:
JSON::PP
->new
->filter_json_single_key_object (__widget__ => sub {
$WIDGET{ $_[0] }
})
->decode ('{"__widget__": 5')
# this can be used with a TO_JSON method in some "widget" class
# for serialisation to json:
sub WidgetBase::TO_JSON {
my ($self) = @_;
unless ($self->{id}) {
$self->{id} = ..get..some..id..;
$WIDGET{$self->{id}} = $self;
}
{ __widget__ => $self->{id} }
}
$json = $json->shrink([$enable])
$enabled = $json->get_shrink
如果 $enable
為 true(或不存在),則 encode
回傳的字串會縮小(也就是說,如果可能的話會降級)。
shrink 的實際定義可能會在未來版本中變更,但它會始終嘗試以犧牲時間為代價來節省空間。
如果 $enable
為 false,則 JSON::PP 什麼都不做。
$json = $json->max_depth([$maximum_nesting_depth])
$max_depth = $json->get_max_depth
設定編碼或解碼時接受的最大巢狀層級(預設為 512
)。如果在 JSON 文字或 Perl 資料結構中偵測到更高的巢狀層級,則編碼器和解碼器會停止並在該點發出 croak。
巢狀層級由編碼器需要穿越的雜湊或陣列參考數量來定義,以到達給定的點,或在字串中穿越未搭配其匹配的關閉括號的 {
或 [
字元的數量,以到達給定的字元。
將最大深度設定為 1 會禁止任何巢狀,因此確保物件只是一個單一的雜湊/物件或陣列。
如果未提供引數,則會使用最高可能的設定,這通常沒有用。
請參閱 JSON::XS 中的「安全性考量」,以取得更多關於這一點為何有用的資訊。
$json = $json->max_size([$maximum_string_size])
$max_size = $json->get_max_size
設定 JSON 文字在嘗試解碼時可能具有的最大長度(以位元組為單位)。預設為 0
,表示沒有限制。當對長度超過這麼多位元組的字串呼叫 decode
時,它不會嘗試解碼字串,而是會擲回例外。此設定對 encode
沒有影響(目前)。
如果未提供引數,則會停用限制檢查(與指定 0
相同)。
請參閱 JSON::XS 中的「安全性考量」,以取得更多關於這一點為何有用的資訊。
$json_text = $json->encode($perl_scalar)
將給定的 Perl 值或資料結構轉換為其 JSON 表示形式。在發生錯誤時發出 croak。
$perl_scalar = $json->decode($json_text)
encode
的相反動作:預期一個 JSON 文字並嘗試解析它,回傳產生的簡單純量或參考。在發生錯誤時發出 croak。
($perl_scalar, $characters) = $json->decode_prefix($json_text)
此功能類似於 decode
方法,但當第一個 JSON 物件之後有尾隨垃圾時,它不會引發例外,而是會在該處靜默停止解析,並回傳到目前為止已消耗的字元數。
如果您的 JSON 文字未由外部協定分隔,而且您需要知道 JSON 文字在哪裡結束,這會很有用。
JSON::PP->new->decode_prefix ("[1] the tail")
=> ([1], 3)
以下旗標和屬性僅適用於 JSON::PP。如果您使用其中任何一個,您無法透過用 JSON::XS 取代 JSON::PP 來讓您的應用程式執行得更快。如果您需要這些功能,同時也需要提升速度,您可能想嘗試 Cpanel::JSON::XS,這是 Reini Urban 分支的 JSON::XS,支援其中一些功能(具有不同的不相容性)。這些歷史旗標大多數僅保留向下相容性,不應在新的應用程式中使用。
$json = $json->allow_singlequote([$enable])
$enabled = $json->get_allow_singlequote
如果 $enable
為 true(或遺失),則 decode
會接受無效的 JSON 文字,其中包含以單引號開頭和結尾的字串。encode
絕不會受到任何影響。請注意,這個選項讓您接受無效的 JSON 文字,就像它們是有效的!。我建議僅使用這個選項來剖析人類撰寫的應用程式特定檔案(組態檔案、資源檔案等)。
如果 $enable
為 false(預設值),則 decode
只會接受有效的 JSON 文字。
$json->allow_singlequote->decode(qq|{"foo":'bar'}|);
$json->allow_singlequote->decode(qq|{'foo':"bar"}|);
$json->allow_singlequote->decode(qq|{'foo':'bar'}|);
$json = $json->allow_barekey([$enable])
$enabled = $json->get_allow_barekey
如果 $enable
為 true(或遺失),則 decode
會接受無效的 JSON 文字,其中包含名稱未以引號開頭和結尾的 JSON 物件。encode
絕不會受到任何影響。請注意,這個選項讓您接受無效的 JSON 文字,就像它們是有效的!。我建議僅使用這個選項來剖析人類撰寫的應用程式特定檔案(組態檔案、資源檔案等)。
如果 $enable
為 false(預設值),則 decode
只會接受有效的 JSON 文字。
$json->allow_barekey->decode(qq|{foo:"bar"}|);
$json = $json->allow_bignum([$enable])
$enabled = $json->get_allow_bignum
如果 $enable
為 true(或遺失),則 decode
會將 Perl 無法處理的大整數轉換為 Math::BigInt 物件,並將浮點數轉換為 Math::BigFloat 物件。encode
會將 Math::BigInt
和 Math::BigFloat
物件轉換為 JSON 數字。
$json->allow_nonref->allow_bignum;
$bigfloat = $json->decode('2.000000000000000000000000001');
print $json->encode($bigfloat);
# => 2.000000000000000000000000001
另請參閱 MAPPING。
$json = $json->loose([$enable])
$enabled = $json->get_loose
如果 $enable
為 true(或遺失),則 decode
會接受無效的 JSON 文字,其中包含未跳脫的 [\x00-\x1f\x22\x5c] 字元。encode
絕不會受到任何影響。請注意,這個選項讓您接受無效的 JSON 文字,就像它們是有效的!。我建議僅使用這個選項來剖析人類撰寫的應用程式特定檔案(組態檔案、資源檔案等)。
如果 $enable
為 false(預設值),則 decode
只會接受有效的 JSON 文字。
$json->loose->decode(qq|["abc
def"]|);
$json = $json->escape_slash([$enable])
$enabled = $json->get_escape_slash
如果 $enable
為 true(或遺失),則 encode
會明確跳脫斜線(正斜線;U+002F
)字元,以降低 JSON 文字中 </script>
可能導致的 XSS(跨網站指令碼)風險,代價是增加 JSON 文字的大小。
當你將 JSON 嵌入在 HTML 中時,此選項可能會很有用,但一般來說,將任意 JSON 嵌入在 HTML 中(透過某些 HTML 範本工具組或字串內插)是有風險的。你必須依據脈絡,正確地跳脫必要的字元。
decode
絕不會受到任何影響。
$json = $json->indent_length($number_of_spaces)
$length = $json->get_indent_length
此選項僅在你同時啟用 indent
或 pretty
時才會有用。
當你 encode
時,JSON::XS 會以三個空格縮排(如果 indent
或 pretty
要求),且無法變更數字。JSON::PP 允許你使用這些 mutator/accessor 變更/取得縮排空格數。預設空格數為三個(與 JSON::XS 相同),可接受的範圍從 0
(不縮排;最好透過 indent(0)
停用縮排)到 15
。
$json = $json->sort_by($code_ref)
$json = $json->sort_by($subroutine_name)
如果你只是想在 encode
時對 JSON 物件中的金鑰(名稱)進行排序,請啟用 canonical
選項(見上文),它允許你按字母順序對物件金鑰進行排序。
如果你確實需要在非字母順序下進行排序,無論出於何種原因,你可以將程式碼參考(或子程式名稱)傳遞給 sort_by
,然後將參數傳遞給 Perl 的內建 sort
函數。
由於排序是在 JSON::PP 範圍內進行的,你通常需要在子程式名稱之前加上 JSON::PP::
,以及 sort
函數使用的子程式中使用的特殊變數 $a
和 $b
。
範例
my %ORDER = (id => 1, class => 2, name => 3);
$json->sort_by(sub {
($ORDER{$JSON::PP::a} // 999) <=> ($ORDER{$JSON::PP::b} // 999)
or $JSON::PP::a cmp $JSON::PP::b
});
print $json->encode([
{name => 'CPAN', id => 1, href => 'http://cpan.org'}
]);
# [{"id":1,"name":"CPAN","href":"http://cpan.org"}]
請注意,sort_by
會影響資料結構中的所有純雜湊。如果你需要更精細的控制,請使用實作有序雜湊的模組(例如 Hash::Ordered 和 Tie::IxHash)來 tie
必要雜湊。canonical
和 sort_by
都不會影響 tie
d 雜湊中的金鑰順序。
use Hash::Ordered;
tie my %hash, 'Hash::Ordered',
(name => 'CPAN', id => 1, href => 'http://cpan.org');
print $json->encode([\%hash]);
# [{"name":"CPAN","id":1,"href":"http://cpan.org"}] # order is kept
此部分也取自 JSON::XS。
在某些情況下,需要增量式剖析 JSON 文字。雖然此模組總是必須同時在記憶體中保留 JSON 文字和產生的 Perl 資料結構,但它確實允許你增量式剖析 JSON 串流。它會累積文字,直到它有一個完整的 JSON 物件,然後它就可以解碼。此程序類似於使用 decode_prefix
來查看是否有完整的 JSON 物件,但效率更高(並且可以用最少的函數呼叫來實作)。
JSON::PP 只有在確定它有足夠的文字來取得決定性結果時,才會嘗試剖析 JSON 文字,它使用非常簡單但真正增量式的剖析器。這表示它有時不會像完整剖析器一樣早停止,例如,它不會偵測到不匹配的括號。它保證的唯一事情是,它會在看到語法上有效的 JSON 文字後立即開始解碼。這表示你需要設定資源限制(例如 max_size
)以確保剖析器在存在語法錯誤時停止剖析。
下列方法實作此增量解析器。
$json->incr_parse( [$string] ) # void context
$obj_or_undef = $json->incr_parse( [$string] ) # scalar context
@obj_or_empty = $json->incr_parse( [$string] ) # list context
這是核心解析函式。它可以附加新文字,並從迄今累積的串流中萃取物件(這兩個函式都是選用的)。
如果給定 $string
,則此字串會附加到已存在的 JSON 片段,儲存在 $json
物件中。
之後,如果函式在空內容中呼叫,它只會回傳而不做任何進一步的動作。這可以用來在您想要的區塊中加入更多文字。
如果方法在純量內容中呼叫,它會嘗試萃取一個 JSON 物件。如果成功,它會回傳此物件,否則它會回傳 undef
。如果發生解析錯誤,此方法會像 decode
一樣發出 croak(然後可以使用 incr_skip
來略過錯誤的部分)。這是使用此方法最常見的方式。
最後,在清單內容中,它會嘗試從串流中萃取盡可能多的物件,並回傳它們,否則回傳空清單。要執行此動作,JSON 物件或陣列之間不能有分隔符號(空白字元除外),它們必須連續串接。如果發生錯誤,會像在純量內容案例中一樣引發例外。請注意,在此案例中,先前解析的任何 JSON 文字都會遺失。
範例:解析給定字串中的一些 JSON 陣列/物件,並回傳它們。
my @objs = JSON::PP->new->incr_parse ("[5][7][1,2]");
$lvalue_string = $json->incr_text
此方法回傳目前儲存的 JSON 片段為 lvalue,也就是說,您可以操作它。這 僅 在先前呼叫 純量內容 中的 incr_parse
成功回傳物件時才有效。在所有其他情況下,您不得呼叫此函式(我是認真的。雖然在簡單測試中它實際上可能會運作,但在實際情況下它 會 失敗)。作為特別例外,您也可以在解析任何內容之前呼叫此方法。
這表示您只能使用此函式在完整 JSON 物件之前或之後查看或操作文字,而不能在解析器解析 JSON 物件的過程中使用。
此函式在兩種情況下很有用:a) 尋找 JSON 物件後的尾隨文字,或 b) 解析以非 JSON 文字(例如逗號)分隔的多個 JSON 物件。
$json->incr_skip
這會重設增量解析器的狀態,並從輸入緩衝區中移除迄今已解析的文字。這在 incr_parse
發生錯誤時很有用,在這種情況下,輸入緩衝區和增量解析器狀態保持不變,以略過迄今已解析的文字並重設解析狀態。
與 incr_reset
的不同之處在於,只會移除發生解析錯誤之前的文字。
$json->incr_reset
這會完全重設增量解析器,也就是說,呼叫此方法後,解析器會像從未解析過任何內容一樣。
如果您想要重複解析 JSON 物件,並忽略任何尾隨資料,這會很有用,這表示您必須在每次成功解碼後重設剖析器。
此區段大部分內容也取自 JSON::XS。
此區段說明 JSON::PP 如何將 Perl 值對應到 JSON 值,反之亦然。這些對應在大部分情況下都設計為自動「執行正確的動作」,保留往返特徵(您輸入的內容會以等效的形式輸出)。
對於較為了解的人:請注意在以下說明中,小寫的 perl 指的是 Perl 詮譯器,而大寫的 Perl 指的是 Perl 語言本身。
JSON 物件會變成 Perl 中雜湊的參考。物件鍵的順序不會保留(JSON 本身不會保留物件鍵的順序)。
JSON 陣列會變成 Perl 中陣列的參考。
JSON 字串會變成 Perl 中的字串純量 - JSON 中的 Unicode 碼位元會以 Perl 字串中的相同碼位元表示,因此不需要手動解碼。
JSON 數字會變成 perl 中的整數、數字(浮點數)或字串純量,具體取決於其範圍和任何小數部分。在 Perl 層級中,這些沒有差別,因為 Perl 會處理所有轉換細節,但整數可能佔用的記憶體較少,而且可能比浮點數更精確地表示更多值。
如果數字僅包含數字,JSON::PP 會嘗試將其表示為整數值。如果失敗,它會嘗試將其表示為數字(浮點數)值,如果這樣做不會造成精確度損失。否則,它會將數字保留為字串值(這種情況下,您會失去往返能力,因為 JSON 數字會重新編碼為 JSON 字串)。
包含小數或指數部分的數字會永遠表示為數字(浮點數)值,可能會造成精確度損失(這種情況下,您可能會失去完美的往返能力,但 JSON 數字仍會重新編碼為 JSON 數字)。
請注意,精確度不等於準確度 - 二進位浮點數值無法精確表示大多數十進位小數,而且在從浮點數轉換為浮點數時,JSON::PP 僅保證精確度達到最低有效位元,但不包含最低有效位元。
當啟用 allow_bignum
時,大整數值和任何數字值會分別轉換為 Math::BigInt 和 Math::BigFloat 物件,而不會變成字串純量或失去精確度。
這些 JSON 原子會分別變成 JSON::PP::true
和 JSON::PP::false
。它們會被覆載,以幾乎完全像數字 1
和 0
一樣作用。您可以使用 JSON::PP::is_bool
函數檢查純量是否是 JSON 布林值。
JSON null 原子在 Perl 中會變成 undef
。
# 文字
)作為 JSON 語法中啟用 relaxed
設定的非標準擴充,shell 風格註解是允許的。它們可以在字串外的任何地方開始,並持續到該行的結尾。
(標記)值
)。JSON 語法中的另一個非標準擴充,啟用 allow_tags
設定,是標記值。在此實作中,標記必須是編碼為 JSON 字串的 perl 套件/類別名稱,而 值 必須是編碼為 JSON 陣列的選用建構函數引數。
請參閱下方的 "物件序列化",以取得詳細資訊。
從 Perl 到 JSON 的對應稍微困難一些,因為 Perl 是真正的無型別語言,所以我們只能猜測 Perl 值表示哪種 JSON 型別。
Perl 雜湊參照會變成 JSON 物件。由於雜湊鍵 (或 JSON 物件) 中沒有固有順序,因此它們通常會以偽亂數順序編碼。JSON::PP 可以選擇性地對雜湊鍵進行排序 (由 canonical 旗標和/或 sort_by 屬性決定),因此相同的資料結構將序列化為相同的 JSON 文字 (給定相同的設定和 JSON::PP 版本),但這會產生執行時間開銷,而且只有在罕見的情況下才有用,例如當您想要比較某個 JSON 文字與另一個 JSON 文字以判斷是否相等時。
Perl 陣列參照會變成 JSON 陣列。
其他未祝福的參照通常不允許,並且會導致引發例外狀況,但對於整數 0
和 1
的參照除外,它們會在 JSON 中轉換為 false
和 true
原子。您也可以使用 JSON::PP::false
和 JSON::PP::true
來改善可讀性。
to_json [\0, JSON::PP::true] # yields [false,true]
這些特殊值分別會變成 JSON true 和 JSON false 值。如果您想要,也可以直接使用 \1
和 \0
。
這個特殊值會變成 JSON null。
受祝福的物件無法直接以 JSON 呈現,但 JSON::PP
提供多種處理物件的方式。詳情請參閱下方的 "物件序列化"。
簡單的 Perl 純量(任何非參考的純量)是最難編碼的物件:JSON::PP 會將未定義的純量編碼為 JSON null
值,在編碼為 JSON 字串前最後一次用於字串內容的純量,以及任何其他內容作為數字值
# dump as number
encode_json [2] # yields [2]
encode_json [-3.0e17] # yields [-3e+17]
my $value = 5; encode_json [$value] # yields [5]
# used as string, so dump as string
print $value;
encode_json [$value] # yields ["5"]
# undef becomes null
encode_json [undef] # yields [null]
你可以透過字串化來強制類型為 JSON 字串
my $x = 3.1; # some variable containing a number
"$x"; # stringified
$x .= ""; # another, more awkward way to stringify
print $x; # perl does it for you, too, quite often
# (but for older perls)
你可以透過數字化來強制類型為 JSON 數字
my $x = "3"; # some variable containing a string
$x += 0; # numify it, ensuring it will be dumped as a number
$x *= 1; # same thing, the choice is yours.
目前無法以其他較不模糊的方式強制類型。
自版本 2.91_01 起,JSON::PP 使用不同的數字偵測邏輯,將可以安全轉換為數字的純量轉換為數字。新的邏輯速度稍快,且有助於使用較舊 Perl 或想要編碼複雜資料結構的人。不過,這可能會產生與 JSON::XS 編碼不同的 JSON 文字(因此可能會中斷比較整個 JSON 文字的測試)。如果你確實需要先前的行為以確保相容性或進行更精細的控制,請在 use
JSON::PP(或 JSON.pm)之前將 PERL_JSON_PP_USE_B 環境變數設定為 true。
請注意,數字精確度與 Perl 中的意義相同(因此二進制轉換為十進制的規則與 Perl 中相同,可能會與其他語言不同)。此外,你的 Perl 詮譯器可能會公開平台浮點數的延伸,例如無窮大或 NaN - 這些無法以 JSON 呈現,傳入這些值會產生錯誤。
JSON::PP (和 JSON::XS) 信任您傳遞給 encode
方法 (或 encode_json
函數) 的資料是一個乾淨、已驗證的資料結構,其值只能表示為有效的 JSON 值,因為它不是來自外部資料來源 (與您傳遞給 decode
或 decode_json
的 JSON 文字相反,JSON::PP 認為它們是不安全的,不予信任)。由於 JSON::PP 不知道您和您的 JSON 文字的使用者希望意外值是什麼 (您可能希望將它們轉換為 null,或使用正規化或不使用正規化將它們字串化 (無限大/NaN 的字串表示法可能會因平台而異),或在不轉換的情況下發出 croak),建議您在編碼之前執行您和您的使用者需要執行的操作,並且不要在未驗證的情況下對可能以類似數字的值開頭的值進行數字化 (包括無限大/NaN)。
由於 JSON 無法直接表示 Perl 物件,因此您必須在純 JSON 表示法 (無法自動再次反序列化物件) 和 JSON 語法的非標準延伸標記值之間進行選擇。
當 JSON::PP
遇到 Perl 物件時會發生什麼,取決於 allow_blessed
、convert_blessed
、allow_tags
和 allow_bignum
設定,它們會按此順序使用
在這種情況下,JSON::PP
會使用 JSON 語法的非標準延伸建立標記的 JSON 值。
這會透過對物件呼叫 FREEZE
方法來執行,第一個引數是序列化物件,第二個引數是常數字串 JSON
,用於將其與其他序列化器區分開來。
FREEZE
方法可以傳回任意數量的值 (即零個或多個)。這些值和物件的套件/類別名稱隨後會以下列格式編碼為標記的 JSON 值
("classname")[FREEZE return values...]
例如
("URI")["http://www.google.com/"]
("MyDate")[2013,10,29]
("ImageData::JPEG")["Z3...VlCg=="]
例如,假設的 My::Object
FREEZE
方法可能會使用物件的 type
和 id
成員來編碼物件
sub My::Object::FREEZE {
my ($self, $serialiser) = @_;
($self->{type}, $self->{id})
}
convert_blessed
且物件有 TO_JSON
方法。在這種情況下,會在純量內容中呼叫物件的 TO_JSON
方法。它必須傳回一個單一純量,該純量可以直接編碼成 JSON。此純量會取代 JSON 文字中的物件。
例如,下列 TO_JSON
方法會在序列化時將所有 URI 物件轉換為 JSON 字串。這些值原本是 URI 物件的事實會遺失。
sub URI::TO_JSON {
my ($uri) = @_;
$uri->as_string
}
allow_bignum
已啟用且物件為 Math::BigInt
或 Math::BigFloat
。物件將序列化為 JSON 數字值。
allow_blessed
已啟用。物件將序列化為 JSON null 值。
如果未啟用任何設定或缺少相關方法,JSON::PP
會擲回例外狀況。
對於反序列化,只有兩種情況需要考慮:使用非標準標記,此時由 allow_tags
決定,或物件無法自動反序列化,此時您可以使用後處理或 filter_json_object
或 filter_json_single_key_object
回呼取得 JSON 中的實際物件。
本節只考慮標記值情況:解碼過程中遇到標記的 JSON 物件且 allow_tags
已停用,將導致剖析錯誤(就像標記值不是語法的一部分一樣)。
如果 allow_tags
已啟用,JSON::PP
將查詢序列化期間使用的套件/類別名稱的 THAW
方法(不會嘗試將套件載入為 Perl 模組)。如果沒有此方法,解碼將失敗並產生錯誤。
否則,THAW
方法會以類別名稱為第一個引數、常數字串 JSON
為第二個引數,以及 JSON 陣列中的所有值(最初由 FREEZE
方法傳回的值)為其餘引數來呼叫。
然後,方法必須傳回物件。雖然技術上您可以傳回任何 Perl 純量,但您可能必須啟用 allow_nonref
設定才能在所有情況下都能正常運作,因此最好傳回實際的祝福參考。
舉例來說,我們實作一個 THAW
函式,從先前的 FREEZE
範例中重新產生 My::Object
sub My::Object::THAW {
my ($class, $serialiser, $type, $id) = @_;
$class->new (type => $type, id => $id)
}
本節取自 JSON::XS。
有興趣的讀者可能看過許多表示編碼或字元集的旗標 - utf8
、latin1
和 ascii
。這些旗標的作用似乎有些混淆,因此以下提供簡短的比較
utf8
控制由 encode
建立 (且 decode
預期的) JSON 文字是否編碼為 UTF-8,而 latin1
和 ascii
只控制 encode
是否跳脫其各自字元集範圍之外的字元值。這些旗標彼此不會衝突,儘管有些組合比其他組合更沒有意義。
已仔細確保所有旗標相對於 encode
和 decode
都是對稱的,也就是說,使用這些旗標值任何組合編碼的文字,在使用相同旗標時都能正確解碼 - 一般來說,如果您在編碼時使用不同的旗標設定,而解碼時使用不同的旗標設定,您可能在某處有錯誤。
以下是這些旗標的詳細說明。請注意,「字元集」只是一個字元碼點對的抽象集合,而編碼會採用那些碼點數字並將它們編碼,在我們的案例中編碼成八位元組。Unicode 是 (除其他事項之外) 一個字元集,UTF-8 是一種編碼,而 ISO-8859-1 (= latin 1) 和 ASCII 同時是字元集和編碼,這可能會令人混淆。
utf8
旗標當停用 utf8
(預設值) 時,encode
/decode
會產生和預期 Unicode 字串,也就是說,序數 Unicode 值較高的字元 (> 255) 會編碼為此類字元,而此類字元也會原樣解碼,不會對它們進行任何變更,除了分別將它們「(重新)詮釋」為 Unicode 碼點或 Unicode 字元 (對 Perl 而言,在字串中它們是相同的事物,除非您執行有趣/奇怪/愚蠢的操作)。
當您想要自行編碼時 (例如,當您想要有 UTF-16 編碼的 JSON 文字) 或當其他層級為您執行編碼時 (例如,當使用會透明編碼為 UTF-8 的檔案句柄列印至終端機時,您肯定不希望先對您的資料進行 UTF-8 編碼,然後再讓 Perl 再次編碼它),這會很有用。
utf8
旗標如果啟用 utf8
旗標,encode
/decode
會使用對應的 UTF-8 多位元組序列編碼所有字元,並且會預期您的輸入字串編碼為 UTF-8,也就是說,輸入字串的「字元」不得有任何值 > 255,因為 UTF-8 不允許這樣做。
因此,utf8
標記在兩種模式之間切換:停用表示您將在 Perl 中取得 Unicode 字串,而啟用表示您在 Perl 中取得 UTF-8 編碼的八進位/二進位字串。
latin1
或 ascii
標記啟用 latin1
(或 ascii
)後,encode
會跳脫序數值大於 255 的字元(啟用 ascii
時大於 127),並根據 utf8
標記編碼其餘字元。
如果停用 utf8
,則結果也會正確編碼在這些字元集(因為兩者都是 Unicode 的適當子集,表示所有字元值小於 256 的 Unicode 字串與 ISO-8859-1 字串相同,而所有字元值小於 128 的 Unicode 字串與 Perl 中的 ASCII 字串相同)。
如果啟用 utf8
,您仍會取得正確的 UTF-8 編碼字串,不論這些標記為何,只會使用 \uXXXX
跳脫更多字元。
請注意,ISO-8859-1 編碼的字串與 UTF-8 編碼不相容,而 ASCII 編碼的字串則相容。這是因為 ISO-8859-1 編碼並非 UTF-8 的子集(儘管 ISO-8859-1 編碼集是 Unicode 的子集),而 ASCII 則相容。
令人驚訝的是,decode
會忽略這些標記,因此將所有輸入值視為受 utf8
標記管控。如果停用,這允許您解碼 ISO-8859-1 和 ASCII 編碼的字串,因為兩者都是 Unicode 的嚴格子集。如果啟用,您可以正確解碼 UTF-8 編碼的字串。
因此,latin1
和 ascii
都不與 utf8
標記不相容,它們只管 JSON 輸出引擎是否跳脫字元。
latin1
的主要用途是以相對有效率的方式將二進位資料儲存為 JSON,但會破壞與大多數 JSON 解碼器的相容性。
ascii
的主要用途是強制輸出不包含值大於 127 的字元,表示您可以將結果字串解釋為 UTF-8、ISO-8859-1、ASCII、KOI8-R 或大多數任何字元集和 8 位元編碼,並仍取得相同的資料結構。當您傳輸 JSON 的管道並非 8 位元乾淨,或編碼可能在中間被破壞(例如在郵件中),這會很有用,而且可行是因為 ASCII 是世界上大多數 8 位元和多位元編碼的適當子集。
請將此模組特定行為的錯誤報告至 RT 或 GitHub 問題(優先)
https://github.com/makamaka/JSON-PP/issues
https://rt.cpan.org/Public/Dist/Display.html?Queue=JSON-PP
至於新功能和要求變更一般行為,請先透過電子郵件(很重要!)詢問 JSON::XS 的作者(Marc Lehmann,<schmorp[at]schmorp.de>),以維持 JSON.pm 後端之間的相容性。
一般來說,如果您需要特殊的功能,建議您建立一個新的模組,也許可以基於 JSON::Tiny,它比這個模組更小,而且寫得更乾淨。
json_pp 命令列公用程式,可用於快速實驗。
JSON::XS、Cpanel::JSON::XS 和 JSON::Tiny,可作為更快速的替代方案。 JSON 和 JSON::MaybeXS,可輕鬆進行移轉。
JSON::PP::Compat5005 和 JSON::PP::Compat5006,適用於較舊的 perl 使用者。
RFC4627 (http://www.ietf.org/rfc/rfc4627.txt)
RFC7159 (http://www.ietf.org/rfc/rfc7159.txt)
RFC8259 (http://www.ietf.org/rfc/rfc8259.txt)
Makamaka Hannyaharamitu,<makamaka[at]cpan.org>
Kenichi Ishigaki,<ishigaki[at]cpan.org>
著作權 2007-2016 Makamaka Hannyaharamitu 所有
大部分的文件都取自 Marc Lehmann 的 JSON::XS
這個函式庫是自由軟體;您可以在與 Perl 相同的條款下重新發布或修改它。