Let's import inventory for playing with AXON with python.
In [1]:
from __future__ import unicode_literals, print_function, division
from pprint import pprint
import axon
import json
import xml.etree as etree
from IPython.display import HTML, display, display_html
Here is well known example of JSON message:
In [2]:
!cat basic_sample.json
In [3]:
json_vals= json.load(open("basic_sample.json"))
vals = axon.load("basic_sample.json", json=1)
One can see that content of json_vals and axon_vals are equal.
In [4]:
print(json_vals)
print(vals[0])
assert str(json_vals) == str(vals[0])
AXON supports more readable and compact form. Any JSON message can be translated to this form by removing of all , and " around keys that are identifiers:
In [5]:
axon.dumps(vals, pretty=1))
We'l call these forms as JSON style of notation, which bases on compositions of dicts and lists.
For compatibility reasons there is a mode in
pyaxonpython library that allow using symbol','as a separator symbol between values in lists and dicts. In this case almost validJSONmessage can be loaded as well asAXONmessage:
AXON supports decimal numbers, date/time/datetime values and comments.
Let's consider AXON example – list of dicts containing decimal, date and time values:
In [6]:
!cat better_json.axon
In [7]:
vals = axon.load("better_json.axon")
pprint(vals)
There is compact dump:
In [8]:
print(axon.dumps(vals))
There is a dump into formatted form:
In [9]:
print(axon.dumps(vals, pretty=1))
There is also parameter hsize. It specifies maximum number of simple data items in a line:
In [10]:
print(axon.dumps(vals, pretty=1, hsize=2))
AXON also supports reference links between values in the message. Here is an simple example:
In [11]:
!cat better_json_crossref.axon
In [12]:
vals = axon.load("better_json_crossref.axon")
assert vals[-1]['children'][0] is vals[0]
assert vals[-1]['children'][1] is vals[1]
pprint(vals)
In [13]:
print(axon.dumps(vals, pretty=1, crossref=1, hsize=2))
Let's consider short fragment of JSON:
"name": {
"key_1": "value_1",
"key_2": "value_2"
}
It can be translated as a value of the attribute name of some object. But it also can be translated as an object that is constructed from the value
{
"key_1": "value_1",
"key_2": "value_2"
}
using some factory function that corresponds to the tag name.
For this kind of use cases there are mappings in AXON:
name {
key_1: "value_1"
key_2: "value_2"
}
It's also usefull for notation of the object whose type/class is mapped to the name.
This kind of notation may be also considered as direct translation of the XML notation:
<name
key_1="value_1"
key_2="value_2" />
Let's consider another short fragment of JSON:
"name": [
«value_1»,
«value_2»
]
Some times this form is used for notation of the container of some type that corresponds to the tag name.
For this kind of use cases there are sequences in AXON:
tag {
«value_1»
«value_2»
}
This kind of notation in AXON can be considered as translation of the following XML pattern:
<tag>
«value_1»
«value_2»
</tag>
First basic example of JSON can be translated to AXON by following XML style of data representation when anonymous structures becames named and subelement is used instead of key:value or attribute:value value for some good reasons:
In [14]:
vals = axon.load("basic_sample.axon")
print(axon.dumps(vals, pretty=1))
Here is it's XML version for comparison:
<person firstName="John" lastName="Smith" age="25">
<address
streetAddress="21 2nd Street"
city="New York"
state="NY"
postalCode=10021 />
<phoneNumber type="home" number="212 555-1234"/>
<phoneNumber type="fax" number="646 555-4567"/>
</person>
By this way one can support extensibility of the representation as XML does when element is used instead of attribute. In case of XML this kind of notation is verbose for representation of name/value pair:
<attr>value</attr>
But in case of AXON it isn't:
attr{value}
So any XML element
<ename
attr_1="value_m"
...
attr_m="value_m">
<subename_1>...</subename_1>
...
<subename_N>...</subename_N>
</ename>
can be easily translated to AXON notation as follows:
ename {
attr_1:"value_m"
...
attr_m:"value_m"
subename_1 {...}
...
subename_N {...}
}
Presented above AXON forms of messages are are in compact form and in formatted with braces.
Compact form uses minimum amount of space:
In [15]:
print(axon.dumps(vals))
Compact form of notation usually as small as many binary serialization formats in the cases when objects contains mostly strings and a few of numbers.
Formatted form is used for readability of expresson based format of representation:
In [16]:
print(axon.dumps(vals, pretty=1, braces=1))
Note that one free to use spaces and line breaks between tokens as he want.
AXON also supports YAML/Python inspired formatted form without braces:
In [17]:
print(axon.dumps(vals, pretty=1))
This type of notation is widely used in YAML. In AXON the same indentation level uses to indicate bounds of nested parts of the named block of data.
Let's consider JSON text:
# formatted form
{"skillz": {
"web": [
{"name": "html", "years": "5", "level": "5"},
{"name": "css", "years": "3", "level": "5"}
],
"database": [
{"name": "sql", "years": "7", "level": "4"}
]
}}
# compact form
{"skillz":{"web":[{"name":"html","years":"5","level":"5"},
{"name":"css","years":"3","level":"5"}],
{"name":"sql","years": "7", "level": "4"}]}}
and it's translation to XML-style representation in AXON formatted form (equal indentation of inner content of complex values is just usefull convention which is not required by syntax of AXON):
# formatted form
skills {
web {
html {years:5 level:5}
css {years:3 level:5}}
database {
sql {years:7 level:4}}
}
# compact form
skills{web{html{years:5 level:5}} database{sql{years:7 level:4}}}
or in indented form (equal indentation of inner content of complex values is required by syntax of AXON):
skills
web
html
years: 5
level: 5
css
years: 3
level: 5
database
sql
years: 7
level: 4
One could see that XML-style data representation has advantages over JSON-style in some context. The reverse is also the case.
Also one could see that formatted form of data representation has advantages over indented form in some context. The reverse is also the case.
More of that: you can mix them as you want in handwritten AXON representation:
skillz {
web
{name: "html"
years: 5
level: 5}
{name: "css"
years: 3
level: 5}
database
{name: "sql"
years: 7
level: 4}
}
or
skillz
web
{name: "html"
years: 5
level: 5}
{name: "css"
years: 3
level: 5}
database
{name: "sql"
years: 7
level: 4}
Reference implementation of AXON in python dosn't force you to choice one style or form of data representation over another. You can select them explicitly in dump call. But by default compact form of data representation is used.
It's hoped that existance in AXON of formatted expression based and indented statement based representations will help to combine these two ways of data representation when it's reasonable.
For example, consider JSON-style representation of complex structure in formatted form:
{ store: {
book: [
{ category: "reference"
author: "Nigel Rees"
title: "Sayings of the Century"
price: 8.95
}
{ category: "fiction"
author: "Evelyn Waugh"
title: "Sword of Honour"
price: 12.99
}
{ category: "fiction"
author: "Herman Melville"
title: "Moby Dick"
isbn: "0-553-21311-3"
price: 8.99
}
{ category: "fiction"
author: "J. R. R. Tolkien"
title: "The Lord of the Rings"
isbn: "0-395-19395-8"
price: 22.99
}
]
bicycle: {
color: "red"
price: 19.95
}
}
}
There is XML-style representation of same structure in formatted form:
store {
book {
category: "reference"
author: "Nigel Rees"
title: "Sayings of the Century"
price: 8.95
}
book {
category: "fiction"
author: "Evelyn Waugh"
title: "Sword of Honour"
price: 12.99
}
book {
category: "fiction"
author: "Herman Melville"
title: "Moby Dick"
isbn: "0-553-21311-3"
price: 8.99
}
book {
category: "fiction"
author: "J. R. R. Tolkien"
title: "The Lord of the Rings"
isbn: "0-395-19395-8"
price: 22.99
}
bicycle {
color: "red"
price: 19.95
}
}
and in indented form:
store
book
category: "reference"
author: "Nigel Rees"
title: "Sayings of the Century"
price: 8.95
book
category: "fiction"
author: "Evelyn Waugh"
title: "Sword of Honour"
price: 12.99
book
category: "fiction"
author: "Herman Melville"
title: "Moby Dick"
isbn: "0-553-21311-3"
price: 8.99
book
category: "fiction"
author: "J. R. R. Tolkien"
title: "The Lord of the Rings"
isbn: "0-395-19395-8"
price: 22.99
bicycle
color: "red"
price: 19.95
Last there is compact form:
store{book{category:"reference" author:"Nigel Rees" title:"Sayings of the Century" price:8.95}
book{category:"fiction" author:"Evelyn Waugh" title:"Sword of Honour" price:12.99}
book{category:"fiction" author:"Herman Melville" title:"Moby Dick" isbn:"0-553-21311-3" price:8.99}
book{category:"fiction" author:"J. R. R. Tolkien" title:"The Lord of the Rings" isbn:"0-395-19395-8" price:22.99}
bicycle:{color:"red" price:19.95}}
AXON extend JSON by allowing using of named objects by introducing nodes.
For example:
# formatted with braces
person {
name: "John Hunt"
age: 50
weight: 87.5
}
# formatted without braces
person
name: "John Hunt"
age: 50
weight: 87.5
AXON also extend JSON by allowing using of named arrays. Note that JSON arrays are just lists in AXON.
For example:
# compact form
primes { 2 3 5 7 11 13 17 19 23 }
# mixed form
people {
person
name: "John"
age: 37
sex: "male"
person
name: "Ann"
age: 27
sex: "female"
person
name: "Jane"
age: 30
sex: "female"
}
Hierarchical objects in AXON are objects, which contains sequence of child subobjects. They are represent attributed trees. So they can represent hierarchical data as well as XML can.
For example:
# compact form
tree{node{id:1 node{id:2 leaf{"Class A"}} node{id:3 leaf{"Class B"}}}}
# formatted with braces
tree {
node {
id:1
node {
id:2
leaf { "Class A" }
}
node {
id:3
leaf { "Class B" }
}
}
}
# formatted without braces
tree
node
id:1
node
id:2
leaf
"Class A"
node
id:3
leaf
"Class B"
AXON supports using of object references for representation of relational data.
For example:
# formatted form with braces
graph {
nodes: [
# &1, &2, &3, &4 are labels of the values
&1 node {1 1}
&2 node {1 2}
&3 node {2 2}
&4 node {2 1}
]
edges: [
# *1, *2, *3, *4 are references of the values
edge {*1 *2}
edge {*1 *3}
edge {*2 *3}
edge {*1 *4}
edge {*3 *4}
]
}
# formatted form without braces
graph:
nodes: [
# 1, 2, 3, 4 are labels of the values
&1 node {1 1}
&2 node {1 2}
&3 node {2 2}
&4 node {2 1}]
edges:
# *1, *2, *3, *4 are references of the values
edge {*1 *2}
edge {*1 *3}
edge {*2 *3}
edge {*1 *4}
edge {*3 *4}]
In [ ]: