JSON and JSON-Schema for XML Developers Roger L. Costello February 5, 2014 Approved for Public Release; Distribution Unlimited. Case Number 14-3179 © 2014 The MITRE Corporation. All rights reserved. |2| Trends in XML and JSON usage 80% XML 70% 60% 50% 40% JSON 30% 20% 10% 0% 2006 2007 2008 2009 2010 2011 2012 2013 Based on directory of 11,000 web APIs listed at Programmable Web, December 2013 Wow! I better have expertise in both XML and JSON © 2014 The MITRE Corporation. All rights reserved. |3| Specifications The JSON specification is here: – http://www.ecma-international.org/publications/files/ECMAST/ECMA-404.pdf There are two specifications for JSON-Schema – http://json-schema.org/latest/json-schema-core.html – http://json-schema.org/latest/json-schema-validation.html © 2014 The MITRE Corporation. All rights reserved. |4| Table of Contents Comparison of XML and JSON JSON JSON Schema © 2014 The MITRE Corporation. All rights reserved. |5| Viewing this Tutorial This tutorial is best viewed in slide show mode – Under the View menu select Slide Show Periodically you will see an icon at the bottom, right of the slide indicating that it is time to do a lab exercise. I strongly recommend that you stop and do the lab exercise to obtain the maximum benefit from this tutorial. © 2014 The MITRE Corporation. All rights reserved. |6| XML is a data format XML is a way of structuring data … XML is a data format. © 2014 The MITRE Corporation. All rights reserved. |7| JSON is a data format JSON is a way of structuring data … JSON is a data format. © 2014 The MITRE Corporation. All rights reserved. |8| Example of XML-formatted data The below XML document contains data about a book: its title, authors, date of publication, and publisher. <Book> <Title>Parsing Techniques</Title> <Authors> <Author>Dick Grune</Author> <Author>Ceriel J.H. Jacobs</Author> </Authors> <Date>2007</Date> <Publisher>Springer</Publisher> </Book> © 2014 The MITRE Corporation. All rights reserved. |9| Same data, JSON-formatted { "Book": { "Title": "Parsing Techniques", "Authors": [ "Dick Grune", "Ceriel J.H. Jacobs" ], "Date": "2007", "Publisher": "Springer" } } © 2014 The MITRE Corporation. All rights reserved. | 10 | XML and JSON, side-by-side { <Book> <Title>Parsing Techniques</Title> <Authors> <Author>Dick Grune</Author> <Author>Ceriel J.H. Jacobs</Author> </Authors> <Date>2007</Date> <Publisher>Springer</Publisher> </Book> © 2014 The MITRE Corporation. All rights reserved. "Book": { "Title": "Parsing Techniques", "Authors": [ "Dick Grune", "Ceriel J.H. Jacobs" ], "Date": "2007", "Publisher": "Springer" } } | 11 | Creating lists in XML and JSON { <Book> <Title>Parsing Techniques</Title> <Authors> <Author>Dick Grune</Author> <Author>Ceriel J.H. Jacobs</Author> </Authors> <Date>2007</Date> <Publisher>Springer</Publisher> </Book> © 2014 The MITRE Corporation. All rights reserved. "Book": { "Title": "Parsing Techniques", "Authors": [ "Dick Grune", "Ceriel J.H. Jacobs" ], "Date": "2007", "Publisher": "Springer" } } | 12 | XML is a meta-language XML is a language that you use to create other languages. For example, on the previous slides we saw how to use XML to create a Book language, consisting of <Book>, <Title>, <Author>, and so forth. © 2014 The MITRE Corporation. All rights reserved. | 13 | JSON is a meta-language JSON is also a language that you use to create other languages. For example, on the previous slides we saw how to use JSON to create a Book language, consisting of "Book", "Title", "Author", and so forth. © 2014 The MITRE Corporation. All rights reserved. | 14 | An XML document is a tree Book Title Parsing Techniques © 2014 The MITRE Corporation. All rights reserved. Authors Author Author Dick Grune Ceriel J.H. Jacobs Date Publisher 2007 Springer | 15 | A JSON Object is a tree Book Title Authors Date Publisher Parsing Techniques [“Dick Grune”, “Ceriel J.H. Jacobs”] 2007 Springer © 2014 The MITRE Corporation. All rights reserved. | 16 | Trees are well-studied The tree data structure has been well-studied by computer scientists and mathematicians. There are many well-known algorithms for processing and traversing trees. Both XML and JSON are able to leverage this. © 2014 The MITRE Corporation. All rights reserved. | 17 | XML Schema for Book <xs:element name="Book"> <xs:complexType> <xs:sequence> <xs:element name="Title" type="xs:string" /> <xs:element name="Authors"> <xs:complexType> <xs:sequence> <xs:element name="Author" type="xs:string" maxOccurs="5"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Date" type="xs:gYear" /> <xs:element name="Publisher" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="Springer" /> <xs:enumeration value="MIT Press" /> <xs:enumeration value="Harvard Press" /> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> © 2014 The MITRE Corporation. All rights reserved. | 18 | Equivalent JSON Schema { "$schema": "http://json-schema.org/draft-04/schema "type": "object", "properties": { "Book": { "type": "object", "properties": { "Title": {"type": "string"}, "Authors": {"type": "array", "minItems": 1, "maxItems": 5, "items": { "type": "string" }}, "Date": {"type": "string", "pattern": "^[0-9]{4}$"}, "Publisher": {"type": "string", "enum": ["Springer", "MIT Press", "Harvard Press"]} }, "required": ["Title", "Authors", "Date"], "additionalProperties": false } }, "required": ["Book"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 19 | Title with string type { "$schema": "http://json-schema.org/draft-04/schema "type": "object", "properties": { <xs:element name="Title" type="xs:string" /> "Book": { "type": "object", "properties": { "Title": {"type": "string"}, "Authors": {"type": "array", "minItems": 1, "maxItems": 5, "items": { "type": "string" }}, "Date": {"type": "string", "pattern": "^[0-9]{4}$"}, "Publisher": {"type": "string", "enum": ["Springer", "MIT Press", "Harvard Press"]} }, "required": ["Title", "Authors", "Date"], "additionalProperties": false } }, "required": ["Book"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 20 | Authors list { "$schema": "http://json-schema.org/draft-04/schema "type": "object", <xs:element name="Authors"> <xs:complexType> "properties": { <xs:sequence> "Book": { <xs:element name="Author" type="xs:string" maxOccurs="5"/> "type": "object", </xs:sequence> </xs:complexType> "properties": { </xs:element> "Title": {"type": "string"}, "Authors": {"type": "array", "minItems": 1, "maxItems": 5, "items": { "type": "string" }}, "Date": {"type": "string", "pattern": "^[0-9]{4}$"}, "Publisher": {"type": "string", "enum": ["Springer", "MIT Press", "Harvard Press"]} }, "required": ["Title", "Authors", "Date"], "additionalProperties": false } }, "required": ["Book"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 21 | Date with year type { "$schema": "http://json-schema.org/draft-04/schema "type": "object", "properties": { <xs:element name="Date" type="xs:gYear" /> "Book": { "type": "object", "properties": { "Title": {"type": "string"}, "Authors": {"type": "array", "minItems": 1, "maxItems": 5, "items": { "type": "string" }}, "Date": {"type": "string", "pattern": "^[0-9]{4}$"}, "Publisher": {"type": "string", "enum": ["Springer", "MIT Press", "Harvard Press"]} }, "required": ["Title", "Authors", "Date"], "additionalProperties": false } }, "required": ["Book"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 22 | Publisher with enumeration { "$schema": "http://json-schema.org/draft-04/schema "type": "object", "properties": { "Book": { "type": "object", "properties": { "Title": {"type": "string"}, "Authors": {"type": "array", "minItems": 1, "maxItems": 5, "items": { "type": "string" }}, "Date": {"type": "string", "pattern": "^[0-9]{4}$"}, "Publisher": {"type": "string", "enum": ["Springer", "MIT Press", "Harvard Press"]} }, "required": ["Title", "Authors", "Date"], "additionalProperties": false <xs:element name="Publisher" minOccurs="0"> } <xs:simpleType> }, <xs:restriction base="xs:string"> "required": ["Book"], <xs:enumeration value="Springer" /> "additionalProperties": false <xs:enumeration value="MIT Press" /> } © 2014 The MITRE Corporation. All rights reserved. <xs:enumeration value="Harvard Press" /> </xs:restriction> </xs:simpleType> </xs:element> | 23 | Bootstrap the schema language An XML Schema is written in XML. A JSON Schema is written in JSON. © 2014 The MITRE Corporation. All rights reserved. | 24 | Validate XML docs against XML Schema XML Schema XML (instance) © 2014 The MITRE Corporation. All rights reserved. XML Schema Validator XML instance is valid/invalid | 25 | Validate JSON docs against JSON Schema JSON Schema JSON (instance) © 2014 The MITRE Corporation. All rights reserved. JSON Schema Validator JSON instance is valid/invalid | 26 | JSON Schema validators http://json-schema.org/implementations.html © 2014 The MITRE Corporation. All rights reserved. | 27 | Online JSON Schema validator http://json-schema-validator.herokuapp.com/index.jsp Paste your JSON Schema in here Paste your JSON in here 2 Click on the validate button 3 © 2014 The MITRE Corporation. All rights reserved. 1 Results of validation is shown here 4 | 28 | Command-line JSON Schema validator Want to validate a JSON instance against a JSON Schema from the command line? Download: json-schema-validator-2.2.5-lib.jar from: https://bintray.com/fge/maven/json-schema-validator/view and then, from a command line, type: java -jar json-schema-validator-2.2.5-lib.jar schema.json instance.json © 2014 The MITRE Corporation. All rights reserved. | 29 | Use a JSON Schema validator from a Java program Want to validate a JSON instance against a JSON Schema from a Java program? Download: json-schema-validator-2.2.5-lib.jar from: https://bintray.com/fge/maven/json-schema-validator/view and then read the documentation on the Java API. © 2014 The MITRE Corporation. All rights reserved. | 30 | Schema-for-Schemas At the following URL is a JSON Schema. It is a schema for validating JSON Schemas … it is a schema for schemas! http://json-schema.org/draft-04/schema# JSON Schema for Schemas JSON Schema © 2014 The MITRE Corporation. All rights reserved. JSON Schema Validator JSON Schema is valid/invalid | 31 | Status of JSON Schema specifications JSON Schema is being developed under the auspicies of the IETF standards organization. The JSON Schema specification is currently at draft #4. Work is proceeding on draft #5. Draft #5 will contain a few new things, but will be mostly the same as draft #4 (draft #5 is backward compatible with draft #4). Here are the draft #5 changes: https://groups.google.com/forum/#!topic/jsonschema/FSJmct8crXk © 2014 The MITRE Corporation. All rights reserved. | 32 | JSON Schema mailing list The Google Group where JSON Schema is discussed: https://groups.google.com/forum/#!forum/json-schema © 2014 The MITRE Corporation. All rights reserved. | 33 | JSON used to store location of tweets (Eric Fisher) https://www.mapbox.com/blog/twitter-map-every-tweet/ © 2014 The MITRE Corporation. All rights reserved. | 34 | JSON used to store location of tweets (cont.) Tracking geotagged tweets from Twitter’s public API for the last three and a half years. There are about 10 million public geotagged tweets every day, which is about 120 per second. The accumulated history adds up to nearly three terabytes of compressed JSON and is growing by four gigabytes a day. The map on the previous slide shows what 6,341,973,478 tweets look like on a map. Using this program to parse the JSON and pull out just each tweet’s username, date, time, location, client, and text: https://github.com/ericfischer/twitter-json © 2014 The MITRE Corporation. All rights reserved. | 35 | OASIS using JSON The OASIS Open Data Protocol (Odata) Technical Committee (https://www.oasis-open.org/committees/odata) is currently defining a JSON format for OData service metadata, and plan to use JSON Schema as the basis for this format. © 2014 The MITRE Corporation. All rights reserved. | 36 | Processing JSON and JSON Schema with Java Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. https://code.google.com/p/google-gson/ http://www.studytrails.com/java/json/java-google-jsonintroduction.jsp Class JsonReader: Reads a JSON encoded value as a stream of tokens. This stream includes both literal values (strings, numbers, booleans, and nulls) as well as the begin and end delimiters of objects and arrays. The tokens are traversed in depth-first order, the same order that they appear in the JSON document. Within JSON objects, name/value pairs are represented by a single token. http://googlegson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/g son/stream/JsonReader.html © 2014 The MITRE Corporation. All rights reserved. | 37 | JSON Design Philosophy StackOverflow Question: Is there an XSLT equivalent for JSON? Something to allow me to do transformations on JSON like XSLT does to XML. Response: Not too sure there is need for this, and to me lack of tools suggests lack of need. JSON is best processed as objects (the way it's done in JS anyway), and you typically use language of the objects itself to do transformations (Java for Java objects created from JSON, same for Perl, Python, Perl, c#, PHP and so on). Just with normal assignments (or set, get), looping and so on. I mean, XSLT is just another language, and one reason it is needed is that XML is not an object notation and thus objects of programming languages are not exact fits (impedance between hierarchic xml model and objects/structs). [StaxMan] http://stackoverflow.com/questions/1618038/xslt-equivalent-for-json © 2014 The MITRE Corporation. All rights reserved. | 38 | http://www.freeformatter.com/xml-to-json-converter.html © 2014 The MITRE Corporation. All rights reserved. | 39 | Example of XML-to-JSON The online freeformatter.com tool converts this XML: <Book id="MCD"> <Title>Modern Compiler Design</Title> <Author>Dick Grune</Author> <Publisher>Springer</Publisher> </Book> to this JSON: { "@id": "MCD", "Title": "Modern Compiler Design", "Author": "Dick Grune", "Publisher": "Springer" } I like that it encodes XML attributes by prefixing the attribute name with the @ symbol. © 2014 The MITRE Corporation. All rights reserved. | 40 | Auto-converting XML to JSON: a bad idea? Should you devise a way to auto-convert XML to JSON? In the below message the person says: Based on our real-world experience, it is best to create the JSON design from scratch. Do not auto-generate it from XML. Hi all, To throw in a view from a long-time XML user: IPTC - www.iptc.org - builds XML-based news exchange formats for 17 years now and was also challenged to do the same in JSON. After a long discussion we refrained from automatically converting an existing XML data model to JSON: - currently no shared/common way to deal with namespaces in JSON - designs like inline elements don't exist in JSON - the element/attribute model has no corresponding design in JSON - and a basic requirement of JSON users is: no complex data model, please! Therefore we created - a simplified data model for the news exchange in JSON - www.newsinjson.org - compared to the richer but also more complex XML format www.newsml-g2.org - a highly corresponding JSON model to an initial XML model for the rights expression language ODRL as this is a set of data which cannot be simplified: http://www.w3.org/community/odrl/work/json/ vs http://www.w3.org/community/odrl/work/2-0-xml-encoding-constraint-draft-changes/ Both approaches were welcome and are used - and we learned: an XML-to-JSON tool only is of limited help. http://lists.xml.org/archives/xml-dev/201412/msg00022.html © 2014 The MITRE Corporation. All rights reserved. | 41 | The upcoming slides The following slides are organized as follows: – Description of the JSON data format – How to create JSON Schemas © 2014 The MITRE Corporation. All rights reserved. | 42 | The JSON data format © 2014 The MITRE Corporation. All rights reserved. | 43 | JSON value A JSON instance contains a single JSON value. A JSON value may be either an object, array, number, string, true, false, or null: Acknowledgement: This “railroad” graphic comes from the JSON specification, as do the railroad graphics on the next several slides. © 2014 The MITRE Corporation. All rights reserved. | 44 | JSON object A JSON object is zero or more string-colon-value pairs, separated by comma and wrapped within curly braces: Example of a JSON object: { "name": "John Doe", "age": 30, "married": true } © 2014 The MITRE Corporation. All rights reserved. | 45 | Empty object A JSON object may be empty. This is a JSON object: { } © 2014 The MITRE Corporation. All rights reserved. | 46 | JSON array A JSON array is used to express a list of values. A JSON array contains zero or more values, separated by comma and wrapped within square brackets: Example of a JSON array { "name": "John Doe", "age": 30, "married": true, "siblings": ["John", "Mary", "Pat"] } © 2014 The MITRE Corporation. All rights reserved. | 47 | Empty array vs. array with a null value [] Array with no items in it. © 2014 The MITRE Corporation. All rights reserved. [ null ] Array with one item in it. | 48 | Array of objects Each item in an array may be any of the seven JSON values. { "name": "John Doe", "age": 30, "married": true, "siblings": [ {"name": "John", "age": 25}, true, "Hello World" ] } © 2014 The MITRE Corporation. All rights reserved. The array contains 3 items. The first item is an object, the second item is a boolean, and the third item is a string. Do Lab1 | 49 | JSON number A number is an integer or a decimal and it may have an exponent: { "name": "John Doe", "age": 30, "married": true, "siblings": ["John", "Mary", "Pat"] } © 2014 The MITRE Corporation. All rights reserved. Example of a JSON number | 50 | JSON string A string is a sequence of Unicode characters wrapped within quotes ("). { "name": "John Doe", "age": 30, "married": true, "siblings": ["John", "Mary", "Pat"] } © 2014 The MITRE Corporation. All rights reserved. Example of a JSON string | 51 | JSON chars are a superset of XML chars JSON XML Lesson Learned: be careful converting JSON to XML as the result may be a non-well-formed XML document. © 2014 The MITRE Corporation. All rights reserved. | 52 | These characters must be escaped If any of the following characters occur within a string, they must be escaped by preceding them with a backslash (\): – quotation mark ("), – backslash (\), – the control characters U+0000 to U+001F © 2014 The MITRE Corporation. All rights reserved. | 53 | Expressing characters in hex format A character may be represented as a hexadecimal number, like so: \u006A or \u006a for the 'j' character. © 2014 The MITRE Corporation. All rights reserved. | 54 | No multiline strings JSON does not allow multiline strings. http://json.org/ http://stackoverflow.com/questions/2392766/multiline-strings-in-json © 2014 The MITRE Corporation. All rights reserved. | 55 | Achieving interoperability in a world where different OS's represent newline differently Each operating system has its own convention for signifying the end of a line of text: Unix: the newline is a character, with the value hex A (LF). MS Windows: the newline is a combination of two characters, with the values hex D (CR) and hex A (LF), in that order. Mac OS: the newline is a character, with the value hex D (CR). This operating-system-dependency of newlines can cause interoperability problems: the newlines in a string created on a Unix box will not be understood by applications running on a Windows box. Here is how the newline problem is resolved in XML and in JSON: XML: all newlines are normalized by an XML parser to hex A (LF). So it doesn't matter whether you create your XML document on a Unix box, a Windows box, or a Macintosh box, all newlines will be represented as hex A (LF). JSON: multi-line strings are not permitted! So the newline problem is avoided completely. You can, however, embed within your JSON strings the \n (LF) or \r\n (CRLF) symbols, to instruct processing applications: "Hey, I would like a newline here." That is quite an interesting difference in approach between XML and JSON for dealing with the newline problem! © 2014 The MITRE Corporation. All rights reserved. | 56 | Other JSON values The values true, false, and null are literal values; they are not wrapped in quotes. { "name": "John Doe", "age": 30, "married": true, "siblings": ["John", "Mary", "Pat"] } © 2014 The MITRE Corporation. All rights reserved. Example of a JSON boolean | 57 | Good use-case for null Some people do not have a middle name, we can use null to indicate “no value”: { “first-name": "John", “middle-name": null, “last-name": “Doe" } © 2014 The MITRE Corporation. All rights reserved. | 58 | This is a legal JSON instance 42 © 2014 The MITRE Corporation. All rights reserved. | 59 | so is this "Hello World" © 2014 The MITRE Corporation. All rights reserved. | 60 | and so is this true © 2014 The MITRE Corporation. All rights reserved. | 61 | and this [ true, null, 12, "ABC" ] © 2014 The MITRE Corporation. All rights reserved. | 62 | Whitespace is irrelevant { "name": "John Doe", "age": 30, "married": true } equivalent {"name":"John Doe","age":30,"married":true} © 2014 The MITRE Corporation. All rights reserved. | 63 | String delimiters: JSON vs. XML JSON strings are always delimited by double quotes. XML strings (such as attribute values) may be delimited by either double quotes or single quotes. © 2014 The MITRE Corporation. All rights reserved. | 64 | JSON is recursively defined { "foo": json-value } The above JSON instance is an object. The object has a single property, "foo". Its value is any JSON value – recursive definition! © 2014 The MITRE Corporation. All rights reserved. | 65 | Using JSON you can define arbitrarily complex structures { "Book": { "Title": "Parsing Techniques", "Authors": [ "Dick Grune", "Ceriel J.H. Jacobs" ] } } { "Book": { "Title": "Parsing Techniques", "Authors": [ {"name":"Dick Grune", "university": "Vrije Universiteit"}, {"name":"Ceriel J.H. Jacobs", "university": "Vrije Universiteit"} ] } } © 2014 The MITRE Corporation. All rights reserved. | 66 | Extend, ad infinitum { "Book": { "Title": "Parsing Techniques", "Authors": [ {"name": {"first":"Dick", "last":"Grune"}, "university": "Vrije Universiteit"}, {"name": {"first":"Ceriel", "last":"Jacobs"}, "university": "Vrije Universiteit"} ] } } © 2014 The MITRE Corporation. All rights reserved. | 67 | 7 simple JSON components, assemble to generate unlimited complexity Integer Null Boolean Object Array © 2014 The MITRE Corporation. All rights reserved. String Number | 68 | JSON provides the structures and assembly rules, you customize them for your needs object array [ json-value, json-value, json-value, … ] { "___": json-value, "___": json-value, "___": json-value, … } © 2014 The MITRE Corporation. All rights reserved. string "___" | 69 | JSON provides the structures and assembly rules, you customize them for your needs structures object array [ json-value, json-value, json-value, … ] { "___": json-value, "___": json-value, "___": json-value, … } © 2014 The MITRE Corporation. All rights reserved. string "___" | 70 | JSON provides the structures and assembly rules, you customize them for your needs assembly points object array [ json-value, json-value, json-value, … ] { "___": json-value, "___": json-value, "___": json-value, … } © 2014 The MITRE Corporation. All rights reserved. string "___" | 71 | JSON provides the structures and assembly rules, you customize them for your needs object array [ json-value, json-value, json-value, … ] { "___": json-value, "___": json-value, "___": json-value, … string "___" } customize © 2014 The MITRE Corporation. All rights reserved. | 72 | oXygen XML supports JSON You can create and edit JSON instances and JSON Schemas using oXygen XML and it will check that the document is correctly formatted. Nice! © 2014 The MITRE Corporation. All rights reserved. | 73 | MS Visual Studio supports JSON Schema Visual Studio provides a wonderful editor that helps you create JSON Schemas. The editor is available in the free Community version of Visual Studio 2013. Here's a YouTube presentation on how to create JSON Schemas using Visual Studio: https://www.youtube.com/watch?v=Jt5SCNC87d4 Do Lab2 © 2014 The MITRE Corporation. All rights reserved. | 74 | FAQ Q: I don't see any JSON constructs that are equivalent to XML attributes. A: Correct, there are no attributes in JSON. Q: Is there a namespace construct in JSON? If not, why was it deemed unnecessary? A: No namespaces in JSON. JSON is a reaction against the complexity of XML and namespaces is one of the biggest culprits, in terms of complexity. Continued © 2014 The MITRE Corporation. All rights reserved. | 75 | FAQ Q: Does JSON have tools to extract nodes from one or more instances and recombine them into a new instance? A: There is no equivalent of XSLT in JSON. The JSON people believe that text documents should be processed by a general purpose language such as Java or JavaScript, not a domainspecific language such as XSLT. Q: It appears to be trivially easy to convert from JSON to XML. Is that correct or are there complicating factors? A: JSON to XML should be straightforward. Going the other way is challenging, due to XML attributes and namespaces. Acknowledgement: Thanks to Rob Simmons for the excellent questions. © 2014 The MITRE Corporation. All rights reserved. | 76 | Generating railroad diagrams I love the railroad diagrams which are used to represent the JSON language. What tool is used to generate these diagrams? There is an Online Railroad Diagram Generator. It creates SVG syntax diagrams, also known as railroad diagrams, from context-free grammars specified in EBNF. You can copy the SVG code or take screen shots. You have to type in the grammar and it'll make the diagram. © 2014 The MITRE Corporation. All rights reserved. | 77 | Generating railroad diagrams For example, to create the railroad diagram for a JSON object, you would use the code: object ::= '{' ((string ':' value ) ( ',' string ':' value )*)? '}' http://stackoverflow.com/questions/796824/tool-for-generating-railroad-diagram-used-on-json-org © 2014 The MITRE Corporation. All rights reserved. | 78 | JSONx (JSON XML) JSONx is an IBM standard format to represent JSON as XML This document specifies a mapping between JSON and XML, known as JSONx. It is used by several IBM products. http://tools.ietf.org/html/draft-rsalz-jsonx-00 "phoneNumbers": [ "212 555-1111", "212 555-2222" ] © 2014 The MITRE Corporation. All rights reserved. <json:array name="phoneNumbers"> <json:string>212 555-1111</json:string> <json:string>212 555-2222</json:string> </json:array> | 79 | xml2json XML Shell (xmlsh, http://www.xmlsh.org) provides a capability to convert XML to JSON: http://www.xmlsh.org/CommandXml2json © 2014 The MITRE Corporation. All rights reserved. | 80 | How to create JSON Schemas © 2014 The MITRE Corporation. All rights reserved. | 81 | A contract for data exchanges Both XML Schema and JSON Schema may be used as a contract for data exchanges: conforms to data © 2014 The MITRE Corporation. All rights reserved. Contract (schema) | 82 | Fundamental difference between XML Schema and JSON Schema XML Schema: specifies closed content unless deliberate measures are taken to make it open (e.g., sprinkle the <any> element liberally throughout the schema). JSON Schema: specifies open content unless deliberate measures are taken to make it closed (e.g., sprinkle "additionalProperties": false liberally throughout the schema). Definition of Open Content: instance documents can contain items above and beyond those specified by the schema. Definition of Closed Content: instance documents can contain only those items specified by the schema. © 2014 The MITRE Corporation. All rights reserved. | 83 | The power of JSON Schema comes from: Regular expressions (regexes): JSON Schema uses regexes a lot. The regular expression language is well-established and very powerful. Most data constraints can be expressed using regexes. Recursion: nearly all keywords in JSON Schema are recursively defined, so you are limited only by your imagination in what you create. Simplicity: JSON Schema doesn't have a large set of data types or other features. It employs simple components which may be assembled to generate arbitrary complexity. © 2014 The MITRE Corporation. All rights reserved. | 84 | The power of JSON Schema comes from: Regular expressions (regexes): JSON Schema uses regexes a lot. The regular expression language is well-established and very powerful. Most data constraints can be expressed using regexes. Recursion: nearly all keywords in JSON Schema are recursively defined, so you are limited only by your imagination in what you create. Simplicity: JSON Schema doesn't have a large set of data types or other features. It employs simple components which may be assembled to generate arbitrary complexity. Awesome © 2014 The MITRE Corporation. All rights reserved. | 85 | A JSON Schema is a JSON object { "keyword": value, "keyword": value, "keyword": value, … } © 2014 The MITRE Corporation. All rights reserved. | 86 | A JSON Schema is a JSON object { "keyword": value, "keyword": value, "keyword": value, … } The JSON Schema specification defines the set of keywords and values that can be used to construct a schema. In this tutorial we will learn the keywords that may be used in a JSON Schema. © 2014 The MITRE Corporation. All rights reserved. | 87 | Empty schema {} This is a valid JSON Schema! It places no restrictions on JSON instances. © 2014 The MITRE Corporation. All rights reserved. | 88 | Every JSON instance is valid! {} JSON JSON Schema Validator Valid! instance Do Lab3 © 2014 The MITRE Corporation. All rights reserved. | 89 | "$schema" keyword { "$schema": "http://json-schema.org/draft-04/schema#", … } © 2014 The MITRE Corporation. All rights reserved. | 90 | "$schema" keyword { "$schema": "http://json-schema.org/draft-04/schema#", … } The $schema keyword says: This object is a JSON schema, conforming to the schema at http://json-schema.org/draft-04/schema#. © 2014 The MITRE Corporation. All rights reserved. | 91 | "type" keyword { "$schema": "http://json-schema.org/draft-04/schema#", "type": "type", … } © 2014 The MITRE Corporation. All rights reserved. | 92 | "type" keyword { "$schema": "http://json-schema.org/draft-04/schema#", "type": "type", … } The type keyword says: The JSON instance must be of this type. There are seven types: - "boolean" - "number" - "integer" - "string" - "array" - "object" - "null" © 2014 The MITRE Corporation. All rights reserved. | 93 | Boolean type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "boolean" } This schema constrains instances to contain only a boolean value (true or false). © 2014 The MITRE Corporation. All rights reserved. | 94 | Only boolean instances are valid { "$schema": "http://json-schema.org/draft-04/schema#", "type": "boolean" } JSON Schema Validator Valid! © 2014 The MITRE Corporation. All rights reserved. true | 95 | String instances are not valid { "$schema": "http://json-schema.org/draft-04/schema#", "type": "boolean" } JSON Schema Validator Not valid! © 2014 The MITRE Corporation. All rights reserved. "Hello World" | 96 | Alert! "true" is not a Boolean value { "$schema": "http://json-schema.org/draft-04/schema#", "type": "boolean" } JSON Schema Validator Not valid! © 2014 The MITRE Corporation. All rights reserved. "true" | 97 | Run example01 Open the example01 folder (in the examples folder). In that folder are two files: – schema.json – instance.json Open the files in oXygen XML. Copy to the clipboard the content of schema.json and then paste it into the Schema section of this online validator: http://json-schema-validator.herokuapp.com/index.jsp Copy to the clipboard the content of instance.json and then paste it into the Data section. Press the validate button. © 2014 The MITRE Corporation. All rights reserved. | 98 | http://json-schema-validator.herokuapp.com/index.jsp Paste schema here 1 Instance is valid! 4 Paste instance here 2 Press the Validate button 3 © 2014 The MITRE Corporation. All rights reserved. | 99 | Order of keywords is irrelevant { "$schema": "http://json-schema.org/draft-04/schema#", "type": "boolean" } equivalent! { "type": "boolean", "$schema": "http://json-schema.org/draft-04/schema#" } © 2014 The MITRE Corporation. All rights reserved. | 100 | Number type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number" } This schema constrains instances to contain only a number (integer, decimal, number with exponent). © 2014 The MITRE Corporation. All rights reserved. | 101 | Only numeric instances are valid { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number" } JSON Schema Validator Valid! © 2014 The MITRE Corporation. All rights reserved. 12.3 | 102 | Examples of numeric values 12 99.1 12.123e3 12.123E3 12.123 x 103 © 2014 The MITRE Corporation. All rights reserved. | 103 | "enum" keyword The value of enum is an array. The items in the array is a list of values that instances may have. The following schema says that the only allowable values in instances are the numbers: 2, 4, 6, 8, 10. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "enum": [2, 4, 6, 8, 10] } See example02 © 2014 The MITRE Corporation. All rights reserved. | 104 | "minimum" and "maximum" keywords A range of values can be specified using the "minimum" and "maximum" keywords. The following schema constrains instances to numbers in the range 0-100, inclusive. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "minimum": 0, "maximum": 100 } © 2014 The MITRE Corporation. All rights reserved. | 105 | "exclusiveMinimum", "exclusiveMaximum" A range's endpoints can be made exclusive by using the "exclusiveMinimum" and "exclusiveMaximum" keywords. The following schema constrains instances to numbers in the range 0-100, exclusive. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "minimum": 0, "maximum": 100, "exclusiveMinimum": true, "exclusiveMaximum": true } See example03 © 2014 The MITRE Corporation. All rights reserved. | 106 | "multipleOf" keyword Instances can be constrained to a number that is a multiple of a number. The following schema says that a JSON instance must be a number 0-100, inclusive, and must be a multiple of 2. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "minimum": 0, "maximum": 100, "multipleOf": 2 } Here are four schema-valid values: 0 See example04 © 2014 The MITRE Corporation. All rights reserved. 2 4 100 | 107 | "multipleOf" value The value of "multipleOf" must be greater than 0 (no negative numbers). © 2014 The MITRE Corporation. All rights reserved. | 108 | Integer type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "integer" } This schema constrains instances to contain only an integer. Here are two schema-valid values: -900 © 2014 The MITRE Corporation. All rights reserved. 129 | 109 | Number constraints also apply to integer The constraints that apply to "number" also apply to "integer": – enum – minimum – maximum – exclusiveMinimum – exclusiveMaximum – multipleOf Do Lab4 © 2014 The MITRE Corporation. All rights reserved. | 110 | String type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string" } This schema constrains instances to contain only a string. © 2014 The MITRE Corporation. All rights reserved. | 111 | "maxLength" keyword The maximum length of a string is constrained using the "maxLength" keyword. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 20 } Here is a schema-valid value: "Hello World" See example05 © 2014 The MITRE Corporation. All rights reserved. | 112 | Value of "maxLength" { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": ___ } Must be an integer, ≥ 0 © 2014 The MITRE Corporation. All rights reserved. | 113 | "minLength" keyword The "minLength" keyword is used to specify the shortest string length allowed. The value of "minLength" must be an integer, greater than or equal to 0. The default value is 0. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "minLength": 5, "maxLength": 20 } © 2014 The MITRE Corporation. All rights reserved. | 114 | "pattern" keyword The set of characters that can be used in a string can be constrained using the "pattern" keyword, whose value is a regular expression [1]. The following schema constrains the set of characters to the lower- and upper-case letters of the English alphabet, plus the space character. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } See example06 [1] What flavor of regexes does JSON Schema use? Answer: ECMA 262. http://www.ecma-international.org/ecma-262/5.1/#sec-15.10 © 2014 The MITRE Corporation. All rights reserved. | 115 | "pattern" value is a regular expression The value of "pattern" is a regular expression. The regular expressions are not implicitly anchored (as they are in XML Schema) so you must use the start and end anchors (^…$). { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } This symbol indicates that a string must end with the letters of the alphabet plus space. This symbol indicates that a string must start with the letters of the alphabet plus space. © 2014 The MITRE Corporation. All rights reserved. | 116 | How to read this JSON Schema { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } “ The string in a JSON instance cannot have a length greater than 20 characters and the characters must be a-z, A-Z, or space. ” © 2014 The MITRE Corporation. All rights reserved. | 117 | Components of regular expressions Basic pattern Matching string x The character x . Any character, except newline Legend: [xyz ...] Any of the characters, x, y, z, … x, y, z, … stand for any character R, R1, R2, …stand for any regular expression Repetition operators: R? R is optional (zero or one occurrence) R* Zero or more occurrences of R R+ One or more occurrences of R Operator Precedence: Repetition operators have the highest precedence (bind most tightly); next comes the concatenation operator; and the alternatives operator | has the lowest precedence Compositional operators: R1R2 An R1 followed by an R2 R1|R2 Either an R1 or an R2 Acknowledgement: This table comes from Modern Compiler Design by Grune et al, p62. Grouping: (R) © 2014 The MITRE Corporation. All rights reserved. R itself | 118 | Escaping the dot (.) and the dash (-) In regular expressions the dot (.) symbol means “any character” Suppose that you want the dot (.) symbol, not “any character”. How would you express that? You might think, do this: \. However, that’s not correct. You need to escape the backslash. Here’s how to do it: \\. Similarly, in regular expressions the dash (-) symbol means “range-of-characters” Suppose that you want the dash (-) symbol, not “range-ofcharacters”. Here’s how to express it: \\- © 2014 The MITRE Corporation. All rights reserved. | 119 | Enumerate the allowed string The "enum" keyword can be used with the string type. The following schema says that only three strings are allowed: "red", "white", or "blue". { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "enum": ["red", "white", "blue"] } Here’s a schema-valid instance: "red" See example07 © 2014 The MITRE Corporation. All rights reserved. | 120 | "enum" applies to all types The "enum" keyword can be used with all seven types. © 2014 The MITRE Corporation. All rights reserved. | 121 | "enum" without "type" When the "type" keyword" is specified, then all the values in the "enum" array must conform to that type. If the "type" keyword is omitted, then the values in the "enum" array can be of any type. The following schema says that a JSON instance can be the string: "red", the number 12, or the boolean false. { "$schema": "http://json-schema.org/draft-04/schema#", "enum": ["red", 12, false] } © 2014 The MITRE Corporation. All rights reserved. | 122 | "format" keyword The "format" keyword is used to specify the format of a string. The following schema says that JSON instances must consist of a string and the string must be formatted as an ISO 8601 date/time value. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "format": "date-time" } Here’s a schema-valid instance: "2014-06-20T12:50:00Z" See example08 © 2014 The MITRE Corporation. All rights reserved. | 123 | date-time format A string with format date-time must conform to one of these two forms: yyyy-MM-dd'T'HH:mm:ssZ yyyy-MM-dd'T'HH:mm:ss.SSSZ © 2014 The MITRE Corporation. All rights reserved. | 124 | "format" keyword values Here are the valid values for the "format" keyword: – "date-time" – "email" – "hostname" – "ipv4" – "uri" Those values are called format attributes. The "format" keyword may only be used with the string type. © 2014 The MITRE Corporation. All rights reserved. | 125 | Examples of "format" values "date-time" "2014-06-20T12:50:00Z" "email" "smith@example.org" "hostname" "www.google.com" "ipv4" "192.168.5.0" "uri" "http://www.google.com" Do Lab5 © 2014 The MITRE Corporation. All rights reserved. | 126 | Array © 2014 The MITRE Corporation. All rights reserved. | 127 | Array type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array" } © 2014 The MITRE Corporation. All rights reserved. | 128 | Array type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array" } This schema constrains instances to contain only an array. Here’s a schema-valid value: ["value1", "value2", 12, null] © 2014 The MITRE Corporation. All rights reserved. | 129 | Enumerate the allowed arrays The "enum" keyword can be used with the array type. The following schema says that instances may be either of these arrays: ["A", "B"] or [1,2,3]. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "enum": [["A", "B"], [1,2,3]] } Here are the only two valid instance values: ["A", "B"] See example09 © 2014 The MITRE Corporation. All rights reserved. [1,2,3] | 130 | "maxItems" keyword The maximum number of items in the array is specified using the "maxItems" keyword. The following schema says that JSON instances must consist of an array and the instance cannot contain more than three items. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3 } Here’s a schema-valid instance: See example10 © 2014 The MITRE Corporation. All rights reserved. [ 1, true, ["A", "B"] ] | 131 | The items can be anything { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3 } This constrains the number of array items to three. But each of those items can be anything. © 2014 The MITRE Corporation. All rights reserved. | 132 | "items" keyword The items in an array can be constrained using the "items" keyword. The value of "items" is a JSON Schema. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": JSON Schema } © 2014 The MITRE Corporation. All rights reserved. | 133 | Recursive definition! { This JSON Schema contains this JSON Schema "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": JSON Schema } © 2014 The MITRE Corporation. All rights reserved. | 134 | All that we’ve learned applies to the subschema { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { "keyword": value, "keyword": value, "keyword": value, … } } The value of "items" can be all the things that we've seen: the "type" keyword, the "maxLength" keyword for strings, the "minimum" and "maximum" keywords for numbers, and so forth. © 2014 The MITRE Corporation. All rights reserved. | 135 | Terminology: root schema, subschema { } "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": {{ "keyword": "keyword":value, value, "keyword": "keyword":value, value, "keyword": "keyword":value, value, …… }} root schema © 2014 The MITRE Corporation. All rights reserved. subschema | 136 | Don’t use $schema in subschemas Yes { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { “$schema": "http://json-schema.org/draft-04/schema#", "keyword": value, "keyword": value, … } No } "$schema" should only be used in the root schema, not in subschemas. It’s not illegal in draft #4, but in draft v5, $schema appearing in a subschema will be an error. Do Lab6 © 2014 The MITRE Corporation. All rights reserved. | 137 | Default value for "items" If "items" is not present, it has a default value of { }, which means that each item in the array may be any value. © 2014 The MITRE Corporation. All rights reserved. | 138 | Max of 3 items, each an integer The following schema says that instances must not contain more than 3 items and each item must be an integer. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { "type": "integer" } } Here are four schema-valid instances: [1,2,3] See example11 © 2014 The MITRE Corporation. All rights reserved. [1,2] [1] [] | 139 | Max of 3 items, each an integer 0 – 100 The following schema says that instances must not contain more than 3 items and each item must be an integer and the integer must be between 0 and 100. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { "type": "integer", "minimum": 0, "maximum": 100 } } See example12 © 2014 The MITRE Corporation. All rights reserved. | 140 | "uniqueItems" keyword We can require each item in the array be unique. This is accomplished using the "uniqueItems" keyword. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { "type": "integer", "minimum": 0, "maximum": 100 }, "uniqueItems": true } The default value of "uniqueItems" is false. See example13 © 2014 The MITRE Corporation. All rights reserved. | 141 | Max of 3 items, each a string with max length 20, consisting of letters and spaces only { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } } See example14 © 2014 The MITRE Corporation. All rights reserved. | 142 | "items" with empty schema value If the value of "items" is { } then each item may have any value. The following schema permits each array item to be anything. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": {} } Here is a schema-valid instance: [ "hello world", 12, {"age":30} ] See example15 © 2014 The MITRE Corporation. All rights reserved. | 143 | Equivalent! { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3, "items": {} } Equivalent since the default value of "items" is { } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "maxItems": 3 } © 2014 The MITRE Corporation. All rights reserved. | 144 | Two legal values for "items" As we’ve seen, the value of "items" is an object (a JSON Schema). Alternatively, the value of "items" may be an array. Each item in the array must be an object (a JSON Schema). { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": JSON Schema } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ JSON Schema, JSON Schema, … ] } © 2014 The MITRE Corporation. All rights reserved. This kind of array is called an array tuple | 145 | Array may contain two strings The below schema specifies an array consisting of up to two items. If the first item is present, it must be either the string "white" or "black". If the second item is present, it must be either the string "cup" or "plate". The array may be empty. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ] } © 2014 The MITRE Corporation. All rights reserved. | 146 | Some legal instances { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ] } Here are three valid values: [ "white", "cup"] [ "white"] [] See example16 Do Lab7 © 2014 The MITRE Corporation. All rights reserved. | 147 | Array has open content! { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ] } This schema specifies what the first two items in the array must be, but it doesn’t say there can’t be additional items. This is a valid value: [ "white", "cup", true, null, {"foo": 12} ] additional items © 2014 The MITRE Corporation. All rights reserved. | 148 | "additionalItems" keyword "additionalItems": false is used to specify that an array cannot contain additional items. Now the array is constrained to no more than two items: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ], "additionalItems": false } See example17 Do Lab8 © 2014 The MITRE Corporation. All rights reserved. | 149 | Array tuple with { } for each value { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ {}, {} ], "additionalItems": false } The array must contain up to two items. Each item can be anything: a number, integer, boolean, array, object, or null. Here are 4 valid instances: [ ] [1] See example18 © 2014 The MITRE Corporation. All rights reserved. [1, true] [1, [1, true]] | 150 | Desire: any number of additional items, but of a certain type If we don’t specify "additionalItems": false, then instances can have any number of additional items and each item can be anything (of any type). We may want to allow any number of additional items, but they are to be constrained to be of a certain type (e.g., constrain them to be booleans) © 2014 The MITRE Corporation. All rights reserved. | 151 | additionalItems with a JSON Schema value We have seen that additionalItems can have a boolean value. Alternatively, it can have a value that is an object (JSON Schema) "additionalItems": JSON Schema © 2014 The MITRE Corporation. All rights reserved. | 152 | Any number of boolean values The below schema specifies that an instance must be an array that contains one item: a string of max length 20, consisting of the lower and uppercase letters plus space. Further, any number of boolean values may follow the string. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } ], "additionalItems": {"type": "boolean"} } Here are three valid instances: ["Hello World", true, false, false, true] ["Hello World"] [] See example19 © 2014 The MITRE Corporation. All rights reserved. | 153 | Restrict the additional items On the previous slide the schema allowed an unbounded number of additional items (i.e., boolean values). We can restrict the total number of items (thus restricting the number of additional items) using the "maxItems" keyword: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } ], "additionalItems": {"type": "boolean"}, "maxItems": 3 } The total number of items that are allowed in the array is 3, which means there can only be 2 boolean values. See example19.1 © 2014 The MITRE Corporation. All rights reserved. | 154 | Valid and invalid instances { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" } ], "additionalItems": {"type": "boolean"}, "maxItems": 3 } These are schema-valid: These are not schema-valid: [] [true] ["Hello World"] ["Hello World", true, false, false] ["Hello World", true] ["Hello World", true, false] © 2014 The MITRE Corporation. All rights reserved. | 155 | Restrictions on "additionalItems": { … } The value of "additionalItems" can be a schema only if "items" is present and its value is an array tuple (an array of schemas). © 2014 The MITRE Corporation. All rights reserved. | 156 | Default value of "additionalItems" is { } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ] } Equivalent { "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": [ { "type": "string", "enum": ["white", "black"] }, { "type": "string", "enum": ["cup", "plate"] } ], "additionalItems": { } } © 2014 The MITRE Corporation. All rights reserved. The array may contain zero or more additional items and each additional item may have any value. | 157 | Rules for constraining arrays If the value of "items" is a JSON Schema, then we can constrain the number of items using "maxItems" If the value of "items" is an array, then we can prevent the presence of additional items using "additionalItems": false If the value of "items" is an array and the value of "additionalItems" is a JSON Schema, then we can constrain the total number of items using "maxItems" © 2014 The MITRE Corporation. All rights reserved. | 158 | How to constrain arrays: If the schema has this: then the array can be constrained using this keyword: "type": "array" "enum" "type": "array", "items": JSON Schema "maxItems" "type": "array", "items": [ JSON Schema, JSON Schema, … ] "additionalItems": false "type": "array", "items": [ JSON Schema, JSON Schema, … ], "additionalItems": JSON Schema "maxItems" © 2014 The MITRE Corporation. All rights reserved. | 159 | The value of additionalItems is a choice "type": "boolean" "additionalItems": JSON Schema © 2014 The MITRE Corporation. All rights reserved. | 160 | Here is how the schema-for-schema defines "additionalItems" "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, © 2014 The MITRE Corporation. All rights reserved. | 161 | Object © 2014 The MITRE Corporation. All rights reserved. | 162 | Object type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object" } © 2014 The MITRE Corporation. All rights reserved. | 163 | Object type { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object" } The schema constrains instances to contain only an object. Here’s a schema-valid value: { "X": 12, "Y": "hello" } See example20 © 2014 The MITRE Corporation. All rights reserved. | 164 | Unconstrained object { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object" } The schema specifies no constraints on the object's properties (i.e., name/value pairs). © 2014 The MITRE Corporation. All rights reserved. | 165 | Enumerate the allowed objects The "enum" keyword can be used to enumerate the objects that are allowed in instances. The following schema enumerates two objects: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "enum": [ {"name": "John Doe", "age": 30}, {"company": "Google", "product": "searching"} ] } Here are the only valid instances: {"name": "John Doe", "age": 30} See example21 © 2014 The MITRE Corporation. All rights reserved. {"company": "Google", "product": "searching"} | 166 | Desire: specify the property names, but values are variable The "enum" keyword specifies both property name and property value. For more flexibility we would like to enumerate the property names but leave the property values variable. © 2014 The MITRE Corporation. All rights reserved. | 167 | "properties" keyword { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} } } Instances must be an object. The object may contain a property "name" and a property "age". The value of "name" must be a string. The value of "age" must be an integer. See example22 Do Lab9 © 2014 The MITRE Corporation. All rights reserved. | 168 | Sample instance { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} } } Here is a valid instance: { "name": "John Doe", "age": 30 } © 2014 The MITRE Corporation. All rights reserved. | 169 | Order of properties is irrelevant { "name": "John Doe", "age": 30 } equivalent instances { "age": 30, "name": "John Doe" } © 2014 The MITRE Corporation. All rights reserved. | 170 | Property name can be an empty string { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"}, "": {"type": "boolean"} } } Here is a valid instance: { "name": "John Doe", "age": 30, "": true } See example23 © 2014 The MITRE Corporation. All rights reserved. | 171 | Properties are optional By default, the properties listed in "properties" are optional. These are all valid instances: { { "name": "John Doe", "age": 30, "": true {} "name": "John Doe", "age": 30 } } { { "name": "John Doe", "": true } © 2014 The MITRE Corporation. All rights reserved. "name": "John Doe" } | 172 | Mandate properties using "required" The "required" keyword is used to mandate properties. The value of "required" is an array of strings, each string corresponding to the name of a property. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "number" } }, "required": ["name", "age"] } Instances must have "name" and "age" properties. See example24 © 2014 The MITRE Corporation. All rights reserved. | 173 | Object has open content by default { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "number" } }, "required": ["name", "age"] } The schema specifies two properties that must be in instances. But it doesn’t say there can’t be additional properties. This is a valid value: { "name": "John Doe", "age": 30, "height": 68, additional properties "married": true } © 2014 The MITRE Corporation. All rights reserved. | 174 | Sprinkle additional properties anywhere In instances "name" and "age" don’t have to come first. Additional properties can come before and after them. This is a valid instance: { "married": true, "name": "John Doe", "height": 68, "age": 30 } © 2014 The MITRE Corporation. All rights reserved. | 175 | "additionalProperties" keyword Instances can be constrained to contain only those listed in the schema by using "additionalProperties": false { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "number" } }, "required": ["name", "age"], "additionalProperties": false } Now instances must contain "name" and "age" and nothing else. See example25 © 2014 The MITRE Corporation. All rights reserved. Do Lab10 | 176 | Well-constrained object { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false } Instances must contain an object. The object must have exactly two properties: one named "name" and the other named "age". The value of "name" must be a string, not longer than 20 characters, consisting of the symbols a-z, A-Z, and space. The value of "age" must be a number in the range 0 – 120, inclusive. Nice! See example26 © 2014 The MITRE Corporation. All rights reserved. | 177 | { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false name and age are required } © 2014 The MITRE Corporation. All rights reserved. | 178 | { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false No other properties are allowed } © 2014 The MITRE Corporation. All rights reserved. | 179 | The value of name must be a string, with max length of 20, consisting of a-z, A-Z, and space. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 180 | The value of age must be a number in the range 0 – 120, inclusive. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 181 | The instance must be an object. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": ["name", "age"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 182 | Must specify "type": "object" with "properties" When "properties" is used, then "type": "object" is required to be present. If it is not present: { "$schema": "http://json-schema.org/draft-04/schema#", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} } } then any value in the instance is valid. For example the following instance validates against the schema: true See example27 © 2014 The MITRE Corporation. All rights reserved. | 183 | Here's why { "$schema": "http://json-schema.org/draft-04/schema#", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} } } This schema does not specify the type of value that an instance must have, so instances can have any type! © 2014 The MITRE Corporation. All rights reserved. | 184 | Summary of "properties" The value of "properties" is an object. The object contains members. Each member has a name and its value is a schema: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "property-name": JSON Schema, "property-name": JSON Schema, ... } } © 2014 The MITRE Corporation. All rights reserved. | 185 | Recursive definition! { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "property-name": JSON Schema, "property-name": JSON Schema, ... } This JSON Schema contains these JSON Schemas } © 2014 The MITRE Corporation. All rights reserved. | 186 | additionalItems versus additionalProperties Careful! Distinguish between "additionalItems": false and "additionalProperties": false: – The former is used to disallow additional items in an array, the latter is used to disallow additional properties in an object © 2014 The MITRE Corporation. All rights reserved. | 187 | Constraining the number of properties The minimum and maximum number of properties can be constrained using the "minProperties" and "maxProperties" keywords. The following schema specifies a list of activities: bowling, golfing, and kayaking. At least one activity but not more than two must be selected for inclusion in a JSON instance: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "bowling": { "type": "string", "maxLength": 20 }, "golfing": { "type": "string", "maxLength": 20 }, "kayaking": { "type": "string", "maxLength": 20 } }, "minProperties": 1, "maxProperties": 2, "additionalProperties": false } See example28 © 2014 The MITRE Corporation. All rights reserved. | 188 | Sample instance { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "bowling": { "type": "string", "maxLength": 20 }, "golfing": { "type": "string", "maxLength": 20 }, "kayaking": { "type": "string", "maxLength": 20 } }, "minProperties": 1, "maxProperties": 2, "additionalProperties": false } This JSON instance is valid since it has two of the activities: { "bowling": "50 Lanes", "kayaking": "Red Rock River" } © 2014 The MITRE Corporation. All rights reserved. | 189 | Property with { } as its value If the value of a property is { } then that property may have any value. The following schema says the value of "name" and "age" can be anything. { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { }, "age": { } }, "required": ["name", "age"], "additionalProperties": false } Here is a valid value: { "name": 12, "age": false See example29 © 2014 The MITRE Corporation. All rights reserved. } | 190 | "additionalProperties" (revisited) The value of "additionalProperties" may be a boolean, as shown on the previous slides. Or, it may be a JSON Schema: "additionalProperties": JSON Schema Here is an example: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { "type": "boolean" } } See example30 © 2014 The MITRE Corporation. All rights reserved. | 191 | Additional properties must be booleans { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { "type": "boolean" } } The "additionalProperties" specifies: "Instance may have properties beyond just "name" and "age“. But any additional properties must have a boolean value." So, "additionalProperties" (with an object value) is just for specifying the type of additional properties. © 2014 The MITRE Corporation. All rights reserved. | 192 | Instance containing additional boolean properties { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { "type": "boolean" } } Here is a valid value: { "name": "John Doe", "age": 30, Notice that each additional property "married": true, has a boolean value. "living": true } © 2014 The MITRE Corporation. All rights reserved. | 193 | Unlimited number of additional properties { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { "type": "boolean" } } As we’ve seen, instances may contain additional boolean properties. How many? Answer: An unlimited number. © 2014 The MITRE Corporation. All rights reserved. | 194 | Constrain the number of additional properties using "maxProperties" { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { "type": "boolean" }, "maxProperties": 4 } Now instances can have, at most, 4 properties. See example31 © 2014 The MITRE Corporation. All rights reserved. | 195 | Valid instances { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "additionalProperties": { { "type": "boolean" }, "maxProperties": 4 "name": "John Doe", "age": 30 } } Valid instances: { 3 { "name": "John Doe", "age": 30, "married": true, "living": true } © 2014 The MITRE Corporation. All rights reserved. "name": "John Doe", "age": 30, "married": true, } 1 2 | 196 | But this is also a valid instance { "name": "John Doe", "age": 30, "put-secret-information-in-this-name-field": true, } The value of additional properties are constrained to boolean No constraint on the property name! © 2014 The MITRE Corporation. All rights reserved. | 197 | Constrained additional properties Use the “patternProperties” keyword: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "patternProperties": { "^(married|divorced|living)$": {"type": "boolean"} }, "additionalProperties": false } See example31.1 © 2014 The MITRE Corporation. All rights reserved. Do Lab11 | 198 | Regex for the property name { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"} }, "required": ["name", "age"], "patternProperties": { "^(married|divorced|living)$": {"type": "boolean"} }, "additionalProperties": false } Property names must conform to this regular expression (regex) © 2014 The MITRE Corporation. All rights reserved. | 199 | Valid, invalid instance Valid instance: { "name": "John Doe", "age": 30, "married": true, "living": true } Invalid instance: { "name": "John Doe", "age": 30, "put-secret-information-in-this-name-field": true, } © 2014 The MITRE Corporation. All rights reserved. | 200 | Constraining objects: If the schema has this: then the object can be constrained using this keyword: "type": "object" "enum" "type": "object", "properties": { … } "additionalProperties": false "type": "object", "maxProperties" "properties": { … } "additionalProperties": JSON Schema © 2014 The MITRE Corporation. All rights reserved. | 201 | Multiple Types © 2014 The MITRE Corporation. All rights reserved. | 202 | Instance may be a boolean or a number The value of "type" can be an array of types. This schema says that JSON instances must contain either a boolean value or a number: { "$schema": "http://json-schema.org/draft-04/schema#", "type": [ "boolean", "number" ] } Here are two valid values: true 12 See example32 Do Lab12 © 2014 The MITRE Corporation. All rights reserved. | 203 | Instance may be an array or an object This says that JSON instances must be either an array or an object: "type": ["array", "object"] The following schema constrains the array, if present, to 3 integers in the range 0-100, and constrains the object, if present, to exactly two properties – name and age – and no others: Next slide © 2014 The MITRE Corporation. All rights reserved. | 204 | Well-constrained array or object { "$schema": "http://json-schema.org/draft-04/schema#", "type": ["array", "object"], "maxItems": 3, "items": { "type": "integer", "minimum": 0, "maximum": 100 }, "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "[a-zA-Z ]+" }, "age": { "type": "integer", "minimum": 0, "maximum": 100 } }, "required": ["name", "age"], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 205 | Well-constrained array or object { "$schema": "http://json-schema.org/draft-04/schema#", "type": ["array", "object"], "maxItems": 3, "items": { "type": "integer", "minimum": 0, "maximum": 100 }, "properties": { "name": { "type": "string", "maxLength": 20, "pattern": "[a-zA-Z ]+" }, "age": { "type": "integer", "minimum": 0, "maximum": 100 } }, "required": ["name", "age"], "additionalProperties": false } Here are two valid values: [12, 3, 99] { "name": "John Doe", "age": 30 See example33 © 2014 The MITRE Corporation. All rights reserved. } | 206 | Annotating Schemas © 2014 The MITRE Corporation. All rights reserved. | 207 | Comments for humans The "description" keyword is used to provide a human-readable description. The value of "description" is any string. It is ignored in validation. The "title" keyword is a short human-readable title. { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Short title", "description": "This description can be arbitrarily long " } These keywords may be used in the root schema and in subschemas. © 2014 The MITRE Corporation. All rights reserved. | 208 | Nice example of using description and title { "$schema": "http://json-schema.org/draft-04/schema#", "title": "map.feature.plot", "description": "Plots feature data on the map.", "type": "object", "properties": { "overlayId": { "description": "The ID of the overlay this feature should be loaded into. If an overlay with this ID already exists, the new feature is merged into existing overlay; otherwise, a new overlay is created. If no overlayId is included, default overlay with ID equal to sending widget\u2019s ID is used. If an overlay exists, it will retain its status (whether visible or hidden). If an overlay is created, it will be made visible.", "type": "string" }, "featureId": { "description": "Unique identifier for the given feature data. Note that feature IDs MUST be unique within a given overlay. Reusing a feature ID will be considered a reload, with the original feature data being removed and replaced by the new feature data.", "type": "string" }, "name": { "description": "Name for the given feature data. Note that feature names do not have to be unique and are intended for display purposes only.", "type": "string" }, … } } https://github.com/CMAPI/cmapi-1.2.0/blob/master/channels/map.feature.plot.js © 2014 The MITRE Corporation. All rights reserved. | 209 | Not © 2014 The MITRE Corporation. All rights reserved. | 210 | “Here’s what I don’t want” The "not" keyword is used to specify what you don't want. This schema says that JSON instances can contain any value, as long as it's not a string: { "$schema": "http://json-schema.org/draft-04/schema#", "not": { "type": "string" } } Here are two valid values: true ["Hello", "World"] See example34 Do Lab13 © 2014 The MITRE Corporation. All rights reserved. | 211 | Use case: identifier must not be a reserved word { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "identifier": { "type": "string", "maxLength": 20, "pattern": "^[a-zA-Z][a-zA-Z0-9]*$", "not": {"enum": ["if", "then", "else", "case", "let", "var"]} } } The value of an identifier must not be any of these reserved words: } Valid instance: { Invalid instance: { "identifier": "X" } © 2014 The MITRE Corporation. All rights reserved. "identifier": "if" } See example34.1 | 212 | Use case: ban properties { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "length": { "type": "number", "minimum": 0 }, "width": { "type": "number", "minimum": 0 }, "radius": { "type": "number", "minimum": 0 }, "diameter": { "type": "number", "minimum": 0 } }, "additionalProperties": false, "allOf": [ { "not": {"required": ["radius"]} }, { "not": {"required": ["diameter"]} } ] Ban the presence of radius and diameter in instances } Valid instance: { Invalid instance: { "length": 10, "width": 5 } © 2014 The MITRE Corporation. All rights reserved. "length": 10, "radius": 9 } See example34.2 | 213 | Repository of schemas © 2014 The MITRE Corporation. All rights reserved. | 214 | Creating a repository of schemas The "definitions" keyword is used to define a repository of schemas. The value of "definitions" is a JSON object which contains one or more properties and the value of each property is a schema: "definitions": { "property1": JSON Schema "property2": JSON Schema … } © 2014 The MITRE Corporation. All rights reserved. | 215 | Repository with 2 schemas { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ], "additionalProperties": false }, "evens": { "type": "number", "multipleOf": 2 } } } See example35 © 2014 The MITRE Corporation. All rights reserved. 2 schemas | 216 | Referencing a schema The "$ref" keyword is used to reference a schema: "$ref": reference to a json-schema The value of "$ref" is a path expression (very similar to path expressions in XPath). A json-schema validator replaces "$ref" and its value by the schema that it references. © 2014 The MITRE Corporation. All rights reserved. | 217 | Internal reference The "$ref" in the following schema references the evens schema. The # symbol indicates an internal reference; specifically, it references the schema within "evens" that is within "definitions": { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ], "additionalProperties": false }, "evens": { "type": "number", "multipleOf": 2 } }, "$ref": "#/definitions/evens" } © 2014 The MITRE Corporation. All rights reserved. See example36 Do Lab14 | 218 | Equivalent { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ], "additionalProperties": false }, "evens": { "type": "number", "multipleOf": 2 } }, "$ref": "#/definitions/evens" } equivalent { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "multipleOf": 2 } © 2014 The MITRE Corporation. All rights reserved. | 219 | External reference "$ref" can reference a schema in another document, as shown here: { "$schema": "http://json-schema.org/draft-04/schema#", "$ref": "definitions.json#/definitions/evens" } © 2014 The MITRE Corporation. All rights reserved. | 220 | Reference parent schema "$ref" can reference any schema, including the schema it is contained within: { "$schema": "http://json-schema.org/draft-04/schema#", "$ref": "#" } That schema is valid: it validates against the JSON schema-forschemas. However, when a JSON instance is validated against that schema, an infinite loop error will be generated. There are schemas which are perfectly valid but have no conforming instances. © 2014 The MITRE Corporation. All rights reserved. | 221 | Schema-for-schema uses "definitions" and "$ref" { "$schema": "http://json-schema.org/draft-04/schema, "definitions": { … "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, … "required": { "$ref": "#/definitions/stringArray" }, … } © 2014 The MITRE Corporation. All rights reserved. | 222 | Schema-for-schema references itself { "$schema": "http://json-schema.org/draft-04/schema, … "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, … } © 2014 The MITRE Corporation. All rights reserved. | 223 | "definitions" can be in a subschema The "definitions" keyword does not have to be at the root schema level. It can be embedded in a subschema and then referenced, as shown here: { "$schema": "http://json-schema.org/draft-04/schema#", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$", "definitions": { "evens": { "type": "number", "multipleOf": 2 } } }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "$ref": "#/properties/name/definitions/evens" } See example37 © 2014 The MITRE Corporation. All rights reserved. | 224 | Where is $ref defined in the specs? $ref is defined in a separate document, JSON Reference. The JSON Core specification just references it: http://json-schema.org/latest/json-schema-core.html#anchor26 Here is the JSON Reference specification: http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 © 2014 The MITRE Corporation. All rights reserved. | 225 | How to reference these values reference the first array value { "foo": ["bar", "baz"], "": 0, " ": 7, reference the value of a property whose name is the empty string } reference the value of a property whose name is a space © 2014 The MITRE Corporation. All rights reserved. | 226 | Here’s how to reference the values { "foo": ["bar", "baz"], "": 0, " ": 7, } # #/foo #/foo/0 #/ #/%20 // the whole document ["bar", "baz"] "bar" 0 7 © 2014 The MITRE Corporation. All rights reserved. | 227 | How to reference the first "Name" property? { "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "Id": { "description": "The unique identifier for a product", "type": "integer" }, "Name": { "description": "Name of the product", "type": "string" }, "Name": {"type": "integer"}, "Price": { "type": "number", "minimum": 0, "maximum": 10, "exclusiveMinimum": true } }, "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. How to reference the value of this "Name"? How to reference the value of this "Name"? | 228 | Don’t use duplicate "Name" properties Although technically it has been argued that JSON allows for duplicate keys, it is discouraged and many (most?) JSON parsers will either raise an error or drop one of the values. (Note that I'm referring to JSON, not JSON Schema). As such, you should avoid the duplicate "Name" properties in the first place. Google "JSON duplicate keys" for some good discussions on the topic. Chris White The possibility of having duplicate keys in a JSON object is widely considered to be a bug in the JSON spec. Most parsers do not support it (and will silently pick one value or another), and in the discussion I've seen about updating the JSON standard, cleaning up this issue by disallowing multiple properties is pretty uncontroversial. So basically, don't have multiple "Name" entries in your schema object. :) This isn't just a JSON Pointer or JSON Schema thing, but duplicate key names is a very bad idea in JSON data of any sort. Geraint David Luff © 2014 The MITRE Corporation. All rights reserved. | 229 | Multiple occurrences of a keyword It is okay to have multiple occurrences of the same keyword if they are in different schemas. In the following schema one "maxLength" is in the root schema and the other is in a subschema { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 5, "allOf": [ { "maxLength": 7 } ] } © 2014 The MITRE Corporation. All rights reserved. | 230 | Multiple occurrences of a keyword It is not okay to have multiple occurrences of the same keyword if they are in the same schema. This is not legal: { "type": "string", "pattern": "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$", "pattern": "^[0-9]{3}-[0-9]{3}-[0-9]{4}$" } © 2014 The MITRE Corporation. All rights reserved. | 231 | oneOf © 2014 The MITRE Corporation. All rights reserved. | 232 | Choice of schemas A choice of schemas can be created using the "oneOf" keyword. The value of "oneOf" is an array and each item in the array must be a schema: { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ JSON Schema, JSON Schema, … ] } © 2014 The MITRE Corporation. All rights reserved. | 233 | Either a number or a boolean This schema says that a JSON instance must contain either a number or a boolean: { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ {"type": "number"}, {"type": “boolean"} ] } Here are two valid values: 12 true See example38 Do Lab15 © 2014 The MITRE Corporation. All rights reserved. | 234 | Equivalent { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ {"type": "number"}, {"type": “boolean"} ] } equivalent { "$schema": "http://json-schema.org/draft-04/schema#", "type": [ "boolean", "number" ] } © 2014 The MITRE Corporation. All rights reserved. | 235 | A multiple of 3 or multiple of 5 This schema says that a JSON instance must contain a number that is either a multiple of 3 or a multiple of 5: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "oneOf": [ { "multipleOf": 3 }, { "multipleOf": 5 } ] } Here are two valid values: See example39 © 2014 The MITRE Corporation. All rights reserved. 9 10 | 236 | Content of "oneOf" are schemas? { "$schema": "http://json-schema.org/draft-04/schema#", "type": "number", "oneOf": [ {"multipleOf": 3}, {"multipleOf": 5} ] } Hold on, those aren’t schemas © 2014 The MITRE Corporation. All rights reserved. | 237 | Here’s how "oneOf" really works { The “base” schema. The instance must validate against the base schema. © 2014 The MITRE Corporation. All rights reserved. "$schema": "http://json-schema.org/draft-04/schema#", A, "oneOf": [ { B }, {C} ], D } | 238 | Here’s how "oneOf" really works { The subschemas. The instance must validate against one of the subschemas. © 2014 The MITRE Corporation. All rights reserved. "$schema": "http://json-schema.org/draft-04/schema#", A, "oneOf": [ { B }, {C} ], D } | 239 | Here’s how "oneOf" really works { "$schema": "http://json-schema.org/draft-04/schema#", A, "oneOf": [ { B }, {C} ], D } The instance must validate against the base schema and one of the subschemas. © 2014 The MITRE Corporation. All rights reserved. | 240 | One of the choices can be the empty schema The following schema says that an instance value must be either anything or a number: { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ {}, {"type": "number"} ] } Here are two valid values: See example40 © 2014 The MITRE Corporation. All rights reserved. true [ "Hello", "World" ] | 241 | Is this a valid value? { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ {}, {"type": "number"} ] } Is this a valid value? © 2014 The MITRE Corporation. All rights reserved. 12 | 242 | No! 12 is an invalid instance because it matches both schemas listed in "oneOf" An instance must validate against exactly one of the schemas listed in "oneOf" © 2014 The MITRE Corporation. All rights reserved. | 243 | One of the choices ref’s the parent schema The following schema is a valid schema: { "$schema": "http://json-schema.org/draftv4/schema#", "oneOf": [ {"type": "number"}, { "$ref": "#" } ] } However, when an instance document is validated against the schema, the validator will throw an infinite-loop error. See example41 © 2014 The MITRE Corporation. All rights reserved. | 244 | Ref to schemas within "definitions" This schema says that a JSON instance must contain either a person object or an even number: { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ], "additionalProperties": false }, "evens": { "type": "number", "multipleOf": 2} }, "oneOf": [ {"$ref": "#/definitions/person"}, {"$ref": "#/definitions/evens"} ] } See example42 © 2014 The MITRE Corporation. All rights reserved. | 245 | Schema-valid values Here are two values that validate against the schema on the previous slide: 12 { "name": "John Doe", "age": 30 } © 2014 The MITRE Corporation. All rights reserved. | 246 | Create a schema for this problem Instances must contain this property: "common" Instances must contain either an "a" property or a "b" property So, instances must contain "common" and "a" or "common" and "b" Instances must not contain anything else. Create the schema for this. "common": … choice "a": … "b": … © 2014 The MITRE Corporation. All rights reserved. | 247 | Here’s the schema { "type": "object", "properties": { "common": { "type": "string" }, "a": { "type": "integer" }, "b": { "type": "integer" } }, "required":["common"], "additionalProperties": false, "oneOf": [ { "required": ["a"] }, { "required": ["b"] } ] } See example43 © 2014 The MITRE Corporation. All rights reserved. | 248 | allOf © 2014 The MITRE Corporation. All rights reserved. | 249 | Value of the "allOf" keyword The value of the "allOf" keyword is an array. Each item in the array is a schema. { "$schema": "http://json-schema.org/draft-04/schema#", "allOf": [ JSON Schema, JSON Schema, … ] } © 2014 The MITRE Corporation. All rights reserved. | 250 | The "allOf" keyword An instance must validate against the base schema and it must validate against each schema specified within "allOf". Example: the schema on the next slide says that an instance must conform to the "person" schema and it must have a "height" property. © 2014 The MITRE Corporation. All rights reserved. | 251 | Instance must conform to 2 subschemas { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ] }, "evens": { "type": "number", "multipleOf": 2} }, "allOf": [ {"$ref": "#/definitions/person"}, Instances must { conform to these "type": "object", 2 subschemas "properties": { "height": { "type": "number", "minimum": 0 } }, "required": [ "height" ] } ], "maxProperties": 3 } © 2014 The MITRE Corporation. All rights reserved. See example44 | 252 | Valid instance { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ] }, "evens": { "type": "number", "multipleOf": 2} }, "allOf": [ {"$ref": "#/definitions/person"}, { "type": "object", "properties": { "height": { "type": "number", "minimum": 0 } }, "required": [ "height" ] } ], "maxProperties": 3 } { "name": "John Doe", "age": 30, "height": 68 } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 253 | First, validate against the base schema { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ] }, "evens": { "type": "number", "multipleOf": 2} }, "allOf": [ {"$ref": "#/definitions/person"}, { "type": "object", "properties": { "height": { "type": "number", "minimum": 0 } }, "required": [ "height" ] } ], "maxProperties": 3 } { "name": "John Doe", "age": 30, "height": 68 } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 254 | Second, validate against the first subschema { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ] }, "evens": { "type": "number", "multipleOf": 2} }, "allOf": [ {"$ref": "#/definitions/person"}, { "type": "object", "properties": { "height": { "type": "number", "minimum": 0 } }, "required": [ "height" ] } ], "maxProperties": 3 } { "name": "John Doe", "age": 30, "height": 68 } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 255 | Third, validate against the second subschema { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "person": { "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ] }, "evens": { "type": "number", "multipleOf": 2} }, "allOf": [ {"$ref": "#/definitions/person"}, { "type": "object", "properties": { "height": { "type": "number", "minimum": 0 } }, "required": [ "height" ] } ], "maxProperties": 3 } { "name": "John Doe", "age": 30, "height": 68 } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 256 | Instance is valid only if all 3 validations return “valid” valid instance = valid base schema AND valid subschema1 AND valid subschema2 Do Lab16 © 2014 The MITRE Corporation. All rights reserved. | 257 | No valid instances This "allOf" lists two subschemas, one specifies that the instance must be a number while the other specifies that the instance must be a boolean: { "allOf": [ { "type": "number" }, { "type": "boolean" } ] } No instance can conform to both subschemas since the schema requires the value be both a number and a boolean, which is impossible. © 2014 The MITRE Corporation. All rights reserved. | 258 | What instances validate against this schema? { "$schema": "http://json-schema.org/draft-04/schema#", "type" : "object", "allOf" : [ { "properties" : {"last_name" : { "type" : "string" }}, "required": ["last_name"] }, { "properties" : {"first_name" : { "type" : "string" }}, "required": ["first_name"] } ], "additionalProperties": false } See example45 © 2014 The MITRE Corporation. All rights reserved. | 259 | The "allOf" keyword Here is the base schema: { "$schema": "http://json-schema.org/draft-04/schema#", "type" : "object", "allOf" : [ { "properties" : {"last_name" : { "type" : "string" }}, "required": ["last_name"] }, { "properties" : {"first_name" : { "type" : "string" }}, "required": ["first_name"] } ], "additionalProperties": false } Only the empty instance { } validates against the base schema. © 2014 The MITRE Corporation. All rights reserved. | 260 | Instances must validate against 3 schemas Here are the two subschemas defined within "allOf": { "properties" : {"last_name" : { "type" : "string" }}, "required": ["last_name"] } { "properties" : {"first_name" : { "type" : "string" }}, "required": ["first_name"] } An instance must validate against the base schema plus the two subschemas. © 2014 The MITRE Corporation. All rights reserved. | 261 | This instance doesn’t validate Consider this instance: { "last_name": "Doe", "first_name": "John" } Validating that instance yields the error: "last_name and first_name are not allowed by the schema." That's because the base schema does not allow last_name and first_name. © 2014 The MITRE Corporation. All rights reserved. | 262 | And this instance doesn’t validate Consider this instance : {} then the instance validates against the base schema but not the subschemas. Validation yields these errors: "object has missing required properties "last_name" and "object has missing required properties "first_name". © 2014 The MITRE Corporation. All rights reserved. | 263 | { "$schema": "http://json-schema.org/draft-04/schema#", "type" : "object", "allOf" : [ { "properties" : {"last_name" : { "type" : "string" }}, "required": ["last_name"] }, { "properties" : {"first_name" : { "type" : "string" }}, "required": ["first_name"] } ], "additionalProperties": false } This schema has no valid instances! © 2014 The MITRE Corporation. All rights reserved. | 264 | Multiple occurrences of the same keyword, which one wins? This schema has two "maxLength" keywords: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "string", "maxLength": 5, "allOf": [ { "maxLength": 7 } ] } What’s the maximum length of a string: 5 or 7? See example45.1 © 2014 The MITRE Corporation. All rights reserved. | 265 | All constraints must be met Both "maxLength" constraints must be met. The "maxLength": 5 is part of the base schema, so any data will be validated against that first. If that holds true, it will then proceed to "allOf", and the data must also validate against every schema in the allOf array. Good value: "12345" Bad value: "123456" (too long) © 2014 The MITRE Corporation. All rights reserved. | 266 | anyOf © 2014 The MITRE Corporation. All rights reserved. | 267 | Value of the "anyOf" keyword The value of the "anyOf" keyword is an array. Each item in the array is a schema. { "$schema": "http://json-schema.org/draft-04/schema#", "anyOf": [ JSON Schema, JSON Schema, … ] } © 2014 The MITRE Corporation. All rights reserved. | 268 | Semantics of the "anyOf" keyword An instance validates successfully against the "anyOf" keyword if it validates successfully against at least one schema defined by this keyword's value. © 2014 The MITRE Corporation. All rights reserved. | 269 | Example schema using "anyOf" The following schema says that JSON instances can be either a number or a boolean: { "$schema": "http://json-schema.org/draftv4/schema#", "anyOf": [ {"type": "number"}, {"type": "boolean"} ] } Here are two valid values: 12 © 2014 The MITRE Corporation. All rights reserved. false | 270 | "oneOf " versus "anyOf" { "$schema": "http://json-schema.org/draft-04/schema#", "oneOf": [ {}, {"type": "number"} ] } 12 valid JSON Schema Validator JSON Schema Validator invalid 12 See example46 © 2014 The MITRE Corporation. All rights reserved. { "$schema": "http://json-schema.org/draft-04/schema#", “anyOf": [ {}, {"type": "number"} ] } | 271 | "anyOf" specifies required properties The "anyOf" in the following schema says that JSON instances must contain a "name" property, an "age" property, or both. And nothing else: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "anyOf": [ {"required": [ "name" ]}, {"required": [ "age" ]} ], "additionalProperties": false } See example47 © 2014 The MITRE Corporation. All rights reserved. | 272 | Difference between these schemas? { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } } "additionalProperties": false } difference? { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "anyOf": [ {"required": [ "name" ]}, {"required": [ "age" ]} ], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. | 273 | The difference is with an empty instance { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } } "additionalProperties": false The empty object { } is schema-valid } { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "anyOf": [ {"required": [ "name" ]}, {"required": [ "age" ]} ], "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. The empty object { } is not schema-valid | 274 | Each subschema must be processable All subschemas within "anyOf" must be processable by the validator. Thus, instances will fail validation against the following schema because the second subschema within "anyOf" contains an infinite loop (which is not processable): { "$schema": "http://json-schema.org/draftv4/schema#", "anyOf": [ {"type": "number"}, { "$ref": "#" } ] } See example48 © 2014 The MITRE Corporation. All rights reserved. | 275 | default © 2014 The MITRE Corporation. All rights reserved. | 276 | The "default" keyword The "default" keyword is used to provide a default value. The following schema creates an object that has the properties: "title", "name", and "age". The allowable values for "title" is specified using "enum". If a JSON instance does not contain a "title" the value "Mr" is the default. { default value for "title" "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "title": { "type": "string", "enum": ["Mr", "Mrs", "Miss"], "default": "Mr"}, "name": { "type": "string", "maxLength": 20,"pattern": "^[a-zA-Z ]*$" }, "age": { "type": "number", "minimum": 0, "maximum": 120 } }, "required": [ "name", "age" ], "additionalProperties": false } See example49 © 2014 The MITRE Corporation. All rights reserved. | 277 | "default" is ignored by validators The value of "default" is ignored by schema validators. So this is a legal default: "title": { "type": "string", "enum": ["Mr", "Mrs", "Miss"], "default": "BlahBlah"} © 2014 The MITRE Corporation. All rights reserved. | 278 | Expressing co-constraints © 2014 The MITRE Corporation. All rights reserved. | 279 | Expressing co-constraints The "dependencies" keyword enables constraints between properties (a.k.a. co-constraints) to be expressed. Consider properties of these shapes: circle and rectangle. Data for radius and diameter must be provided for circle. Data for width and length must be provided for rectangle. So if there is a radius, there must be a diameter and vice versa. If there is a width, there must be a length and vice versa. The schema on the next slide specifies that radius/diameter and length/width must always occur in pairs. © 2014 The MITRE Corporation. All rights reserved. | 280 | Co-constraint: “If there is a radius, then there must be a diameter and vice versa” { } "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "length": { "type": "number", "minimum": 0 }, "width": { "type": "number", "minimum": 0 }, "radius": { "type": "number", "minimum": 0 }, "diameter": { "type": "number", "minimum": 0 } }, "dependencies": { "radius": ["diameter"], If the instance has "radius" then "diameter": ["radius"], it must also have "diameter" "length": ["width"], and vice versa. "width": ["length"] }, If the instance has “length" then "additionalProperties": false it must also have “width" and See example50 © 2014 The MITRE Corporation. All rights reserved. vice versa. | 281 | Properties must occur in pairs, or it’s invalid Here is a valid instance: { "length": 10, "width": 20 } The following instance is invalid because it has a "length" without the required "width" property: { "length": 10 } © 2014 The MITRE Corporation. All rights reserved. | 282 | Multiple pairs are okay Note that "dependencies" does not prohibit other properties from appearing in instances. For example, this is a valid instance: { "length": 10, "width": 5, "radius": 10, "diameter": 10 } © 2014 The MITRE Corporation. All rights reserved. | 283 | An array list of dependent properties The value of "dependencies" is an object; the value of each object property is an array of strings. The array may contain strings that are not the name of any property, such as this: "radius": ["diameter", "Blah"] If "additionalProperties": false is specified, then "Blah" will not be allowed in instances and there is a paradox: the schema mandates that the instance contain "Blah" whenever it contains "radius" but "additionalProperties": false disallows instances to contain "Blah". © 2014 The MITRE Corporation. All rights reserved. | 284 | No co-constraint between property and value "dependencies" cannot be used to express co-constraints between properties and values. For example, consider a schema with an object that has a "shape" property and an "enum" with values "circle" or "rectangle": { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "shape": { "type": "string", "enum": ["circle", "rectangle"] }, "length": { "type": "number", "minimum": 0 }, "width": { "type": "number", "minimum": 0 }, "radius": { "type": "number", "minimum": 0 }, "diameter": { "type": "number", "minimum": 0 } }, "additionalProperties": false } © 2014 The MITRE Corporation. All rights reserved. It would be useful to express this: If the value of "shape" is "circle" then the "radius" and "diameter" properties must be present. If the value of "shape" is "rectangle" then the "width" and "length" properties must be present. However, that capability is not provided by JSON Schema. | 285 | Property versus schema dependency We have seen that within "dependencies" you specify a property with an array value and each item in the array is the name of another property. This is called a property dependency. There is another way to use "dependencies": you specify a property and the value of it is an object that defines additional properties. This is called a schema dependency. © 2014 The MITRE Corporation. All rights reserved. | 286 | Example of a schema dependency The schema on the following slide says: – If the instance contains the "car" property then the instance must also contain a "numPassengers" property. – If the instance contains the "juicers" property then the instance must also contain a "kind" property. © 2014 The MITRE Corporation. All rights reserved. | 287 | Schema dependency { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "car": { "type": "string", "maxLength": 20 }, "juicer": { "type": "string", "maxLength": 20 } }, "dependencies": { "car": { "type": "object", "properties": { If "numPassengers": { "type": "integer", "minimum": 1 } }, "required": ["numPassengers"] }, "juicer": { "type": "object", "properties": { "kind": { "type": "string", "enum": ["press", "centrifugal"] } }, "required": [“kind"] } } } See example51 © 2014 The MITRE Corporation. All rights reserved. "car" then "numPassengers" If "juicer" then "kind" | 288 | Schema-valid instance { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "car": { "type": "string", "maxLength": 20 }, "juicer": { "type": "string", "maxLength": 20 } }, "dependencies": { "car": { "type": "object", "properties": { "numPassengers": { "type": "integer", "minimum": 1 } }, "required": ["numPassengers"] }, "juicer": { "type": "object", "properties": { "kind": { "type": "string", "enum": ["press", "centrifugal"] } }, "required": [“kind"] } } } { "car": "Toyota Avalon", "numPassengers": 5 } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 289 | An instance could also contain "juicer" and its dependent "kind" property { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "car": { "type": "string", "maxLength": 20 }, "juicer": { "type": "string", "maxLength": 20 } }, "dependencies": { "car": { "type": "object", "properties": { "numPassengers": { "type": "integer", "minimum": 1 } }, "required": ["numPassengers"] }, "juicer": { "type": "object", "properties": { "kind": { "type": "string", "enum": ["press", "centrifugal"] } }, "required": [“kind"] } } } { "car": "Toyota Avalon", "numPassengers": 5, "juicer": "Omega Juicer", "kind": "centrifugal" } JSON Schema Validator © 2014 The MITRE Corporation. All rights reserved. valid! | 290 | Constrain the number of properties If we want to allow just "car" (and its dependent property, "numPassenger") or "juicer" (and its dependent propert, "kind") but not both, use "maxProperties": 2 as shown here: { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "car": { "type": "string", "maxLength": 20 }, "juicer": { "type": "string", "maxLength": 20 } }, "maxProperties": 2, "dependencies": { "car": { "type": "object", "properties": { "numPassengers": { "type": "integer", "minimum": 1 } }, "required": ["numPassengers"] }, "juicer": { "type": "object", "properties": { "kind": { "type": "string", "enum": ["press", "centrifugal"] } }, "required": [“kind"] } } } © 2014 The MITRE Corporation. All rights reserved. Instances can contain no more than 2 properties. | 291 | Recursion © 2014 The MITRE Corporation. All rights reserved. | 292 | Create a schema for this { "book": { "title": "Title 1", "section": { "title": "Title 1.1", "section": { "title": "Title 1.1.1", "section": { "title": "Title 1.1.1.1" } } } } } © 2014 The MITRE Corporation. All rights reserved. A section contains a title and a section. See the recursion? | 293 | Here’s what we want title: string section: © 2014 The MITRE Corporation. All rights reserved. | 294 | Create a recursive "definitions" "definitions": { "section": { "type": "object", "properties": { "title": { "type": "string" }, "section": { "$ref": "#/definitions/section" } }, "required": [ "title" ], "additionalProperties": false } }, © 2014 The MITRE Corporation. All rights reserved. | 295 | Create "book" and set its value to point to the recursive schema "definitions": { "section": { "type": "object", "properties": { "title": { "type": "string" }, "section": { "$ref": "#/definitions/section" } }, "required": [ "title" ], "additionalProperties": false } }, "properties": { "book": { "$ref": "#/definitions/section" } } © 2014 The MITRE Corporation. All rights reserved. | 296 | Here’s the schema { "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "section": { "type": "object", "properties": { "title": { "type": "string" }, "section": { "$ref": "#/definitions/section" } }, "required": [ "title" ], "additionalProperties": false } }, "type": "object", "properties": { "book": { "$ref": "#/definitions/section" } } } See example52 © 2014 The MITRE Corporation. All rights reserved. | 297 | Unbounded nesting The recursive schema on the previous slide allows unbounded nesting. There is no way to limit the amount of nesting or recursion. © 2014 The MITRE Corporation. All rights reserved. The End © 2014 The MITRE Corporation. All rights reserved.