Network Working Group A. Newton Internet-Draft ARIN Intended status: Standards Track P. Cordell Expires: April 1, 2018 Codalogic September 28, 2017 A Language for Rules Describing JSON Content draft-newton-json-content-rules-09 Abstract This document describes a language for specifying and testing the expected content of JSON structures found in JSON-using protocols, software, and processes. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on April 1, 2018. Copyright Notice Copyright (c) 2017 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. Newton & Cordell Expires April 1, 2018 [Page 1] Internet-Draft JSON Content Rules September 2017 Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1. A First Example: Specifying Content . . . . . . . . . . . 3 1.2. A Second Example: Testing Content . . . . . . . . . . . . 3 2. Overview of the Language . . . . . . . . . . . . . . . . . . 5 3. Lines and Comments . . . . . . . . . . . . . . . . . . . . . 7 4. Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 4.1. Rule Names and Assignments . . . . . . . . . . . . . . . 8 4.2. Annotations . . . . . . . . . . . . . . . . . . . . . . . 9 4.3. Starting Points and Root Rules . . . . . . . . . . . . . 10 4.4. Type Specifications . . . . . . . . . . . . . . . . . . . 10 4.5. Primitive Specifications . . . . . . . . . . . . . . . . 12 4.5.1. Numbers, Booleans and Null . . . . . . . . . . . . . 12 4.5.2. Strings . . . . . . . . . . . . . . . . . . . . . . . 13 4.6. Any Type . . . . . . . . . . . . . . . . . . . . . . . . 16 4.7. Member Specifications . . . . . . . . . . . . . . . . . . 16 4.8. Object Specifications . . . . . . . . . . . . . . . . . . 16 4.9. Array Specifications . . . . . . . . . . . . . . . . . . 19 4.9.1. Unordered Array Specifications . . . . . . . . . . . 21 4.10. Group Specifications . . . . . . . . . . . . . . . . . . 21 4.11. Ordered and Unordered Groups in Arrays . . . . . . . . . 22 4.12. Sequence and Choice Combinations in Array, Object, and Group Specifications . . . . . . . . . . . . . . . . . . 22 4.13. Repetition in Array, Object, and Group Specifications . . 23 4.14. Negating Evaluation . . . . . . . . . . . . . . . . . . . 25 5. Directives . . . . . . . . . . . . . . . . . . . . . . . . . 26 5.1. jcr-version . . . . . . . . . . . . . . . . . . . . . . . 26 5.2. ruleset-id . . . . . . . . . . . . . . . . . . . . . . . 27 5.3. import . . . . . . . . . . . . . . . . . . . . . . . . . 27 6. Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . 28 6.1. Any Member with Any Value . . . . . . . . . . . . . . . . 28 6.2. Lists of Values . . . . . . . . . . . . . . . . . . . . . 29 6.3. Groups in Arrays . . . . . . . . . . . . . . . . . . . . 29 6.4. Groups in Objects . . . . . . . . . . . . . . . . . . . . 30 6.5. Group Rules as Macros . . . . . . . . . . . . . . . . . . 31 6.6. Object Mixins . . . . . . . . . . . . . . . . . . . . . . 31 6.7. Subordinate Dependencies . . . . . . . . . . . . . . . . 31 7. Implementation Status . . . . . . . . . . . . . . . . . . . . 32 7.1. JCR Validator . . . . . . . . . . . . . . . . . . . . . . 32 7.2. Codalogic JCR Parser . . . . . . . . . . . . . . . . . . 33 7.3. JCR Java . . . . . . . . . . . . . . . . . . . . . . . . 33 8. ABNF Syntax . . . . . . . . . . . . . . . . . . . . . . . . . 33 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 39 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 39 10.1. Normative References . . . . . . . . . . . . . . . . . . 39 10.2. Infomative References . . . . . . . . . . . . . . . . . 40 10.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Newton & Cordell Expires April 1, 2018 [Page 2] Internet-Draft JSON Content Rules September 2017 Appendix A. Co-Constraints . . . . . . . . . . . . . . . . . . . 40 Appendix B. Testing Against JSON Content Rules . . . . . . . . . 41 B.1. Locally Overriding Rules . . . . . . . . . . . . . . . . 41 B.2. Rule Callbacks . . . . . . . . . . . . . . . . . . . . . 42 Appendix C. Changes from -07 and -08 . . . . . . . . . . . . . . 42 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 42 1. Introduction This document describes JSON Content Rules (JCR), a language for specifying and testing the interchange of data in JSON [RFC7159] format used by computer protocols and processes. The syntax of JCR is not JSON but is "JSON-like", possessing the conciseness and utility that has made JSON popular. 1.1. A First Example: Specifying Content The following JSON data describes a JSON object with two members, "line-count" and "word-count", each containing an integer. { "line-count" : 3426, "word-count" : 27886 } Figure 1 This is also JCR that describes a JSON object with a member named "line-count" that is an integer that is exactly 3426 and a member named "word-count" that is an integer that is exactly 27886. For a protocol specification, it is probably more useful to specify that each member is any integer and not specific, exact integers: { "line-count" : integer, "word-count" : integer } Figure 2 Since line counts and word counts should be either zero or a positive integer, the specification may be further narrowed: { "line-count" : 0.. , "word-count" : 0.. } Figure 3 1.2. A Second Example: Testing Content Building on the first example, this second example describes the same object but with the addition of another member, "file-name". Newton & Cordell Expires April 1, 2018 [Page 3] Internet-Draft JSON Content Rules September 2017 { "file-name" : "rfc7159.txt", "line-count" : 3426, "word-count" : 27886 } Figure 4 The following JCR describes objects like it. { "file-name" : string, "line-count" : 0.., "word-count" : 0.. } Figure 5 For the purposes of writing a protocol specification, JCR may be broken down into named rules to reduce complexity and to enable re- use. The following example takes the JCR from above and rewrites the members as named rules. { $fn, $lc, $wc } $fn = "file-name" : string $lc = "line-count" : 0.. $wc = "word-count" : 0.. Figure 6 With each member specified as a named rule, software testers can override them locally for specific test cases. In the following example, the named rules are locally overridden for the test case where the file name is "rfc4627.txt". $fn = "file-name" : "rfc4627.txt" $lc = "line-count" : 2102 $wc = "word-count" : 16714 Figure 7 Newton & Cordell Expires April 1, 2018 [Page 4] Internet-Draft JSON Content Rules September 2017 In this example, the protocol specification describes the JSON object in general and an implementation overrides the rules for testing specific cases. All figures used in this specification are available here [1]. 2. Overview of the Language JCR is composed of rules (as the name suggests). A collection of rules that is processed together is a ruleset. Rulesets may also contain comments, blank lines, and directives that apply to the processing of a ruleset. Rules are composed of two parts, an optional rule name and a rule specification. A rule specification can be either a type specification or a member specification. A member specification consists of a member name specification and a type specification. A type specification is used to specify constraints on a superset of a JSON value (e.g. number / string / object / array etc.). In addition to defining primitive types (such as string or integer), array types, and object types, type specifications may define the JCR specific concept of group types. Type specifications corresponding to arrays, objects and groups may be composed of other rule specifications. A member specification is used to specify constraints on a JSON member (i.e. members of a JSON object). Rules with rule name assignments may be referenced in place of type specifications and member specifications. Rules may be defined across line boundaries and there is no line continuation syntax. Any rule consisting only of a type specification is considered a root rule. Unless otherwise specified, all the root rules of a ruleset are evaluated against a JSON instance or document. Putting it all together, Figure 9 describes the JSON in Figure 8. Newton & Cordell Expires April 1, 2018 [Page 5] Internet-Draft JSON Content Rules September 2017 Example JSON shamelessly lifted from RFC 4627 { "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] } } Figure 8 Newton & Cordell Expires April 1, 2018 [Page 6] Internet-Draft JSON Content Rules September 2017 Rules describing Figure 8 ; the root of the JSON instance is an object ; this root rule describes that object { ; the object specification contains ; one member specification "Image" : { ; $width and $height are defined below $width, $height, ; "Title" member specification "Title" :string, ; "Thumbnail" member specification, which ; defines an object "Thumbnail": { ; $width and $height are re-used again $width, $height, "Url" :uri }, ; "IDs" member that is an array of ; one ore more integers "IDs" : [ integer * ] } } ; The definitions of the rules $width and $height $width = "Width" : 0..1280 $height = "Height" : 0..1024 Figure 9 3. Lines and Comments There is no statement terminator and therefore no need for a line continuation syntax. Rules may be defined across line boundaries. Blank lines are allowed. Newton & Cordell Expires April 1, 2018 [Page 7] Internet-Draft JSON Content Rules September 2017 Comments are the same as comments in ABNF [RFC4234]. They start with a semi-colon (';') and continue to the end of the line. 4. Rules Rules have two main components, an optional rule name assignment and a type or member specification. Type specifications define arrays, objects, etc... of JSON and may reference other rules using rule names. Most type specifications can be defined with repetitions for specifying the frequency of the type being defined. In addition to the type specifications describing JSON types, there is an additional group specification for grouping types. Member specifications define members of JSON objects, and are composed of a member name specification and either a type specification or a rule name referencing a type specification. Rules may also contain annotations which may affect the evaluation of all or part of a rule. Rules without a rule name assignment are considered root rules, though rules with a rule name assignment can be considered a root rule with the appropriate annotation. Type specifications, depending on their type, can contain zero or more other specifications or rule names. For example, an object specification might contain multiple member specifications or rule names that resolve to member specifications or a mixture of member specifications and rule names. For the purposes of this document, specifications and rule names composing other specifications are called subordinate components. 4.1. Rule Names and Assignments Rule names are signified with the dollar character ('$'), which is not part of the rule name itself. Rule names have two components, an optional ruleset identifier alias and a local rule name. Local 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 ('_'). Local rule names are case sensitive, and must be unique within a ruleset (that is, no two rule name assignments may use the same local rule name). Ruleset identifier aliases enable referencing rules from another ruleset. They are not allowed in rule name assignments, and only found in rule names referencing other rules. Ruleset identifiers Newton & Cordell Expires April 1, 2018 [Page 8] Internet-Draft JSON Content Rules September 2017 must start with an alphabetic character and contain no whitespace. Ruleset identifiers are case sensitive. Simple use cases of JCR will most likely not use ruleset identifiers. In Figure 10 below, "http://ietf.org/rfcYYYY.JCR" and "http://ietf.org/rfcXXXX.JCR" are ruleset identifiers and "rfcXXXX" is a ruleset identifier alias. # ruleset-id http://ietf.org/rfcYYYY.JCR # import http://ietf.org/rfcXXXX.JCR as rfcXXXX $my_encodings = ( "mythic" | "magic" ) $all_encodings = ( $rfcXXXX.encodings | $my_encodings ) Figure 10 There are two forms of rule name assignments: assignments of primitive types and assignments of all other types. Rule name assignments to primitive type specifications separate the rule name from the type specification with the character sequence '=:', whereas rule name assignments for all other type specifications only require the separation using the '=' character. ;rule name assignments for primitive types $foo =: "foo" $some_string =: string ;rule name assignments for arrays $bar = [ integer, integer, integer ] ;rule name assignement for objects $bob = { "bar" : $bar, "foo" : $foo } Figure 11 This is the one little "gotcha" in JCR. This syntax is necessary so that JCR parsers may readily distinguish between rule name assignments involving string and regular expressions primitive types and member names of member specifications. 4.2. Annotations Annotations may appear before a rule name assignment, before a type or member specification, or before a rule name contained within a type specification. In each place, there may be zero or more annotations. Each annotation begins with the character sequence "@{" and ends with "}". The following is an example of a type specification with the not annotation (explained in Section 4.14): Newton & Cordell Expires April 1, 2018 [Page 9] Internet-Draft JSON Content Rules September 2017 @{not} [ "fruits", "vegatables" ] Figure 12 This specification defines the annotations "root", "not", and "unordered", but other annotations may be defined for other purposes. 4.3. Starting Points and Root Rules Evaluation of a JSON instance or document against a ruleset begins with the evaluation of a root rule or set of root rules. If no root rule (or rules) is specified locally at runtime, the set of root rules specified in the ruleset are evaluated. The order of evaluation is undefined. The set of root rules specified in a ruleset is composed of all rules without a rule name assignment and all rules annotated with the "@{root}" annotation. The "@{root}" annotation may either appear before a rule name assignment or before a type definition. It is ignored if present before referenced rule name inside of a type specification. 4.4. Type Specifications The syntax of each type of type specifications varies depending on the type: Newton & Cordell Expires April 1, 2018 [Page 10] Internet-Draft JSON Content Rules September 2017 ; primitive types can be string ; or number literals ; or number ranges "foo" 2 1..10 ; primitive types can also be more generalized types string integer ; primitive type rules may be named $my_int =: 12 ; member specifications consist of a member name ; followed by a colon and then followed by another ; type specification or a rule name ; (example shown with a rule name assignment) $mem1 = "bar" : "baz" $mem2 = "fizz" : $my_int ; member names may either be quoted strings ; or regular expressions ; (example shown with a rule name assignment) $mem3 = /^dev[0-9]$/ : 0..4096 ; object specifications start and end with "curly braces" ; object specifications contain zero ; or more member specifications ; or rule names which reference a member specification { $mem1, "foo" : "fuzz", "fizz" : $my_int } ; array specifications start and end with square brackets ; array specifications contain zero ; or more non-member type specifications [ 1, 2, 3, $my_int ] ; finally, group specifications start and end with parenthesis ; groups contain other type specifications ( [ integer, integer], $rule1 ) $rule1 = [ string, string ] Figure 13 Newton & Cordell Expires April 1, 2018 [Page 11] Internet-Draft JSON Content Rules September 2017 4.5. Primitive Specifications Primitive type specifications define content for JSON numbers, booleans, strings, and null. 4.5.1. Numbers, Booleans and Null The rules for booleans and null are the simplest and take the following forms: true false boolean null Figure 14 Rules for numbers can specify the number be either an integer or floating point number: integer float double Figure 15 The keyword 'float' represents a single precision IEEE-754 floating point number represented in decimal. The keyword 'double' represents a double precision IEEE-754 floating point number represented in decimal format. Numbers may also be specified as an absolute value or a range of possible values, where a range may be specified using a minimum, maximum, or both: n n..m ..m n.. n.f n.f..m.f ..m.f n.f.. Figure 16 When specifying a minimum and a maximum, both must either be an integer or a floating point number. Thus to specify a floating point Newton & Cordell Expires April 1, 2018 [Page 12] Internet-Draft JSON Content Rules September 2017 number between zero and ten a definition of the following form is used: 0.0..10.0 Figure 17 Integers may also be specified as ranges using bit lengths preceded by the 'int' or 'uint' words (i.e. 'int8', 'uint16'). The 'int' prefix specifies the integer as being signed whereas the 'uint' prefix specifies the integer as being unsigned. ; 0..255 uint8 ; -32768..32767 int16 ; 0..65535 uint16 ; -9223372036854775808..9223372036854775807 int64 ; 0..18446744073709551615 uint64 Figure 18 4.5.2. Strings JCR provides a large number of data types to define the contents of JSON strings. Generically, a string may be specified using the word 'string'. String literals may be specified using a double quote character followed by the literal content followed by another double quote. And regular expressions may be specified by enclosing a regular expression within the forward slash ('/') character. Newton & Cordell Expires April 1, 2018 [Page 13] Internet-Draft JSON Content Rules September 2017 ; any string string ; a string literal "she sells sea shells" ; a regular expression /^she sells .*/ Figure 19 Regular expressions are not implicitly anchored and therefore must be explicitly anchored if necessary. A string can be specified as a URI [RFC3986] using the word 'uri', but also may be more narrowly scoped to a URI of a specific scheme. Specific URI schemes are specified with the word 'uri' followed by two period characters ('..') followed by the URI scheme. ; any URI uri ;a URI narrowed for an HTTPS uri uri..https Figure 20 IP addresses may be specified with either the word 'ipv4' for IPv4 addresses [RFC1166] or the word 'ipv6' for IPv6 addresses [RFC5952]. Fully qualified A-label and U-label domain names may be specified with the words 'fqdn' and 'idn'. Dates and time can be specified as formats found in RFC 3339 [RFC3339]. The word 'date' corresponds to the full-date ABNF rule, the word 'time' corresponds to the full-time ABNF rule, and the word 'datetime' corresponds to the 'date-time' ABNF rule. Email addresses formatted according to RFC 5322 [RFC5322] may be specified using the 'email' word, and E.123 phone numbers may be specified using the word 'phone'. Newton & Cordell Expires April 1, 2018 [Page 14] Internet-Draft JSON Content Rules September 2017 ;IP addresses ipv4 ipv6 ipaddr ;domain names fqdn idn ; RFC 3339 full-date date ; RFC 3339 full-time time ; RFC 3339 date-time datetime ; RFC 5322 email address email ; phone number phone Figure 21 Binary data can be specified in string form using the encodings specified in RFC 4648 [RFC4648]. The word 'hex' corresponds to base16, while 'base32', 'base32hex', 'base64', and 'base64url' correspond with their RFC 4648 counterparts accordingly. ; RFC 4648 base16 hex ; RFC 4648 base32 base32 ; RFC 4648 base32hex base32hex ; RFC 4648 base64 base64 ; RFC 4648 base64url base64url Figure 22 Newton & Cordell Expires April 1, 2018 [Page 15] Internet-Draft JSON Content Rules September 2017 4.6. Any Type It is possible to specify that a value can be of any type allowable by JSON using the word 'any'. The 'any' type specifies any primitive type, array, or object. 4.7. Member Specifications Member specifications define members of JSON objects. Unlike other type specifications, member specifications cannot be root rules and must be part of an object specification or preceded by a rule name assignment. Member specifications consist of a member name specification followed by a colon character (':') followed by either a subordinate component, which is either a rule name or a primitive, object, array, or group specification. Member name specifications can be given either as a quoted string using double quotes or as a regular expression using forward slash ('/') characters. Regular expressions are not implicitly anchored and therefore must have explicit anchors if needed. ;member name will exactly match "locationURI" $location_uri = "locationURI" : uri ;member name will match "eth0", "eth1", ... "eth9" $iface_mappings = /^eth[0-9]$/ : ipv4 Figure 23 4.8. Object Specifications Object specifications define JSON objects and are composed of zero or more subordinate components, each of which can be either a rule name, member specification, or group specification. The subordinate components are enclosed at the start with a left curly brace character ('{') and at the end with a right curly brace character ('}'). Evaluation of the subordinate components of object specifications is as follows: o No order is implied for the members of the object being evaluated. o Subordinate components of the object specification are evaluated in the order they appear. Newton & Cordell Expires April 1, 2018 [Page 16] Internet-Draft JSON Content Rules September 2017 o Each member of the object being evaluated can only match one subordinate component. o Any members not matched against a subordinate component are ignored. The following examples illustrate matching of JSON objects to JCR object specifications. As order is not implied for the members of objects under evaluation, the following rule will match the JSON in Figure 25 and Figure 26. { "locationUri" : uri, "statusCode" : integer } Figure 24 { "locationUri" : "http://example.com", "statusCode" : 200 } Figure 25 { "statusCode" : 200, "locationUri" : "http://example.com" } Figure 26 Newton & Cordell Expires April 1, 2018 [Page 17] Internet-Draft JSON Content Rules September 2017 Because subordinate components of an object specification are evaluated in the order in which they are specified (i.e. left to right, top to bottom) and object members can only match one subordinate component of an object specification, the rule o1 below will not match against the JSON in Figure 28 but the rule o2 below will match it. ; zero or more members that match "p0", "p1", etc ; and a member that matches "p1" $o1 = { /^p\d+$/ : integer *, "p1" : integer } ; a member that matches "p1" and ; zero or more members that match "p0", "p1", etc $o2 = { "p1" : integer, /^p\d+$/ : integer * } The first subordinate of rule o1 specifies that an object can have zero or more members (that is the meaning of "*", see Section 4.13) where the member name is the letter 'p' followed by a number (e.g. "p0", "p1", "p2"), and the second rule specifies a member with the exact member name of "p1". Rule o2 has the exact same member specifications but in the opposite order. Figure 28 does not match rule o1 because all of the members match the first subordinate rule leaving none to match the second subordinate rule. However, rule o2 does match because the first subordinate rule matches only one member of the JSON object allowing the second subordinate rule to match the other member of the JSON object. Figure 27 { "p0" : 1, "p1" : 2 } Figure 28 As stated above, members of objects which do not match a rule are ignored. The reason for this validation model is due to the nature of the typical access model to JSON objects in many programming languages, where members of the object are obtained by referencing the member name. Therefore extra members may exist without harm. However, some specifications may need to restrict the members of a JSON object to a known set. To construct a rule specifying that no extra members are expected, the @{not} annotation (see Section 4.14) may be used with a "match-all" regular expression as the last subordinate component of the object specification. Newton & Cordell Expires April 1, 2018 [Page 18] Internet-Draft JSON Content Rules September 2017 The following rule will match the JSON object in Figure 30 but will not match the JSON object in Figure 31. { "foo" : 1, "bar" : 2, @{not} // : any + } Figure 29 { "foo" : 1, "bar" : 2 } Figure 30 { "foo" : 1, "bar" : 2, "baz" : 3 } Figure 31 This works because subordinate components are evaluated in the order they appear in the object rule, and the last component accepts any member with any type but fails to validate if one or more of those components are found due to the @{not} annotation. 4.9. Array Specifications Array specifications define JSON arrays and are composed of zero or more subordinate components, each of which can either be a rule name or a primitive, array, object or group specification. The subordinate components are enclosed at the start with a left square brace character ('[') and at the end with a right square brace character (']'). Evaluation of the subordinate components of array specifications is as follows: o The order of array items is implied unless the @{unordered} annotation is present. o Subordinate components of the array specification are evaluated in the order they appear. o Each item of the array being evaluated can only match one subordinate component of the array specification. o If any items of the array are not matched, then the array does not match the array specification. These rules are further explained in the examples below. Newton & Cordell Expires April 1, 2018 [Page 19] Internet-Draft JSON Content Rules September 2017 [ 0..1024, 0..980 ] Figure 32 Unlike object specifications, order is implied in array specifications by default. That is, the first subordinate component will match the first element of the array, the second subordinate component will match the second element of the array, and so on. Take for example the following ruleset: ; the first element of the array is to be a string ; the second element of the array is to be an integer $a1 = [ string, integer ] ; the first element of the array is to be an integer ; the second element of the array is to be a string $a2 = [ integer, string ] Figure 33 It defines two rules, a1 and a2. The array in the following JSON will not match a1, but will match a2. [ 24, "Bob Smurd" ] Figure 34 If an array has more elements than can be matched from the array specification, the array does not match the array specification. Or stated differently, an array with unmatched elements does not validate. Using the example array rule a2 from above, the following array does not match because the last element of the array does not match any subordinate component: [ 24, "Bob Smurd", "http://example.com/bob_smurd" ] Figure 35 To allow an array to contain any value after guaranteeing that it contains the necessary items, the last subordinate component of the array specification should accept any item: Newton & Cordell Expires April 1, 2018 [Page 20] Internet-Draft JSON Content Rules September 2017 ; the first element of the array is to be an integer ; the second element of the array is to be a string ; anything else can follow $a3 = [ integer, string, any * ] The JSON array in Figure 35 will validate against the a3 rule in this example. Figure 36 4.9.1. Unordered Array Specifications Array specifications can be made to behave in a similar fashion to object specifications with regard to the order of matching with the @{unordered} annotation. In the ruleset below, a1 and a2 have the same subordinate components given in the same order. a2 is annotated with the @{unordered} annotation. $a1 = [ string, integer ] $a2 = @{unordered} [ string, integer ] Figure 37 The JSON array below does not match a1 but does match a2. [ 24, "Bob Smurd" ] Figure 38 Like ordered array specifications, the subordinate components in an unordered array specification are evaluated in the order they are specified. The difference is that they need not match an element of the array in the same position as given in the array specification. Finally, like ordered array specifications, unordered array specifications also require that all elements of the array be matched by a subordinate component. If the array has more elements than can be matched, the array does not match the array specification. 4.10. Group Specifications Unlike the other type specifications, group specifications have no direct tie with JSON syntax. Group specifications simply group together their subordinate components. Group specifications enclose one or more subordinate components with the parenthesis characters. Newton & Cordell Expires April 1, 2018 [Page 21] Internet-Draft JSON Content Rules September 2017 Group specifications and any nesting of group specifications, must conform to the allowable set of type specifications of the type specifications in which they are contained. For example, a group specification inside of an array specification may not contain a member specification since member specifications are not allowed as direct subordinates of array specifications (arrays contain values, not object members in JSON). Likewise, a group specification referenced inside an object specification must only contain member specifications (JSON objects may only contain object members). The following is an example of a group specification: $the_bradys = [ $parents, $children ] $children = ( "Greg", "Marsha", "Bobby", "Jan" ) $parents = ( "Mike", "Carol" ) Figure 39 Like the subordinate components of array and object specifications, the subordinate components of a group specification are evaluated in the order they appear. 4.11. Ordered and Unordered Groups in Arrays Section 4.9.1 specifies that arrays can be evaluated by the order of the items in the array or can be evaluated without order. Section 4.10 specifies that arrays may have group rules as subordinate components. The evaluation of a group specification inside an array specification inherits the ordering property of the array specification. If the array specification is unordered, then the items of the group specification are also considered to be unordered. And if the array specification is ordered, then the items of the group specification are also considered to be ordered. 4.12. Sequence and Choice Combinations in Array, Object, and Group Specifications Combinations of subordinate components in array, object, and group specifications can be specified as either a sequence ("and") or a choice ("or"). A sequence is a subordinate component followed by the comma character (',') followed by another subordinate component. A choice is a subordinate component followed by a pipe character ('|') followed by another subordinate component. Newton & Cordell Expires April 1, 2018 [Page 22] Internet-Draft JSON Content Rules September 2017 ; sequence ("and") [ "this" , "that" ] ; choice ("or") [ "this" | "that" ] Figure 40 Sequence and choice combinations cannot be mixed, and group specifications must be used to explicitly declare precedence between a sequence and a choice. Therefore, the following is illegal: [ "this", "that" | "the_other" ] Figure 41 The example above should be expressed as: [ "this", ( "that" | "the_other" ) ] Figure 42 NOTE: A future specification will clarify the choice ('|') operation as inclusive or, exclusive or ("xor") or otherwise. At present readers should assume the choice ('|') operator is an inclusive or. However, for objects and unordered arrays that is not ideal, nor is xor. We are in the process of defining an algorithm to "rewrite" choices of rules for use with inclusive or which is more suitable for the data model of JSON. 4.13. Repetition in Array, Object, and Group Specifications Evaluation of subordinate components in array, object, and group specifications may be succeeded by a repetition expression denoting how many times the subordinate component should be evaluated. Repetition expressions are specified using a Kleene symbol ('?', '+', or '*') or with the '*' symbol succeeded by specific minimum and/or maximum values, each being non-negative integers. Repetition expressions may also be appended with a step expression, which is the '%' symbol followed by a positive integer. When no repetition expression is present, both the minimum and maximum are 1. A minimum and maximum can be expressed by giving the minimum followed by two period characters ('..') followed by the maximum, with either the minimum or maximum being optional. When the minimum is not Newton & Cordell Expires April 1, 2018 [Page 23] Internet-Draft JSON Content Rules September 2017 explicitly specified, it is assumed to be zero. When the maximum is not explicitly specified, it is assumed to be positive infinity. ; exactly 2 octets $word = [ $octet *2 ] $octet =: int8 ; 1 to 13 name servers [ $name_servers *1..13 ] $name_servers =: fqdn ; 0 to 99 ethernet addresses { /^eth.*/ : $mac_addr *..99 } $mac_addr =: hex ; four or more bytes [ $octet *4.. ] Figure 43 The allowable Kleene operators are the question mark character ('?') which specifies zero or one (i.e. optional), the plus character ('+') which specifies one or more, and the asterisk character ('*') which specifies zero or more. ; age is optional { "name" : string, "age" : integer ? } ; zero or more errors $error_set = ( string * ) ; 1 or more integer values [ integer + ] Figure 44 A repetition step expression may follow a minimum to maximum expression or the zero or more Kleene operator or the one or more Kleene operator. o When the repetition step follows a minimum to maximum expression or the zero or more Kleene operator ('*'), it specifies that the total number of repetitions present in the JSON instance being validated minus the minimum repetition value must be a multiple of the repetition step (e.g. the total repetitions minus the minimum repetition value must be divisible by the step value with a remainder of zero). Newton & Cordell Expires April 1, 2018 [Page 24] Internet-Draft JSON Content Rules September 2017 o When the repetition step follows a one or more Kleene operator ('+'), the minimum repetition value is set equal to the repetition step value and the total number of repetitions minus the step value must be a multiple of the repetition step value. The following is an example for repetition steps in repetition expressions. ; there must be at least 2 name servers ; there may be no more than 12 name servers ; there must be an even number of name servers ; e.g. 2,4,6,8,10,12 [ $name_servers *2..12%2 ] $name_servers =: fqdn ; minimum is zero ; maximum is 100 ; must be an even number { /^eth.*/ : $mac_addr *..100%2 } $mac_addr =: hex ; at least 32 octets ; must be be in groups of 16 ; e.g. 32, 48, 64 etc [ $octet *32..%16 ] $octet =: int8 ; if there are to be error sets, ; their number must be divisible by 4 ; e.g. 0, 4, 8, 12 etc $error_set = ( string *%4 ) ; Throws of a pair of dice must be divisible by 2 ; e.g. 2, 4, 6 etc $dice_throws = ( 1..6 +%2 ) Figure 45 4.14. Negating Evaluation The evaluation of a rule can be changed with the @{not} annotation. With this annotation, a rule that would otherwise match does not, and a rule that would not have matched does. Newton & Cordell Expires April 1, 2018 [Page 25] Internet-Draft JSON Content Rules September 2017 ; match anything that isn't the integer 2 $not_two = [ @{not} 2 ] ; error if one of the status values is "fail" $status = @{not} @{unordered} [ "fail", string * ] Figure 46 5. Directives Directives modify the processing of a ruleset. There are two forms of the directive, the single line directive and the multi-line directive. Single line directives appear on their own line in a ruleset, begin with a hash character ('#') and are terminated by the end of the line. They take the following form: # directive_name parameter_1 parameter_2 ... Figure 47 Multi-line directives also appear on their own lines, but may span multiple lines. They begin with the character sequence "#{" and end with "}". The take the following form: #{ directive_name parameter_1 paramter_2 parameter_3 ... } Figure 48 This specification defines the directives "jcr-version", "ruleset- id", and "import", but other directives may be defined. 5.1. jcr-version This directive declares that the ruleset complies with a specific version of this standard. The version is expressed as a major integer followed by a period followed by a minor integer. # jcr-version 0.7 Figure 49 Newton & Cordell Expires April 1, 2018 [Page 26] Internet-Draft JSON Content Rules September 2017 The major.minor number signifying compliance with this document is "0.7". Upon publication of this specification as an IETF proposed standard, it will be "1.0". # jcr-version 1.0 Figure 50 Ruleset authors are advised to place this directive as the first line of a ruleset. This directive may have optional extension identifiers following the version number. Each extension identifiers is preceded by the plus ('+') character and separated by white space. The format of extension identifiers is specific to the extension, but it is recommended that they are terminated by a version number. # jcr-version 1.0 +co-constraints-1.2 +jcr-doc-1.0 Figure 51 5.2. ruleset-id This directive identifies a ruleset to rule processors. It takes the form: # ruleset-id identifier Figure 52 An identifier can be a URL (e.g. http://example.com/foo), an inverted domain name (e.g. com.example.foo) or any other form that conforms to the JCR ABNF syntax that a ruleset author deems appropriate. To a JCR processor the identifier is treated as an opaque, case-sensitive string. 5.3. import The import directive specifies that another ruleset is to have its rules evaluated in addition to the ruleset where the directive appears. The following is an example: # import http://example.com/rfc9999 as rfc9999 Figure 53 Newton & Cordell Expires April 1, 2018 [Page 27] Internet-Draft JSON Content Rules September 2017 The rule names of the ruleset to be imported may be referenced by prepending the alias followed by a period character ('.') followed by the rule name (i.e. "alias.name"). To continue the example above, if the ruleset at http://example.com/rfc9999 were to have a rule named 'encoding', rules in the ruleset importing it can refer to that rule as 'rfc9999.encoding'. 6. Tips and Tricks 6.1. Any Member with Any Value Because member names may be specified with regular expressions, it is possible to construct a member rule that matches any member name. As an example, the following defines an object with a member with any name that has a value that is a string: { // : string } Figure 54 The JSON below matches the above rule. { "foo" : "bar" } Figure 55 Likewise, the JSON below also matches the same rule. { "fuzz" : "bazz" } Figure 56 Constructing an object with a member of any name with any type would therefore take the form: { // : any } Figure 57 The above rule matches not only the two JSON objects above, but the JSON object below. { "fuzz" : 1234 } Figure 58 Newton & Cordell Expires April 1, 2018 [Page 28] Internet-Draft JSON Content Rules September 2017 6.2. Lists of Values Group specifications may be used to create enumerated lists of primitive data types, because primitive specifications may contain a group specification, which may have multiple primitive specifications. Because a primitive specification must resolve to a single data type, the group specification must only contain choice combinations. Consider the following examples: ; either an IPv4 or IPv6 adress $address =: ( ipv4 | ipv6 ) ; allowable fruits $fruits =: ( "apple" | "banana" | "pear" ) Figure 59 6.3. Groups in Arrays Groups may be a subordinate component of array specifications: [ ( ipv4 | ipv6 ), integer ] Figure 60 Unlike primitive specifications, subordinate group specifications in array specifications may have sequence combinations and contain any type specification. ; a group in an array [ ( $first_name, $middle_name ?, $last_name ), $age ] ; a group referenced from an array [ $name, $age ] $name = ( $first_name, $middle_name ?, $last_name ) $first_name =: string $middle_name =: string $last_name =: string $age =: 0.. Figure 61 Newton & Cordell Expires April 1, 2018 [Page 29] Internet-Draft JSON Content Rules September 2017 6.4. Groups in Objects Groups may be a subordinate component of object specifications: Subordinate group specifications in object specifications may have sequence combinations but must only contain member specifications. ; a group in an object { ( $title, $date, $author ), $paragraph + } ; a group referenced from an object { $front_matter, $paragraph + } $front_matter = ( $title, $date, $author ) $title = "title" : string $date = "date" : date $author = "author" : [ string * ] $paragraph = /p[0-9]*/ : string Figure 62 NOTE: A future specification will clarify the choice ('|') operation as inclusive or, exclusive or ("xor") or otherwise. At present readers should assume the choice ('|') operator is an inclusive or. We are in the process of defining an algorithm to "rewrite" choices of rules for use with inclusive or which is more suitable for the data model of JSON. Such a change will impact the guidance given below. When using groups to use both sequences and choices of member specifications, consideration must be given to the processing of object specifications where by unmatched member specifications are ignored (see Figure 23). A casual reading of this rule might lead a reader to believe that the JSON object in Figure 64 would not match, however it does because the extra member (either "foo" or "baz") is not matched but is ignored. { "bar":string, ( "foo":integer | "baz":string ) } Figure 63 { "bar":"thing", "foo":2, "baz": "thingy" } Figure 64 The rule in Figure 63 must be modified to either match all extra rules, as in Figure 65, or the logic of the rules must be rewritten Newton & Cordell Expires April 1, 2018 [Page 30] Internet-Draft JSON Content Rules September 2017 to explicitly negate the presence of the unwanted members, as in Figure 66. { "bar":string, ( "foo":integer | "baz":string ), @{not} //:any + } Figure 65 { "bar":string, ( ( "foo":integer , @{not} "baz":string ) | ( "baz":string , @{not} "foo":integer ) ) } Figure 66 6.5. Group Rules as Macros The syntax for group specifications accommodates one ore more subordinate components and a repetition expression for each. Other than grouping multiple rules, a group specification can be used as a macro definition for a single rule. $paragraphs = ( /p[0-9]*/ : string + ) Figure 67 6.6. Object Mixins Group rules can be used to create object mixins, a pattern for writing data models similar in style to object derivation in some programming languages. In the example in below, both obj1 and obj2 have a members "foo" and "fob" with obj1 having the additional member "bar" and obj2 having the additional member "baz". $mixin_group = ( "foo" : integer, "fob" : uri ) $obj1 = { $mixin_group, "bar" : string } $obj2 = { $mixin_group, "baz" : string } Figure 68 6.7. Subordinate Dependencies In object and array specifications, there may be situations in which it is necessary to condition the existence of a subordinate component on the existence of a sibling subordinate component. In other words, example_two should only be evaluated if example_one evaluates positively. Or put another way, a member of an object or an item of Newton & Cordell Expires April 1, 2018 [Page 31] Internet-Draft JSON Content Rules September 2017 an array may be present only on the condition that another member or item is present. In the following example, the referrer_uri member can only be present if the location_uri member is present. ; $referrer_uri can only be present if ; $location_uri is present { ( $location_uri, $referrer_uri? )? } $location_uri = "locationURI" : uri $referrer_uri = "referrerURI" : uri Figure 69 7. Implementation Status This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in [RFC7492] . The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist. According to [RFC7492] , "this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit". 7.1. JCR Validator The JCR Validator, written in Ruby, currently implements all portions of this specification, and has been used extensively to prototype various aspects of JCR under consideration. It's development has gone hand-in-hand with this specification. This software is primarily produced by the American Registry for Internet Numbers (ARIN) and freely distributable under the ISC license. Newton & Cordell Expires April 1, 2018 [Page 32] Internet-Draft JSON Content Rules September 2017 Source code for this software is available on GitHub at . This software is also easily obtained as a Ruby Gem through the Ruby Gem system. 7.2. Codalogic JCR Parser The Codalogic JCR Parser is a C++ implementation of a JCR parsing engine, and is a work in progress. It is targeted for the Windows platform. This software is produced by Codalogic Ltd and freely distributable under the Gnu LGPL v3 license. Source code is availabe on GitHub at . 7.3. JCR Java JCR Java is a work in progress and currently only implements the parsing of JCR rulesets according to the ABNF using a custom parsing framework. This software is produced by the American Registry for Internet Numbers (ARIN) and freely distributable under the MIT license. Source code is available on BitBucket at . 8. ABNF Syntax The following ABNF describes the syntax for JSON Content Rules. A text file containing these ABNF rules can be downloaded from [JCR_ABNF]. jcr = *( sp-cmt / directive / root-rule / rule ) sp-cmt = spaces / comment spaces = 1*( WSP / CR / LF ) DSPs = ; Directive spaces 1*WSP / ; When in one-line directive 1*sp-cmt ; When in muti-line directive comment = ";" *comment-char comment-end-char comment-char = HTAB / %x20-10FFFF ; Any char other than CR / LF comment-end-char = CR / LF directive = "#" (one-line-directive / multi-line-directive) one-line-directive = [ DSPs ] Newton & Cordell Expires April 1, 2018 [Page 33] Internet-Draft JSON Content Rules September 2017 (directive-def / one-line-tbd-directive-d) *WSP eol multi-line-directive = "{" *sp-cmt ( directive-def / multi-line-tbd-directive-d ) *sp-cmt "}" directive-def = jcr-version-d / ruleset-id-d / import-d jcr-version-d = jcr-version-kw DSPs major-version "." minor-version *( DSPs "+" [ DSPs ] extension-id ) major-version = non-neg-integer minor-version = non-neg-integer extension-id = ALPHA *not-space ruleset-id-d = ruleset-id-kw DSPs ruleset-id import-d = import-kw DSPs ruleset-id [ DSPs as-kw DSPs ruleset-id-alias ] ruleset-id = ALPHA *not-space not-space = %x21-10FFFF ruleset-id-alias = name one-line-tbd-directive-d = directive-name [ WSP one-line-directive-parameters ] directive-name = name one-line-directive-parameters = *not-eol not-eol = HTAB / %x20-10FFFF eol = CR / LF multi-line-tbd-directive-d = directive-name [ 1*sp-cmt multi-line-directive-parameters ] multi-line-directive-parameters = multi-line-parameters multi-line-parameters = *(comment / q-string / regex / not-multi-line-special) not-multi-line-special = spaces / %x21 / %x23-2E / %x30-3A / %x3C-7C / %x7E-10FFFF ; not ", /, ; or } root-rule = value-rule / group-rule rule = annotations "$" rule-name *sp-cmt "=" *sp-cmt rule-def rule-name = name target-rule-name = annotations "$" [ ruleset-id-alias "." ] rule-name name = ALPHA *( ALPHA / DIGIT / "-" / "-" ) rule-def = member-rule / type-designator rule-def-type-rule / array-rule / object-rule / group-rule / target-rule-name type-designator = type-kw 1*sp-cmt / ":" *sp-cmt Newton & Cordell Expires April 1, 2018 [Page 34] Internet-Draft JSON Content Rules September 2017 rule-def-type-rule = value-rule / type-choice value-rule = primitive-rule / array-rule / object-rule member-rule = annotations member-name-spec *sp-cmt ":" *sp-cmt type-rule member-name-spec = regex / q-string type-rule = value-rule / type-choice / target-rule-name type-choice = annotations "(" type-choice-items *( choice-combiner type-choice-items ) ")" explicit-type-choice = type-designator type-choice type-choice-items = *sp-cmt ( type-choice / type-rule ) *sp-cmt annotations = *( "@{" *sp-cmt annotation-set *sp-cmt "}" *sp-cmt ) annotation-set = not-annotation / unordered-annotation / root-annotation / tbd-annotation not-annotation = not-kw unordered-annotation = unordered-kw root-annotation = root-kw tbd-annotation = annotation-name [ spaces annotation-parameters ] annotation-name = name annotation-parameters = multi-line-parameters primitive-rule = annotations primitive-def primitive-def = string-type / string-range / string-value / null-type / boolean-type / true-value / false-value / double-type / float-type / float-range / float-value / integer-type / integer-range / integer-value / sized-int-type / sized-uint-type / ipv4-type / ipv6-type / ipaddr-type / fqdn-type / idn-type / uri-type / phone-type / email-type / datetime-type / date-type / time-type / hex-type / base32hex-type / base32-type / base64url-type / base64-type / any null-type = null-kw boolean-type = boolean-kw true-value = true-kw false-value = false-kw string-type = string-kw string-value = q-string string-range = regex double-type = double-kw float-type = float-kw float-range = float-min ".." [ float-max ] / ".." float-max float-min = float float-max = float float-value = float integer-type = integer-kw Newton & Cordell Expires April 1, 2018 [Page 35] Internet-Draft JSON Content Rules September 2017 integer-range = integer-min ".." [ integer-max ] / ".." integer-max integer-min = integer integer-max = integer integer-value = integer sized-int-type = int-kw pos-integer sized-uint-type = uint-kw pos-integer ipv4-type = ipv4-kw ipv6-type = ipv6-kw ipaddr-type = ipaddr-kw fqdn-type = fqdn-kw idn-type = idn-kw uri-type = uri-kw [ ".." uri-scheme ] phone-type = phone-kw email-type = email-kw datetime-type = datetime-kw date-type = date-kw time-type = time-kw hex-type = hex-kw base32hex-type = base32hex-kw base32-type = base32-kw base64url-type = base64url-kw base64-type = base64-kw any = any-kw object-rule = annotations "{" *sp-cmt [ object-items *sp-cmt ] "}" object-items = object-item [ 1*( sequence-combiner object-item ) / 1*( choice-combiner object-item ) ] object-item = object-item-types *sp-cmt [ repetition *sp-cmt ] object-item-types = object-group / member-rule / target-rule-name object-group = annotations "(" *sp-cmt [ object-items *sp-cmt ] ")" array-rule = annotations "[" *sp-cmt [ array-items *sp-cmt ] "]" array-items = array-item [ 1*( sequence-combiner array-item ) / 1*( choice-combiner array-item ) ] array-item = array-item-types *sp-cmt [ repetition *sp-cmt ] array-item-types = array-group / type-rule / explicit-type-choice array-group = annotations "(" *sp-cmt [ array-items *sp-cmt ] ")" group-rule = annotations "(" *sp-cmt [ group-items *sp-cmt ] ")" group-items = group-item [ 1*( sequence-combiner group-item ) / 1*( choice-combiner group-item ) ] group-item = group-item-types *sp-cmt [ repetition *sp-cmt ] group-item-types = group-group / member-rule / type-rule / explicit-type-choice group-group = group-rule Newton & Cordell Expires April 1, 2018 [Page 36] Internet-Draft JSON Content Rules September 2017 sequence-combiner = "," *sp-cmt choice-combiner = "|" *sp-cmt repetition = optional / one-or-more / repetition-range / zero-or-more optional = "?" one-or-more = "+" [ repetition-step ] zero-or-more = "*" [ repetition-step ] repetition-range = "*" *sp-cmt ( min-max-repetition / min-repetition / max-repetition / specific-repetition ) min-max-repetition = min-repeat ".." max-repeat [ repetition-step ] min-repetition = min-repeat ".." [ repetition-step ] max-repetition = ".." max-repeat [ repetition-step ] min-repeat = non-neg-integer max-repeat = non-neg-integer specific-repetition = non-neg-integer repetition-step = "%" step-size step-size = non-neg-integer integer = "0" / ["-"] pos-integer non-neg-integer = "0" / pos-integer pos-integer = digit1-9 *DIGIT float = [ minus ] int frac [ exp ] ; From RFC 7159 except 'frac' required minus = %x2D ; - plus = %x2B ; + int = zero / ( digit1-9 *DIGIT ) digit1-9 = %x31-39 ; 1-9 frac = decimal-point 1*DIGIT decimal-point = %x2E ; . exp = e [ minus / plus ] 1*DIGIT e = %x65 / %x45 ; e E zero = %x30 ; 0 q-string = quotation-mark *char quotation-mark ; From RFC 7159 char = unescaped / escape ( %x22 / ; " quotation mark U+0022 %x5C / ; \ reverse solidus U+005C %x2F / ; / solidus U+002F %x62 / ; b backspace U+0008 %x66 / ; f form feed U+000C %x6E / ; n line feed U+000A %x72 / ; r carriage return U+000D Newton & Cordell Expires April 1, 2018 [Page 37] Internet-Draft JSON Content Rules September 2017 %x74 / ; t tab U+0009 %x75 4HEXDIG ) ; uXXXX U+XXXX escape = %x5C ; \ quotation-mark = %x22 ; " unescaped = %x20-21 / %x23-5B / %x5D-10FFFF regex = "/" *( escape "/" / not-slash ) "/" [ regex-modifiers ] not-slash = HTAB / CR / LF / %x20-2E / %x30-10FFFF ; Any char except "/" regex-modifiers = *( "i" / "s" / "x" ) uri-scheme = 1*ALPHA ;; Keywords any-kw = %x61.6E.79 ; "any" as-kw = %x61.73 ; "as" base32-kw = %x62.61.73.65.33.32 ; "base32" base32hex-kw = %x62.61.73.65.33.32.68.65.78 ; "base32hex" base64-kw = %x62.61.73.65.36.34 ; "base64" base64url-kw = %x62.61.73.65.36.34.75.72.6C ; "base64url" boolean-kw = %x62.6F.6F.6C.65.61.6E ; "boolean" date-kw = %x64.61.74.65 ; "date" datetime-kw = %x64.61.74.65.74.69.6D.65 ; "datetime" double-kw = %x64.6F.75.62.6C.65 ; "double" email-kw = %x65.6D.61.69.6C ; "email" false-kw = %x66.61.6C.73.65 ; "false" float-kw = %x66.6C.6F.61.74 ; "float" fqdn-kw = %x66.71.64.6E ; "fqdn" hex-kw = %x68.65.78 ; "hex" idn-kw = %x69.64.6E ; "idn" import-kw = %x69.6D.70.6F.72.74 ; "import" int-kw = %x69.6E.74 ; "int" integer-kw = %x69.6E.74.65.67.65.72 ; "integer" ipaddr-kw = %x69.70.61.64.64.72 ; "ipaddr" ipv4-kw = %x69.70.76.34 ; "ipv4" ipv6-kw = %x69.70.76.36 ; "ipv6" jcr-version-kw = %x6A.63.72.2D.76.65.72.73.69.6F.6E ; "jcr-version" not-kw = %x6E.6F.74 ; "not" null-kw = %x6E.75.6C.6C ; "null" phone-kw = %x70.68.6F.6E.65 ; "phone" root-kw = %x72.6F.6F.74 ; "root" ruleset-id-kw = %x72.75.6C.65.73.65.74.2D.69.64 ; "ruleset-id" string-kw = %x73.74.72.69.6E.67 ; "string" time-kw = %x74.69.6D.65 ; "time" true-kw = %x74.72.75.65 ; "true" type-kw = %x74.79.70.65 ; "type" uint-kw = %x75.69.6E.74 ; "uint" Newton & Cordell Expires April 1, 2018 [Page 38] Internet-Draft JSON Content Rules September 2017 unordered-kw = %x75.6E.6F.72.64.65.72.65.64 ; "unordered" uri-kw = %x75.72.69 ; "uri" ;; Referenced RFC 5234 Core Rules ALPHA = %x41-5A / %x61-7A ; A-Z / a-z CR = %x0D ; carriage return DIGIT = %x30-39 ; 0-9 HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" HTAB = %x09 ; horizontal tab LF = %x0A ; linefeed SP = %x20 ; space WSP = SP / HTAB ; white space Figure 70: ABNF for JSON Content Rules 9. Acknowledgements John Cowan, Andrew Biggs, Paul Kyzivat and Paul Jones provided feedback and suggestions which led to many changes in the syntax. 10. References 10.1. Normative References [JCR_ABNF] Newton, A. and P. Cordell, "ABNF for JSON Content Rules", . [RFC1166] Kirkpatrick, S., Stahl, M., and M. Recker, "Internet numbers", RFC 1166, DOI 10.17487/RFC1166, July 1990, . [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, . [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, . [RFC4234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 4234, DOI 10.17487/RFC4234, October 2005, . Newton & Cordell Expires April 1, 2018 [Page 39] Internet-Draft JSON Content Rules September 2017 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, . [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, DOI 10.17487/RFC5322, October 2008, . [RFC5952] Kawamura, S. and M. Kawashima, "A Recommendation for IPv6 Address Text Representation", RFC 5952, DOI 10.17487/RFC5952, August 2010, . [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 2014, . 10.2. Infomative References [I-D.cordell-jcr-co-constraints] Cordell, P. and A. Newton, "Co-Constraints for JSON Content Rules", draft-cordell-jcr-co-constraints-00 (work in progress), March 2016. [RFC7492] Bhatia, M., Zhang, D., and M. Jethanandani, "Analysis of Bidirectional Forwarding Detection (BFD) Security According to the Keying and Authentication for Routing Protocols (KARP) Design Guidelines", RFC 7492, DOI 10.17487/RFC7492, March 2015, . 10.3. URIs [1] https://github.com/arineng/jcr/tree/master/figs Appendix A. Co-Constraints This specification defines a small set of annotations and directives for JCR, yet the syntax is extensible allowing for other annotations and directives. [I-D.cordell-jcr-co-constraints] ("Co-Constraints for JCR") defines further annotations and directives which define more detailed constraints on JSON messages, including co-constraints (constraining parts of JSON message based on another part of a JSON message). Newton & Cordell Expires April 1, 2018 [Page 40] Internet-Draft JSON Content Rules September 2017 Appendix B. Testing Against JSON Content Rules One aspect of JCR that differentiates it from other format schema languages are the mechanisms helpful to developers for taking a formal specification, such as that found in an RFC, and evolving it into unit tests, which are essential to producing quality protocol implementations. B.1. Locally Overriding Rules As mentioned in the introduction, one tool for testing would be the ability to locally override named rules. As an example, consider the following rule which defines an array of strings. $statuses = [ string * ] Figure 71 Consider the specification where this rule is found does not define the values but references an extensible list of possible values updated independently of the specification, such as in an IANA registry. If a software developer desired to test a specific situation in which the array must at least contain the status "accepted", the rules from the specification could be used and the statuses rule could be explicitly overridden locally as: This rule will evaluate positively with the JSON in Figure 73 $statuses = @{unordered} [ "accepted", string * ] Figure 72 [ "submitted", "validated", "accepted" ] Figure 73 Alternatively, the developer may need to ensure that the status "denied" should not be present in the array: This rule will fail to evaluate the JSON in Figure 75 thus signaling a problem. $statuses = @{unordered} @{not} [ "denied" + , string * ] Figure 74 Newton & Cordell Expires April 1, 2018 [Page 41] Internet-Draft JSON Content Rules September 2017 [ "submitted", "validated", "denied" ] Figure 75 B.2. Rule Callbacks In many testing scenarios, the evaluation of rules may become more complex than that which can be expressed in JCR, sometimes involving variables and interdependencies which can only be expressed in a programming language. A JCR processor may provide a mechanism for the execution of local functions or methods based on the name of a rule being evaluated. Such a mechanism could pass to the function the data to be evaluated, and that function could return to the processor the result of evaluating the data in the function. Appendix C. Changes from -07 and -08 This revision of the document makes no substantive changes to any parts of the specification. Some of the ABNF has been updated to more correctly allow group rules, and other small change have been made to the ABNF to make it simpler. Authors' Addresses Andrew Lee Newton American Registry for Internet Numbers PO Box 232290 Centreville, VA 20120 US Email: andy@arin.net URI: http://www.arin.net Pete Cordell Codalogic PO Box 30 Ipswich IP5 2WY UK Email: pete.cordell@codalogic.com URI: http://www.codalogic.com Newton & Cordell Expires April 1, 2018 [Page 42]