One document matched: draft-newton-json-content-rules-03.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM "http://xml.resource.org/authoring/rfc2629.dtd"
[
<!ENTITY RFC1166 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.1166.xml'>
<!ENTITY RFC3339 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3339.xml'>
<!ENTITY RFC3986 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3986.xml'>
<!ENTITY RFC4234 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4234.xml'>
<!ENTITY RFC4627 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4627.xml'>
<!ENTITY RFC4648 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.4648.xml'>
<!ENTITY RFC5322 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.5322.xml'>
<!ENTITY RFC5952 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.5952.xml'>
<!ENTITY RFC6570 PUBLIC ''
'http://xml.resource.org/public/rfc/bibxml/reference.RFC.6570.xml'>
]>
<?rfc toc="true"?>
<rfc category="std" docName="draft-newton-json-content-rules-03" ipr="trust200902">
<front>
<title abbrev="JSON Content Rules">A Language for Rules Describing JSON Content</title>
<author fullname="Andrew Lee Newton" initials="A.L." surname="Newton">
<organization abbrev="ARIN">American Registry for Internet Numbers</organization>
<address>
<postal>
<street>3635 Concorde Parkway</street>
<city>Chantilly</city>
<region>VA</region>
<country>US</country>
<code>20151</code>
</postal>
<email>andy@arin.net</email>
<uri>http://www.arin.net</uri>
</address>
</author>
<date/>
<abstract>
<t>
This document describes a language useful for documenting the expected content of JSON structures
found in specifications using JSON.
</t>
</abstract>
</front>
<middle>
<section title="Introduction">
<t>
The goal of this document is to provide a way to document the expected content
of data expressed in <xref target="RFC4627">JSON</xref> format. That is, the primary
purpose of this document is to specify a means for one person to communicate with
another person the expected nature of a JSON data structure in a method more concise
than prose. The programmatic validation of a JSON data structure against content rules
is a lesser goal of this document, though such a practice is useful in both the
writing of specifications and the communications of programs.
</t>
<t>
Unlike JSON Schema, this language is not JSON though the syntax described here
is "JSON-like" (a comparison with JSON Schema can be found in <xref target="json-schema-comparison"></xref>
and a "real world" example can be found in <xref target="real-world-example"></xref>).
A specialized syntax is used to reduce the tedium in reading and
writing rules as the complexity describing allowable content is often more involved
than most of the actual content.
<xref target="rfc4627-example-2-rules"></xref> is an example of
this language describing the JSON of <xref target="rfc4627-example-2"></xref>.
</t>
<figure anchor="rfc4627-example-2">
<preamble>Example JSON lifted from RFC 4627</preamble>
<artwork xml:space="preserve">
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]
</artwork>
</figure>
<figure anchor="rfc4627-example-2-rules">
<preamble>Rules describing <xref target="rfc4627-example-2"></xref></preamble>
<artwork xml:space="preserve">
root [
2*2{
"precision" : string,
"Latitude" : float,
"Longitude" : float,
"Address" : string,
"City" : string,
"State" : string,
"Zip" : string,
"Country" : string
}
]
</artwork>
</figure>
<t>
Depending on need and desired style, an alternate mapping can be used
where certain symbols are substituted for words.
</t>
<figure anchor="rfc4627-example-alt-rules">
<preamble>Rules describing <xref target="rfc4627-example-2"></xref> with an alternate syntax</preamble>
<artwork xml:space="preserve">
root ARRAY
2*2 OBJECT
MEMBER "precision" VALUE string AND
MEMBER "Latitude" VALUE float AND
MEMBER "Longitude" VALUE float AND
MEMBER "Address" VALUE string AND
MEMBER "City" VALUE string AND
MEMBER "State" VALUE string AND
MEMBER "Zip" VALUE string AND
MEMBER "Country" VALUE string
END_OBJECT
END_ARRAY
</artwork>
</figure>
<t>
The JSON Content Rules are of five types:
<list style="symbols">
<t>value rules</t>
<t>member rules</t>
<t>array rules</t>
<t>object rules</t>
<t>group rules</t>
</list>
</t>
<t>
Each rule has two components, a rule name and a rule definition. Anywhere in a
rule definition where a rule name is allowed, another rule definition may be used.
</t>
<t>
This is an example of a value rule:
<list style="empty"><t>v1 : integer 0..3</t></list>
It specifies a rule named "v1" that has a definition of ": integer 0..3" (value rule definitions
begin with a ':' character). This defines
values of type "v1" to be integers in the range 0 to 3 (minimum value of 0, maximum value of 3).
Value rules can define the limits of JSON values, such as stating that numbers must fall
into a certain range or that strings must be formatted according to certain patterns or standards
(i.e. URIs, phone numbers, etc...).
</t>
<t>
Member rules specify JSON object members. The following example member rule states that
the rules name is 'm1' with a value defined by the 'v1' value rule:
<list style="empty"><t>m1 "m1name" v1</t></list>
Since rule names can be substituted by rule definitions, this member rule can also
be written as follows:
<list style="empty"><t>m1 "m1name" : integer 0..3</t></list>
</t>
<t>
Object rules are composed of member rules, since JSON objects are composed of members.
Object rules can specify members that are mandatory, optional, and even choices between
members. In this example, the rule 'o1' defines an object that must contain a member
as defined by member rule 'm1' and optionally a member defined by the rule 'm2':
<list style="empty"><t>o1 { m1, ?m2 }</t></list>
</t>
<t>
Finally, array rules are composed of value and object rules. Like object rules, array rules
can specify the cardinality of the contents of an array. The following array rule
defines an array that must contain value rule 'v1' and zero or more objects as defined
by rule 'o1':
<list style="empty"><t>a1 [ v1, *o1 ]</t></list>
</t>
<t>
Putting it all together, <xref target="rfc4627-example-1-rules"></xref>
describes the JSON in <xref target="rfc4627-example-1"></xref>.
</t>
<figure anchor="rfc4627-example-1">
<preamble>Example JSON shamelessly lifted from RFC 4627</preamble>
<artwork xml:space="preserve">
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}
</artwork>
</figure>
<figure anchor="rfc4627-example-1-rules">
<preamble>Rules describing <xref target="rfc4627-example-1"></xref></preamble>
<artwork xml:space="preserve">
width_v : integer 0..1280
height_v : integer 0..1024
width "width" width_v
height "height" height_v
thumbnail "thumbnail" {
width, height, "Url" : uri
}
image "Image" {
width, height, "Title" : string,
thumbnail, "IDs" [ *: integer ]
}
root { image }
</artwork>
</figure>
<t>
The rules from <xref target="rfc4627-example-1-rules"></xref> can be
written more compactly (see <xref target="rfc4627-example-1-compact-rules"></xref>).
</t>
<figure anchor="rfc4627-example-1-compact-rules">
<preamble>Compact rules describing <xref target="rfc4627-example-1"></xref></preamble>
<artwork xml:space="preserve">
width "width" : integer 0..1280
height "height" : integer 0..1024
root {
"Image" {
width, height, "Title" :string,
"thumbnail" { width, height, "Url" :uri },
"IDs" [ *:integer ]
}
}
</artwork>
</figure>
<t>
For completeness, <xref target="rfc4627-example-1-compact-alt-rules"></xref>
demonstrates the same rules as <xref target="rfc4627-example-1-compact-rules"></xref>
using the alternate syntax.
</t>
<figure anchor="rfc4627-example-1-compact-alt-rules">
<preamble>Compact, alternative rules describing <xref target="rfc4627-example-1"></xref></preamble>
<artwork xml:space="preserve">
width MEMBER "width" VALUE integer 0..1280
height MEMBER "height" VALUE integer 0..1024
root OBJECT
MEMBER "Image" OBJECT
width AND height AND
MEMBER "Title" VALUE string AND
MEMBER "thumbnail" OBJECT
width, height, MEMBER "Url" VALUE uri
END_OBJECT AND
MEMBER "IDs" ARRAY *VALUE integer END_ARRAY
END_OBJECT
END_OBJECT
</artwork>
</figure>
</section>
<section title="Lines and Comments">
<t>
There is no statement terminator and therefore no need for a line continuation syntax.
Blank lines are allowed.
</t>
<t>
Comments are very similar to comments in <xref target="RFC4234">ABNF</xref>. They start with a semi-colon (';') and
continue to the end of the line.
</t>
</section>
<section title="Rules">
<t>
Rules are composed of two parts, a rule name and a rule definition. Rule names allow
a rule definition to be referenced easily by a name. With the exception of value rules,
rule definitions refer to other rules using the rule names of other appropriate types
of rules. Because of this, it is also possible to use a rule definition of the appropriate
type where a rule name of that type would be appropriate.
</t>
<t>
The type of rule to use in a rule definition, either directly or by reference of a name,
depends on the type of rule being defined and fall along the structure of allowable JSON
grammar:
<list style="symbols">
<t>
Since a member of a JSON object can contain a "primitive value", an array, or
an object, member rules can be composed of value rules, array rules, and object rules.
</t>
<t>
JSON objects are composed of members, so object rules can only be composed of
member rules.
</t>
<t>
Finally, as JSON arrays may contain other arrays, objects, and values, array
rules may be composed of value rules, object rules, and array rules.
</t>
</list>
</t>
<t>
A fifth rule type, group rules, exist to help reference a collection of rules.
</t>
<t>
Rule names must start with an alphabetic character (a-z,A-Z) and must contain only
alphabetic characters, numeric characters, the hyphen character ('-') and the
underscore character ('_'). Rule names must not be used more than once.
</t>
<section title="Value Rules">
<t>
Value rules define content for JSON values. JSON allows values to be objects, arrays,
numbers, booleans, strings, and null. Arrays and objects are handled by the array and object
rules, and the value rules define the rest.
</t>
<section title="Numbers, Booleans and Null">
<t>
The rules for booleans and null are the simplest and take the following forms:
<list style="empty">
<t>rule_name : boolean</t>
<t>rule_name : null</t>
</list>
</t>
<t>
Rules for numbers can specify the number as either an integer or floating point number
and may specify a range:
<list style="empty">
<t>rule_name : integer n..m</t>
<t>rule_name : float n..m</t>
</list>
where n is the minimum allowable value of the number and m is the maximum allowable value of the
number. The range doesn't have to be given, but if it is given either the minimum, maximum,
or both are required. If the minimum is not given then the minimum is considered to be the
minimum number value possible to represent in JSON. Likewise, if the maximum is not given then
the maximum is considered to be the maximum number value possible to represent in JSON.
</t>
</section>
<section title="Strings">
<t>
String values may be specified generically as:
<list style="empty"><t>rule_name : string</t></list>
However, the content of strings can be narrowed in the following ways:
<list style="hanging">
<t hangText="Regular Expression: ">
A rule can state that a string must match a regular expression
by giving the regular expression after the string literal:
<list style="empty"><t>rule_name : string /regex/</t></list>
</t>
<t hangText="URIs and URI templates: ">
A rule can state that a string must be a <xref target="RFC3986">URI</xref>:
<list style="empty"><t>rule_name : uri</t></list>
URIs may be further scoped to a specific URI pattern by prepending
a <xref target="RFC6570">URI template</xref>:
<list style="empty"><t>rule_name : uri http://{stuff}</t></list>
<list style="empty"><t>rule_name : uri http://{authority}/{thing1}?q={thing2}</t></list>
When using URI templates, the variable names are ignored for pattern matching,
but the should be provided for construction of a valid URI template. Providing
the variable names also aids in the description of what is to be matched.
</t>
<t hangText="IP Addresses: ">
Narrowing the content of strings down to IP addresses can
be done with either the 'ip4' (see <xref target="RFC1166"></xref>)
or 'ip6' (see <xref target="RFC5952"></xref>) literals:
<list style="empty">
<t>rule_name : ip4</t>
<t>rule_name : ip6</t>
</list>
</t>
<t hangText="Domain Names: ">
Fully qualified A-label and U-label domain names can be
specified with the 'fqdn' and 'idn' literals:
<list style="empty">
<t>rule_name : fqdn</t>
<t>rule_name : idn</t>
</list>
</t>
<t hangText="Dates and Times: ">
Dates and times are specified using the ABNF rules from <xref target="RFC3339">RFC 3339</xref>
as literals:
<list style="empty">
<t>rule_name : date-time</t>
<t>rule_name : full-date</t>
<t>rule_name : full-time</t>
</list>
</t>
<t hangText="Email Addresses: ">
A string can be scoped to the syntax of email addresses using the
literal 'email':
<list style="empty">
<t>rule_name : email</t>
</list>
Email addresses must conform to the syntax of <xref target="RFC5322">RFC 5322</xref>.
</t>
<t hangText="Phone Numbers: ">
Strings conforming to E.123 phone number format can be specified
as follows:
<list style="empty"><t>rule_name : phone</t></list>
</t>
<t hangText="Base 64: ">
Strings containing base 64 data, as described by <xref target="RFC4648">RFC 4648</xref>, can be
specified as follows:
<list style="empty"><t>rule_name : base64</t></list>
</t>
</list>
</t>
</section>
<section title="Enumerations" anchor="enumerations">
<t>
Enumerations allow a value to be one of the items in an enumerated list of possible values.
They take the following form:
<list style="empty"><t>rule_name : < "item1" "item2" "item3" ></t></list>
Items in the enumerated list may be quoted strings, integer or floating point numbers, or the literals
'true', 'false' or 'null'. The types of the items may be mixed, as the following
example demonstrations:
<list style="empty"><t>truthy : < 1 true "yes" "Y" ></t></list>
</t>
</section>
</section>
<section title="Member Rules">
<t>
Member rules are the simplest of the rules and define members of JSON objects.
Member rules follow the format:
<list style="empty"><t>rule_name "member_name" target_rule_name</t></list>
where rule_name is the name of the rule being defined, member_name (in quotes) is
the name of the JSON object member, and target_rule_name is a reference to a value
rule, array rule, or object rule specifying the allowable content of the JSON object member.
</t>
<t>
Since rule names in rule definitions may be substituted for rule definitions,
member rules may also be written in this form:
<list><t>rule_name "member_rule" target_rule_definition</t></list>
The following is an example:
<list style="empty"><t>location_uri "locationURI" : uri</t></list>
</t>
</section>
<section title="Object Rules">
<t>
Object rules define the allowable members of a JSON object. Their rule definitions
are composed of member rules and group rules. They take the following form:
<list style="empty"><t>rule_name { member_rule_1, member_rule_2 }</t></list>
The following rule example defines an object composed of two member rules:
<list style="empty"><t>response { location_uri, status_code }</t></list>
</t>
<t>
Given the general rule that where a rule name is found a rule definition
of the appropriate type may be used, the above example might also be
written:
<list style="empty"><t>response { "locationUri" : uri, "statusCode" : integer }</t></list>
</t>
<t>
Rules given in the rule definition of an object rule do not imply order. Given the example
object rule above both
<list style="empty"><t>{ "locationUri" : "http://example.com", "statusCode" : 200 }</t></list>
and
<list style="empty"><t>{ "statusCode" : 200, "locationUri" : "http://example.com" }</t></list>
are JSON objects that match the rule.
</t>
<t>
Member rules or member rule definitions may not be repeated in the rule definition
of an object rule. However, a member of an object can be marked as optional if the
member rule defining it is preceded by the question mark ('?') character. In the
following example, the location_uri member is optional while the status_code member
is required to be in the defined object:
<list style="empty"><t>response { ?location_uri, status_code }</t></list>
</t>
<t>
An object rule can also define the choice between members by placing the forward slash ('/')
character between two member rules. In the following example, the object being
defined can have either a location_uri member or content_type member and must
have a status_code member:
<list style="empty"><t>response { location_uri / content_type, status_code }</t></list>
</t>
<t>
Finally, the specification of a member of an object can be conditioned upon the
the specification of another member of that object by placing the ampersand ('&')
character between two member rules. Using this syntax, the member defined by the
second rule is only allowed in the object if the member defined by the first rule
is given. Or in other words, the appearance of the second member depends upon the
appearance of the first member. In the following example, the object defined can
have a referrer_uri so long as location_uri is also present:
<list style="empty"><t>response { location_uri & referrer_uri }</t></list>
</t>
</section>
<section title="Array Rules">
<t>
Array rules define the allowable content of JSON arrays. Their rule definitions
are composed of value rules, object rules, group rules, and other array rules and have the following
form:
<list style="empty"><t>rulename [ target_rule_name_1, target_rule_name_2 ]</t></list>
The following example defines an array where element 1 is defined by the width_value rule
and element 2 is defined by the height_value rule:
<list style="empty"><t>size [ width_value, height_value ]</t></list>
</t>
<t>
Unlike object rules, order is implied by the array rule definition. That is,
the first rule referenced or defined within an array rule specifies that the first
element of the array will match that rule, the second rule given with the array rule
specifies that the second element of the array will match that rule, and so on.
</t>
<t>
Take for example the following array rule definition:
<list style="empty"><t>person [ : string, : integer ]</t></list>
This JSON array matches the above rule:
<list style="empty"><t>[ "Bob Smurd", 24 ]</t></list>
while this one does not:
<list style="empty"><t>[ 24, "Bob Smurd" ]</t></list>
</t>
<t>
As with object rules, the forward slash character ('/') can be used to indicate
a choice between two elements. Take for example the following rules:
<list style="empty">
<t>name_value : string</t>
<t>age_value : integer</t>
<t>birthdate_value : date-time</t>
<t>person [ name_value, age_value / birthdate_vale ]</t>
</list>
which would validate
<list style="empty"><t>[ "Bob Smurd", 24 ]</t></list>
or
<list style="empty"><t>[ "Bob Smurd", "1988-04-12T23:20:50.52Z" ]</t></list>
</t>
<t>
Repetition of array values may also be specified by preceding a rule with an
asterisk ('*') character surrounded by the lower bound and upper bound of
the repetition (e.g. "0*1"). The following rules define an array that has
between one and three strings:
<list style="empty">
<t>child_value : string</t>
<t>children [ 1*3 child_value ]</t>
</list>
Both the lower bound and the upper bound are optional. If lower bound is not
given then it is assumed to be zero. If the upper bound is not given then it
is assumed to be infinity. The following example defines an array with an
infinite number of child_value defined strings:
<list style="empty"><t>children [ * child_value ]</t></list>
</t>
</section>
<section title="Group Rules">
<t>
Unlike the other types of rules, group rules have no direct tie with JSON syntax.
Group rules simply group together other rules. They take the form:
<list style="empty"><t>rule_name ( target_rule_1, target_rule_2 )</t></list>
</t>
<t>
Group rule definitions and any nesting of group rule definitions, must conform
to the allowable set of rules of the rule containing them. A group rule referenced
inside of an array rule may not contain a member rule since member rules are not
allowed in array rules directly. Likewise, a group rule referenced inside an object
rule must only contain member rules, and once group rules used in an object rule are
fully dereferenced there must be no duplicate member rules as member rules in
object rules are required to be unique.
</t>
<t>
Take for example the following rules:
<list style="empty">
<t>child_1 "first_child" : string</t>
<t>child_2 "second_child" : string</t>
<t>child_3 "third_child" : string</t>
<t>child_4 "fourth_child" : string</t>
<t>first_two_children ( child_1, child_2 )</t>
<t>second_two_children ( child_3, child_4 )</t>
<t>the_children { first_two_children, second_two_children }</t>
</list>
These rules describe a JSON object that might look like this:
<list style="empty">
<t>{ "first_child":"greg", "second_child":"marsha", "third_child":"bobby", "fourth_child":"jan" }</t>
</list>
</t>
<t>
Groups can also be used with the choice and dependency syntax in member rules. Here
the object can either have first_two_children or second_two_children:
<list style="empty"><t>the_children { first_two_children / second_two_children }</t></list>
and here the object can have second_two_children only if first_two_children are given:
<list style="empty"><t>the_children { first_two_children & second_two_children }</t></list>
</t>
<t>
Group rules can be used to create object mixins. In the example in <xref target="group_mixin_example"></xref>,
both obj1 and obj2 have a members "foo" and "fob" with obj1 having the additional member "bar"
and obj2 having the additional member "baz".
</t>
<figure anchor="group_mixin_example">
<artwork xml:space="preserve">
mixin_group ( "foo" : integer, "fob" : uri )
obj1 { mixin_group, "bar" : string }
obj2 { mixin_group, "baz" : string }
</artwork>
</figure>
</section>
<section title="Any Value and Any Member">
<t>
It is possible to specify that a value can be of any type allowable
by JSON using the any value rule. This is done with the 'any' literal in
a value rule:
<list style="empty"><t>rule_name : any</t></list>
However, unlike other value rules which define primitive data types,
this rule defines a value of any kind, either primitive (null, boolean,
number, string), object, or array.
</t>
<t>
Use of the any value rule in arrays can be used with repetition to define
arrays that may contain any value:
<list style="empty">
<t>any_value : any</t>
<t>array_of_any [ *any_value ]</t>
</list>
</t>
<t>
Specifying any object member name in a member rule with the any member rule
is done by pre-pending
a carat character ('^') to an empty member name (that is, ^"" signifies
any member name). This has the following
form:
<list style="empty"><t>rule_name ^"" target_rule_name</t></list>
As an example, the following defines an object member with any name
that has a value that is a string:
<list style="empty"><t>user_data ^"" : string</t></list>
Usage of the any member rule must still satisfy the criteria that all
member names of an object be unique.
</t>
<t>
Constructing an object member of any name with any type would therefore
take the form:
<list style="empty"><t>rule_name ^"" : any</t></list>
</t>
<t>
Unlike other types of member rules, it is possible to use repetition with
the any member rule in an object rule. The repetition syntax and semantics are
the same as the repetition syntax and semantics of repetition with array rules.
The following example rules define an object that may contain any number of
members where each member may have any value.
<list style="empty">
<t>any_member ^"" : any</t>
<t>object_of_anything { *any_member }</t>
</list>
Use of the repetition of any member rules must satisfy the criteria that
all member names of an object be unique.
</t>
</section>
<section title="A Root Rule">
<t>
In some contexts it is necessary that there be a rule that defines
the outer most JSON object or array, or if thought of as an inverted object tree
the structure at the very top. If in a collection of rules there is no rule
explicitly specified for this purpose and a rule named "root" is given, it
can be assumed to be the outer most JSON structure or the root of an
object/array tree. If a rule is explicitly specified other than "root" and
there exists a rule named "root", that rule name holds no special meaning.
</t>
</section>
</section>
<section title="Directives">
<t>
Directives change the interpretation of a collection of rules. They begin with a hash character ('#')
and are terminated by the end of a line. They take the following form:
<list style="empty"><t># directive_name</t></list>
Directives may have other qualifiers after the directive name. They may appear intermixed with rules
but cannot appear in a rule definition.
</t>
<section title="ignore-unknown-members">
<t>
This directive specifies that any member of any object which has
not been specified should be ignored. Ignored object members may have
a value of any type. This directive cannot be used in any collection
of rules that has an any member rule.
</t>
</section>
<section title="language-compatible-members">
<t>
This directive specifies that every member name of every object,
either explicitly defined or specified via an any member rule or
the ignore-unknown-members directive must be a name compatible with programming
languages. The intent is to specify object member names that may
be promoted to first-order object attributes or methods in
an API. The following ABNF describes the restrictions upon the
member names:
</t>
<figure anchor="json_name_abnf">
<preamble>
ABNF for programming language compatible JSON names
</preamble>
<artwork xml:space="preserve">
name = ALPHA *( ALPHA / DIGIT / "_" )
</artwork>
</figure>
</section>
<section title="all-members-optional">
<t>
This directive specifies that every member of every object
is not required. This directive effectively pre-pends a '?' to every
member rule in every object rule.
</t>
</section>
<section title="include">
<t>
This directive specifies that another collection of rules should
be evaluated before the rules following this directive. This directive
must be qualified with a quoted string describing the collection of
rules to evaluate.
<list style="empty"><t># include "Section 3 of RFC XXXX"</t></list>
The quoted string may be optionally followed by a URI:
<list style="empty"><t># include "Section 3 of RFC XXXX" http://example.com/rfcXXXX</t></list>
</t>
</section>
</section>
<section title="Alternate Syntax">
<t>
The syntax given in the sections above does require specific knowledge of JSON content
rules and may not be appropriate for describing simpler JSON structures or may not be
desired for describing JSON to audiences unfamiliar with JSON content rules. In other
words, choice of syntax is a matter of style and taste and can vary depending on
conditions.
</t>
<t>
Therefore this section describes a syntax mapping where symbols are substituted for
words, thus providing a more readable rule set to some audiences. Because it is a
simple mapping between symbols and words, the structure of the rules does not change
and the syntaxes may be interchanged.
</t>
<t>
The syntax map is as follows:
<list style="empty">
<t>: (colon) maps to the word VALUE</t>
<t>{ (left curly bracket) maps to OBJECT</t>
<t>} (right curly bracket) maps to END_OBJECT</t>
<t>, (comma) maps to AND</t>
<t>/ (forward slash) maps to OR</t>
<t>& (ampersand) maps to DEPENDS</t>
<t>[ (left square bracket) maps to ARRAY</t>
<t>] (right square bracket) maps to END_ARRAY</t>
<t>( (left parenthesis) maps to GROUP</t>
<t>) (right parenthesis) maps to END_GROUP</t>
<t>< (less than symbol) maps to ENUM</t>
<t>> (greater than symbol) maps to END_ENUM</t>
</list>
Because member names in member rules must be quoted strings, there is
no need to map the quotation marks. However the word MEMBER can precede the
quoted string in member rules.
</t>
<t>
The carat symbol used in any rules and the asterisk symbol used for
specifying cardinality do not have a mapping as there are probably no
good words to describe their usage. Additionally, directives do not
have mappings as they are descriptive.
</t>
<t>
The following are examples of the symbolic syntax and the alternate word
syntax:
<list style="hanging">
<t hangText="Value Rules">
<list><t>birthdate : date-time</t></list>
<list><t>birthdate VALUE date-time</t></list>
<list><t>valid_widths_rule : < 640 960 1024 ></t></list>
<list><t>valid_widths_rule VALUE ENUM 640 960 1024 END_ENUM</t></list>
</t>
<t hangText="Member Rules with Values">
<list><t>width_rule "width" : integer 0..1280</t></list>
<list><t>width_rule MEMBER "width" VALUE integer 0..1280</t></list>
</t>
<t hangText="Array Rules with Values">
<list><t>person_array [ : string, : integer ]</t></list>
<list><t>person_array ARRAY VALUE string AND VALUE integer END_ARRAY</t></list>
</t>
<t hangText="Object Rules with Members and Values">
<list><t>response { "locationUri" : uri, "statusCode" : integer }</t></list>
<list><t>response OBJECT MEMBER "locationUri" VALUE uri AND MEMBER "statusCode" VALUE integer END_OBJECT</t></list>
</t>
<t hangText="Group Rules">
<list><t>first_two_children ( child_1, child_2 )</t></list>
<list><t>first_two_children GROUP child_1 AND child_2 END_GROUP</t></list>
</t>
</list>
</t>
</section>
<!--
<section title="Acknowledgements">
<t>Many thanks to Byron Ellacott for providing the ABNF in Section 5.</t>
</section>
-->
</middle>
<back>
<references title="Normative References">
&RFC1166;
&RFC3339;
&RFC3986;
&RFC4234;
&RFC4627;
&RFC4648;
&RFC5322;
&RFC5952;
&RFC6570;
</references>
<section title="Comparison with JSON Schema" anchor="json-schema-comparison">
<t>
This section compares this specification, JSON Content Rules, with JSON Schema
using examples.
</t>
<section title="Example 1 from RFC 4627">
<figure>
<preamble>Example JSON lifted from RFC 4627</preamble>
<artwork xml:space="preserve">
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]
</artwork>
</figure>
<figure>
<preamble>JSON Content Rules</preamble>
<artwork xml:space="preserve">
root [
2*2{
"precision" : string,
"Latitude" : float,
"Longitude" : float,
"Address" : string,
"City" : string,
"State" : string,
"Zip" : string,
"Country" : string
}
]
</artwork>
</figure>
<figure>
<preamble>JSON Schema</preamble>
<artwork xml:space="preserve">
{
"type": "array",
"items": [
{
"type": "object",
"properties": {
"precision": { "type": "string", "required": "true" },
"Latitude": { "type": "number", "required": "true" },
"Longitude": { "type": "number", "required": "true" },
"Address" : { "type": "string", "required": "true" },
"City" : { "type": "string", "required": "true" },
"State" : { "type" : "string", "required": "true" },
"Zip" : { "type" : "string", "required": "true" },
"Country" : { "type" : "string", "required": "true" }
}
}
],
"minItems" : 2,
"maxItems" : 2
}
</artwork>
</figure>
</section>
<section title="Example 2 from RFC 4627">
<figure>
<preamble>Example JSON shamelessly lifted from RFC 4627</preamble>
<artwork xml:space="preserve">
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}
</artwork>
</figure>
<figure>
<preamble>JSON Content Rules</preamble>
<artwork xml:space="preserve">
width "width" : integer 0..1280
height "height" : integer 0..1024
root {
"Image" {
width, height, "Title" :string,
"thumbnail" { width, height, "Url" :uri },
"IDs" [ *:integer ]
}
}
</artwork>
</figure>
<figure>
<preamble>JSON Schema</preamble>
<artwork xml:space="preserve">
{
"type" : "object",
"properties" : {
"Image": {
"type" : "object",
"properties" : {
"Width" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 1280,
"required" : "true"
}
"Height" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 1024,
"required" : "true"
}
"Title" : { "type": "string" },
"Thumbnail" : {
"type" : "object",
"properties" : {
"Url" : {
"type" : "string",
"format" : "uri",
"required" : "true"
},
"Width" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 1280,
"required" : "true"
},
"Height" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 1280,
"required" : "true"
}
}
},
"IDs" : {
"type":"array",
"items":[ { "type": "integer" } ],
"required" : "true"
}
}
}
}
}
</artwork>
</figure>
</section>
</section>
<section title="A "Real World" Exmaple" anchor="real-world-example">
<t>
The following example is taken from draft-ietf-weirds-json-response-00.
It describes the entity object (Section 4), the nameserver object
(Section 5) and many of the other sub-structures used in objects defined
in other sections of that draft.
</t>
<figure>
<preamble>JSON Content Rules for nameserver and entity from draft-ietf-weirds-json-response</preamble>
<artwork xml:space="preserve">
# all-members-optional
# ignore-unknown-members
# language-compatible-members
; the nameserver object
; models nameserver host information
; this often referred to as 'host' object too
nameserver {
; the host name of the name server
"name" : fqdn,
; the ip addresses of the nameserver
"ipAddresses" [ *( :ip4 / :ip6 ) ],
common
}
; the entity object
; This object object represents the information of organizations,
; corporations, governments, non-profits, clubs, individual persons,
; and informal groups of people.
entity {
; the names by which the entity is commonly known
"names" [ *:string ],
; the roles this entity has with any containing object
"roles" [ *:string ],
; the place where the person, org, etc... receives postal mail
; THIS IS NOT LOCATION
"postalAddress" [ *:string ],
; electronic mailboxes where the person, org, etc...
; receives messages
"emails" [ *:email ],
; phones where the person, org, etc... receives
; telephonic communication
"phones" {
"office" [ *:phone ], ; office phones
"fax" [ *:phone ], ; facsilime machines
"mobile" [ *:phone ] ; cell phones and the like
},
common
}
; The members "handle", "status", "remarks", "uris", "port43",
; "sponsoredBy", "resoldBy", "registrationBy", "registrationDate",
; "lastChangedDate", and "lastChangedBy" are used in many objects
common (
; a registry-unique identifier
"handle" : string,
; an array of status values
"status" [ *:string ],
; an array of strings, each containing comments about the object
"remarks" [ *:string ].
; an array of uri objects
; "type" referrs to the application of the URI
; "uri" is the uri
"uris" [
*{ "type" : string, "uri" : uri }
],
; a string containing the fully-qualified host name of the
; WHOIS [RFC3912] server where the object instance may be found
"port43" : fqdn,
; a string containing an identifier of the party
; through which the registration was made, such as an IANA approved
; registrar
"sponsoredBy" : string,
; a string containing an identifier of the party
; originating the registration of the object.
"resoldBy" : string,
; a string containing an identifier of the party
; responsible for the registration of the object
"registrationBy" : string,
; the date the object was registered
"registrationDate" : date-time,
; the date of last change made to the object
"lastChangedDate" : date-time,
; a string containing an identifier of the party
; responsible for the last change made to the registration
"lastChangedBy" : string
)
</artwork>
</figure>
</section>
<section title="Design Notes">
<section title="Member Uniqueness">
<t>
JSON does not disallow non-unique object member names (
in other words, it allows non-unique object member names )
but strongly advises against the use of non-unique object
member names. Many JSON implementations use hash-indexed maps
to represent JSON objects, where the object's member names are
the key of the hash index. Non-uniqueness would break
such implementations or result in the value of the last member
given overwriting the value of all previous members of the
same name.
</t>
<t>
Therefore, allowing non-unique object member names would be
bad practice. For this reason, this specification does not
accommodate the need for non-unique object member names.
</t>
</section>
<section title="Member Order">
<t>
JSON gives awkward guidance regarding ordering of
object member names. However, many JSON implementations
use hash-indexed maps to represent JSON objects, where the object's
member names are the key of the hash index. Though it is
possible, usually these maps have no explicit order as
the only index is the hash.
</t>
<t>
Therefore, this specification does not provide a means
to imply order of object member names.
</t>
</section>
<section title="Group Syntax for Arrays and Objects">
<t>
It is possible to create a separate group syntax for
array rules vs object rules, since allowable group rule content
is determined by the containing rule. For instance, while the
syntax for groups in objects could have been "( blah blah )",
syntax for groups in arrays could have been "< blah blah >".
That may be more distinctive and allow the formal syntax parser
to handle rule content validity, but the added extra syntax
appeared to hurt readability. There is only so many enclosure
characters a person should reasonably be required to know, and
adding yet another did not seem prudent.
</t>
</section>
<section title="Inspiration">
<t>The original approach to this problem was to find a concise
way to describe JSON data structures; to do for JSON what
RelaxNG compact syntax does for XML. The syntax itself hopefully
has a JSON-ness or a JSON feel to it. And a good bit of
inspiration came from ABNF.</t>
</section>
<section title="Changelog">
<t>From -00 to -01
<list style="numbers">
<t>Added ABNF. Thanks Byron Ellacott.</t>
<t>Added section about root rules.</t>
<t>Other minor edits.</t>
</list>
</t>
<t>From -01 to -02
<list style="numbers">
<t>Other minor edits.</t>
<t>Added the Possible Future Changes section.</t>
<t>Mostly a keep-alive version.</t>
</list>
</t>
<t>From -02 to -03
<list style="numbers">
<t>Removed formal syntax (ABNF) until such time as the features are nailed down.
It will appear in a future draft.</t>
<t>Took out the option for multiple email conformance levels as everything
should be conformant to RFC 5322.</t>
<t>URIs conformance can now either be just 'uri' or match a URI template
(suggestion from Andrew Biggs).</t>
<t>Added enumerated values based on a suggestion from Paul Jones.</t>
<t>Added a directive for including other collections of rules.</t>
<t>Added an example of object mixins using groups thanks to a discussion
with Andrew Biggs.</t>
<t>Added an alternate syntax mapping.</t>
</list>
</t>
</section>
</section>
</back>
</rfc>| PAFTECH AB 2003-2026 | 2026-04-23 05:25:59 |