Generic-Syntax for JSON

A simple example

{
  "string": "text",
  "number": 12,
  "array": [
    true,
    false,
    null
  ],
  "nullVal": null,
  "quoted key": true
}

Highlights:

Escaping

[
  "Line feed is escaped in JSON,
not in GS."
  "For quotes \", it's the same"
  !"A GS feature: "bounded escaping" !"
]

The GS bounded escaping principle is similar to the Multiparts content type. The content between the boundaries is raw and never escaped. !" is the simplest boundary, if this character sequence is present in the content, any character (except ") can be inserted in the middle: !!", !.", !°", !xyz", !☠"...

Do it in GS (you can't in JSON)

Comments

[
  0
  <#"A short comment">
  1
  {
    a=2
    <#TODO by=john date=2019-12-10 "A typed comment with metadata">
    b="x"
    <#DISCUSS by=mark date=2019-12-12 [
    <p`Comment with <em`rich html in GS-ML format`>.`>
    <p`Useful with an IDE that instrument it!`>
    ]>
  }
]

Simple or complex comments can be inserted in any object and array. Of course these comments are skipped when building the tree of objects.

{
  string= "text"
  number= 12
  array= [
    true
    false
    null
  ]
  nullVal
  'quoted key'= true
}
{
  string= "text"
  number= 12
  <#{array= [
    true
    false
    null
  ]
  nullVal
  'quoted key'= true}>
}
{
  string= "text"
  number= 12
  <#"array= [
    true
    false
    null
  ]
  nullVal
  'quoted key'= true">
}

It is also really simple to comment a json fragment while preserving the structure or force the fragment as raw text.

Multi root auto-boxing

{event=load ts=2019-12-10T20:35:32.023Z}
{event=click isTrusted ts=2019-12-10T21:46:12.223Z error="Uncaught ReferenceError: a is not defined"}

GS does not impose one root. For example, a log file with sequential events can be parsed and an array of objects will be returned.

Optimized parsing for object mapping

{type=Group
id=17
name=Administrators
members=[
		{type=User id=32 name=John password="{SHA256}..."}
		{type=Group id=57
			name="Berlin Team"
			members
		}
	]
}
< type=Group id=17 {
name=Administrators
members=[
		< type=User id=32 name=John password='{SHA256}...'>
		< type=Group id=57 {
			name="Berlin Team"
			members
		}>
	]
}>

These two GS fragments are logically identical and will produce the same tree of generic objects with standard parsing.

But in an object mapping context, you need to construct different typed objects depending on certain properties: User and Group types in this example.

In the first classic form, similar to JSON, event driven parsing is not really useful and an intermediate tree of generic objects is generally constructed first and then is mapped to the typed objects.

The optimized second form pulls up certain properties in the header attributes and permits a simple and efficient event driven parsing with direct typed object construction. Have a look to GS-graph a more powerful Generic-Syntax for object mapping and graph.

How does GS work?

In GS all is node and a node has this form:

'<' specialType? name? attribute* body? attribute* '>'

Each node part is optional. When the node has no specialType (such as comments #), no name, and no attributes but just a body, the '<' and '>' marks can be ommited and you get the GS-ON profile.

The body part can be a list [], a map {}, or a text "" (or without quotes and limited character set used in GS-ON profile for null, boolean and number values).

Discover the full syntax.