Package: pbjson
Packed Binary JSON extension for Pythonpbjsonis a packed binary JSON encoder and decoder for Python 2.5+
and Python 3.3+. It is pure Python code with no dependencies, but
includes an optional C extension for a serious speed boost.pbjsoncan be used standalone or as an extension to the standardjsonmodule or tosimplejson, from which code was heavily
borrowed. The latest documentation forsimplejsoncan be read online
here:http://simplejson.readthedocs.org/The encoder can be specialized to provide serialization in any kind of
situation, without any special support by the objects to be serialized
(somewhat like pickle). This is best done with thedefaultkwarg to
dumps.The decoder can handle incoming JSON strings of any specified encoding
(UTF-8 by default). It can also be specialized to post-process JSON
objects with theobject_hookorobject_pairs_hookkwargs. This
is particularly useful for implementing protocols that have a richer
type system than JSON itself.Using the APIThepbjsonmodule works ust like thejsonmodule. You canpbjson.load,pbjson.loads,pbjson.dump, andpbjson.dumps.Command-Line ToolAfter you have installedpbjson, you can use thepbjsoncommand-line tool to
convert files to or frompbjson. Runpbjson-hfor details.What is Packed Binary JSON (PBJSON)Packed Binary JSON is not the same asBSON.BSONis a format
used primarily in MongoDB and is meant for efficient parsing.PBJSONis meant for efficient conversion from a dict or list, transmission and
conversion back to a dict or list on the other end.BSONhas
explicit support for several types not available in standard JSON.
PBJSON supports only those types supported by normal JSON, plus binary
data blobs and set collections.UnlikeBSON,PBJSONis almost always smaller than the equivalent
JSON. LikeBSON,PBJSONcan be very quickly encoded and decoded
since all elements are length encoded.There are two types of tokens inPBJSON: data and key. Data tokens
can be zero length fundamental types (false,true,null),
variable length fundamental types (int,float,string,binary) or containers (set,array,dict).The type for the data token is generally stored in the top 3 bits (bits
5-7). Type zero is a special type to represent the zero length
fundamental types. The lower bits indicate the actual value. These are:Zero-length Data Types:00 - false01 - true02 - nullAll other types are variable length. If the length is between 0 and 15,
that length is stored in bits 0-3. For lengths in the 16-2047 range, bit
4 is set and bits 0-2 are combined with the next byte to make an 11-bit
length. If bits 4 and 3 are both set, then the value in bits 0-2 are
combined with the next 2 bytes to create a 19-bit length. However, if
bits 4-0 are all set, this indicates that the following 4 bytes are
simply used as a size. So the token plus length is, one byte (length of
0-15), two bytes (16-2047), three bytes (2048-458751) or five bytes
(458876-4294967295).Variable-length Data types:2x - int (bytes stored big endian with leading zero bytes removed)4x - negative int (bytes stored big endian as a positive number with
leading zero bytes removed)6x - float (stored as big endian double precision with trailing zero
bytes removed)8x - stringAx - binaryCollection types: (length is number of elements)Cx - arrayEx - object0C - terminated array0F - terminatorThe final entry, the “terminated array” works a bit differently. This is
for use when the length is not known when writing begins. Instead, a
terminator (0F) is written to the stream when the last element of the
array has been written.Object keys must be text and are a maximum of 127 bytes in length. They
are stored as a (7-bit length, followed by the actual key. The first 128
keys are remembered by index. If the same key is used again, it can be
represented as a single byte consisting of the high bit and the index
number of the key.In other words, if the recurring key is “toast”, it should be encoded as
05 toast. The next time the key “toast” is needed, it can be encoded as
simply 80, since it was the first key.Here is an example of a simple structure:{"toast":true,"burned":false,"name":"the best","toppings":["jelly","jam","butter"],"dimensions":{"thickness":0.7,"width":4.5}}E5 05 'toast' 01 06 'burned' 00 04 'name' 88 'the best'
08 'toppings' C3 85 'jelly' 83 'jam' 86 'butter'
0A 'dimensions' E2 09 'thickness' 61 d7 05 'width' 62 4d5dLet’s break that out:00: E5 - dict with 5 elements01: 05 - key with 5 characters02-06: toast07: 01 - true08: 06 - key with 6 characters09-0E: burned0F: 00 - false10: 04 - key with 4 characters11-14: name15: 88 - string with 8 characters16-1D: the best1E: 08 - key with 8 bytes1F-26: toppings27: C3 - array with 3 elements28: 85 - string with 5 characters29-2D: jelly2E: 83 - string with 3 characters2F-31: jam32: 86 - string with 6 characters33-38: butter39: 0A - key with 10 bytes3A-43: dimensions44: E3 - dict with 2 elements45: 09 - key with 9 characters46-4E: thickness4F: 61 - float with 1 bytes50: first byte of IEEE representation of .7. Remaining 7 bytes were all zeros.51: 05 - key with 5 characters52-56: width57: 62 - float with 2 bytes58-59: first 2 bytes of IEEE representation of 4.5. Remaining 6 bytes were all zeros.Total 90 bytes. The tightestJSONrepresentation requires 126 bytes.
Marshal takes 153 bytes. Pickle takes 184 bytes. BSON takes 145 bytes.Now here is an example with repeating data:{"region":3,"countries":[{"code":"us","name":"United States"},{"code":"ca","name":"Canada"},{"code":"mx","name":"Mexico"}]}E2 06 region 21 03 09 countries C3
E2 04 code 82 us 04 name 8D United States
E2 82 82 ca 83 86 Canada
E2 82 82 mx 83 86 MexicoThis breaks down thus:00: E2 - dict with 2 elements01: 06 - key with 6 characters02-07: region08: 21 - int with 1 byte09: 03 - the int for 3. Only a single byte is required.0A: 09 - key with 9 bytes0B-13: countries14: C3 - array with 3 elements15: E2 - dict with 2 elements16: 04 - key with 4 characters17-1A: code19: 82 - string with 2 characters1A-1B: us1C: 04 - key with 4 characters1E-21: name22: 8D - string with 13 characters23-2F: United States30: E2 - dict with 2 elements31: 82 - recurring key 2. Since ‘code’ was the 3rd key, it has an
index of 2.32: 82 - string with 2 characters33-34: ca35: 83 - recurring key 336: 86 - string with 6 characters37-3C: Canada3D: E2 - dict with 2 elements3E: 82 - recurring key 03F: 82 - string with 2 characters40-41: mx42: 83 - recurring key 143: 86 - string with 6 characters44-49: MexicoTotal 74 bytes. The tightestJSONrepresentation requires 123 bytes.
Marshal takes 158 bytes and Pickle takes 162. BSON takes 154 bytes.Packed Binary JSONis available now in thepbjsonPython module.
That module includes a command line utility to convert between normalJSONfiles andPBJSON.