One document matched: draft-snell-json-test-00.xml
<?xml version="1.0"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY rfc2119 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml'>
<!ENTITY jsonpatch PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml3/reference.I-D.draft-ietf-appsawg-json-patch-05.xml'>
]>
<?rfc toc="yes"?>
<?rfc strict="yes"?>
<?rfc symrefs="yes" ?>
<?rfc sortrefs="yes"?>
<?rfc compact="yes"?>
<rfc category="info" ipr="trust200811" docName="draft-snell-json-test-00">
<front>
<title abbrev="application/merge-patch">
JSON Predicate
</title>
<author initials="J.M." surname="Snell" fullname="James M Snell">
<address>
<email>jasnell@gmail.com</email>
</address>
</author>
<date month="October" year="2012" />
<area>Applications</area>
<!-- workgroup>Individual Submission</workgroup-->
<keyword>I-D</keyword>
<keyword>json</keyword>
<keyword>predicate</keyword>
<abstract>
<t>JSON Predicates defines a syntax for serializing various
predicate expressions as JSON Objects.</t>
</abstract>
</front>
<middle>
<section anchor="intro" title="Introduction">
<t>This specification defines JSON Predicates, a JSON-based syntax
for the description and serialization of logical boolean predicate
operations intended to be used in conjunction with other JSON-based
mechanisms, such as JSON Patch, as a means of incorporating conditional
handling during the processing of a JSON document.</t>
<t>For example, JSON Predicates can be used to extend a <xref target="I-D.ietf-appsawg-json-patch">JSON Patch</xref>
document to provide a broader range of conditional processing
options not currently supported by JSON Patch.</t>
<figure><preamble>Example: Given a source JSON document</preamble>
<artwork>
{
"a": {
"b": {
"c": "ABC!XYZ"
}
}
}
</artwork></figure>
<figure><preamble>The following JSON Patch with JSON Predicates document
will first test that the value of the "c" property is a string
containing the character sequence "ABC" prior to applying the specified
"replace" operation.</preamble><artwork>
[
{
"op": "and",
"path": "/a/b",
"apply": [
{
"op": "type-of",
"path": "/a/b/c",
"value": "string"
},
{
"op": "contains",
"path": "/a/b/c",
"value": "ABC"
}
]
},
{
"op": "replace",
"path": "/a/b/c",
"value": 123
}
]
</artwork></figure>
<t>It is important to note this specification does not define a
distinct JSON Predicates Document format. Rather, it is the intent
for JSON Predicates to be used within other JSON-based document
formats, like JSON Patch.</t>
<t>TODO: Lots more needs to be said here.</t>
<t>In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL"
are to be interpreted as described in <xref target="RFC2119" />.</t>
</section>
<section anchor="predicates" title="Predicate Objects">
<t>A JSON Predicate is a JSON Object whose name value
pairs describe a testable conditions that evaluate as either
true or false.</t>
<t>The essential components of a JSON Predicate include:
<list style="symbols">
<t>A label identifying the predicate operation,</t>
<t>A reference to the value that is to be tested, and </t>
<t>A condition against which that referenced value is to be evaluated.</t>
</list>
</t>
<t>Predicate objects MUST have exactly one "op" member whose value
indicates the type of predicate operation to perform. It's value
MUST be one of: "and", "contains", "defined", "ends", "less",
"matches", "more", "not", "or", "starts", "type", or "undefined".
The semantics for each are defined in the sections that follow.</t>
<t>Note that the value of the "op" member is case-sensitive and that
each of the operations listed are in lower-case. The value "Starts",
for example, is not equivalent to "starts".</t>
<t>If the "op" member specifies any value other than one of those
listed above, the evaluation of the predicate operation MUST cease
and treated as if a boolean value of "false" was returned. The
application processing the predicate operation MAY signal that an
error condition has occurred depending on the specific requirements
of the domain within which JSON Predicates are being used.</t>
<t>The remaining structure of each predicate operation depends on it's
specific type. There are two basic types of predicates.
<list style="symbols">
<t>First Order Predicates that are used to test a single
discreet name value pair against a single condition and</t>
<t>Second Order Predicates that aggregate one or
more subordinate First or Second Order Predicates.</t>
</list>
</t>
<t>In addition to the required "op" member, First Order Predicates
MUST have exactly one "path" member whose value MUST be a string
containing a JSON-Pointer value referencing the location of the
name value pair that is to be tested.</t>
<t>Second Order Predicates MUST have exactly one "apply" member
whose value is a JSON Array containing one or more First or
Second Order Predicate Objects.</t>
<t>Additional members can be required depending on the specific
predicate operation. All other members not explicitly defined by
this specification MUST be ignored.</t>
<t>Note that the ordering of members in JSON objects is not significant;
therefore the following operations are equivalent:</t>
<figure><artwork>
{"op": "contains", "path": "/a/b/c", "value": "ABC"}
{"path": "/a/b/c", "op": "contains", "value": "ABC"}
{"value": "ABC", "path": "/a/b/c", "op": "contains"}
</artwork></figure>
<section anchor="context" title="Predicate Context">
<t>All JSON Predicates are evaluated against a given base
context. The nature of this context is dependent entirely
on the application within which JSON Predicates is being
used. For instance, when used together with JSON Patch,
the JSON Predicate operations are evaluated relative to
the JSON document that is the target of the JSON Patch
operation.</t>
<t>Although Predicate Objects use JSON Pointer references
to identify values against which a predicate operation
is evaluated, the base context is not required to be
a JSON object or array. In such cases, however, it is
the responsibility of the application implementation to
determine how to interpret the JSON Pointer reference
relative to the base context.</t>
</section>
<section anchor="first-order-predicates" title="First Order Predicates">
<section anchor="contains" title="contains">
<t>The "contains" predicate evaluates
as true if the referenced element is defined and has a value whose
string representation contains the exact sequence of characters
given by the predicate object's "value" member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": "This is a test"
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true":</preamble><artwork>
{
"op": "contains",
"path": "/a/b",
"value": " is a "
}
</artwork></figure>
<t>By default, character matching MUST be performed in a
case-sensitive manner. To override this default behavior,
the predicate object MAY contain an "ignore_case" member
whose value is either "true" (to perform case-insensitive
matching) or false.</t>
<figure><preamble>For instance, the following will evaluate
as "true":</preamble><artwork>
{
"op": "contains",
"path": "/a/b/",
"value": " Is A ",
"ignore_case": true
}
</artwork></figure>
</section>
<section anchor="defined" title="defined">
<t>The "defined" predicate evaluates
as true if the referenced element exists within the
target context.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": null
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true" because the path "/a/b"
exist within the document despite being explicitly set to
null:</preamble><artwork>
{
"op": "defined",
"path": "/a/b"
}
</artwork></figure>
<figure><preamble>The following predicate would
evaluate as "false" because
the path "/a/c" does exist within the document.</preamble><artwork>
{
"op": "defined",
"path": "/a/c"
}
</artwork></figure>
</section>
<section anchor="ends" title="ends">
<t>The "ends" predicate evaluates
as true if the referenced element is defined and has a value whose
string representation ends with the exact sequence of characters
given by the predicate object's "value"
member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": "This is a test"
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true":</preamble><artwork>
{
"op": "ends",
"path": "/a/b",
"value": " test"
}
</artwork></figure>
<t>By default, character matching MUST be performed in a
case-sensitive manner. To override this default behavior,
the predicate object MAY contain an "ignore_case" member
whose value is either "true" (to perform case-insensitive
matching) or false.</t>
<figure><preamble>For instance, the following will evaluate as
"true":</preamble><artwork>
{
"op": "ends",
"path": "/a/b/",
"value": " TEST",
"ignore_case": true
}
</artwork></figure>
</section>
<section anchor="less" title="less">
<t>The "less" predicate evaluates
as true if the referenced element is defined and specifies a number
whose value is less than that specified by the predicate object's
"value" member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": 10
}
}
</artwork></figure>
<figure><preamble>The following will evaluate as
"true":</preamble><artwork>
{
"op": "less",
"path": "/a/b",
"value": 15
}
</artwork></figure>
</section>
<section anchor="matches" title="matches">
<t>The "matches" predicate evaluates
as true if the referenced element is defined and has a value whose
string representation matches the regular expression provided by the
predicate object's "value" member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": "this is a test"
}
}
</artwork></figure>
<figure><preamble>The following evalutes as
"true":</preamble><artwork>
{
"op": "matches",
"path": "/a/b",
"value": "[\\w\\s]*"
}
</artwork></figure>
<t>The predicate's matching pattern is expressed as a string
value conforming to the JavaScript Regular Expression syntax.</t>
<t>By default, character matching MUST be performed in a
case-sensitive manner. To override this default behavior,
the predicate object MAY contain an "ignore_case" member
whose value is either "true" (to perform case-insensitive
matching) or false. Setting the value of "ignore_case" to
true is equivalent to using the "i" modifier flag within
the JavaScript Regular Expression syntax (e.g. "/\w\s/*/i").</t>
<figure><preamble>For instance:</preamble><artwork>
{
"op": "ends",
"path": "/a/b/",
"value": "[\\w\\s]*",
"ignore_case": true
}
</artwork></figure>
</section>
<section anchor="more" title="more">
<t>The "more" predicate evaluates
as true if the referenced element is defined and specifies a number
whose value is greater than that specified by the predicate object's
"value" member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": 10
}
}
</artwork></figure>
<figure><preamble>The following will evaluate as
"true":</preamble><artwork>
{
"op": "more",
"path": "/a/b",
"value": 5
}
</artwork></figure>
</section>
<section anchor="starts" title="starts">
<t>The "starts" predicate evaluates
as true if the referenced element is defined and has a value whose
string representation begins with the exact sequence of characters
given by the predicate object's "value" member.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": "This is a test"
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true":</preamble><artwork>
{
"op": "starts",
"path": "/a/b",
"value": "This "
}
</artwork></figure>
<t>By default, character matching MUST be performed in a
case-sensitive manner. To override this default behavior,
the predicate object MAY contain an "ignore_case" member
whose value is either "true" (to perform case-insensitive
matching) or false.</t>
<figure><preamble>For instance, the following will evaluate as "true":</preamble><artwork>
{
"op": "starts",
"path": "/a/b/",
"value": "this ",
"ignore_case": true
}
</artwork></figure>
</section>
<section anchor="type" title="type">
<t>The "type" predicate
evaluates as true if the referenced element exists and specifies
a value whose JSON type is equal to that specified by the predicate's
"value" member.</t>
<t>The "value" member MUST specify one of: "number",
"string", "boolean", "object", "array", "null" or
"undefined".</t>
<figure><preamble>For example, given the JSON document:</preamble><artwork>
{
"a": {
"b": "this is a test",
"c": [1,2,3]
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true"</preamble><artwork>
{
"op": "type",
"path": "/a/b",
"value": "string"
}
</artwork></figure>
<t>Note that the "type" predicate
is generally identical to JavaScript's built in "typeof"
operator with the exception that JavaScript's operator does
not distinguish between Array and Object types. That is, when
executing the JavaScript code "typeof doc.a.c"
against the example JSON document given above, JavaScript will
report the type as "object" rather than "array". By contrast, the
"type" predicate distinguishes
the two types of values.</t>
</section>
<section anchor="undefined" title="undefined">
<t>The "undefined" predicate evaluates
as true if the referenced element does not exist within the
target context.</t>
<figure><preamble>For example, given the JSON document:</preamble>
<artwork>
{
"a": {
"b": null
}
}
</artwork></figure>
<figure><preamble>The following predicate would evaluate as
"true" because the path "/a/c"
does not exist within the document:</preamble><artwork>
{
"op": "undefined",
"path": "/a/c"
}
</artwork></figure>
<figure><preamble>However, the following predicate would
evaluate as "false" because
the path "/a/b" does exist within the document, despite
specifying an explicit null value.</preamble><artwork>
{
"op": "undefined",
"path": "/a/b"
}
</artwork></figure>
</section>
</section>
<section anchor="second-order-predicates" title="Second-Order Predicates">
<t>Second Order Predicates are defined as sets of one or more
subordinate First and Second Order Predicates.</t>
<t>All Second Order Predicates MAY contain a "path" member whose
value specifies a root path prefix for all contained predicates.
For example, given the JSON document:</t>
<figure><artwork>
{
"a": {
"b": {
"c": "ABC!"
}
}
}
</artwork></figure>
<figure><preamble>The following would evaluate as true because the path
"/a/b/c" is defined.</preamble><artwork>
{
"op": "and",
"path": "/a/b",
"apply": [
{
"op": "defined",
"path": "/c"
}
]
}
</artwork></figure>
<figure><preamble>The above example is equivalent to:</preamble><artwork>
{
"op": "and",
"apply": [
{
"op": "defined",
"path": "/a/b/c"
}
]
}
</artwork></figure>
<section anchor="and" title="and">
<t>The "and" predicate evaluates as
"true" if all of it's contained set
of predicate operations evaluate as "true".</t>
<figure><preamble>For example, given the JSON document:</preamble><artwork>
{
"a" : {
"b" : "foo",
"c" : {
"d": 10
}
}
}
</artwork></figure>
<figure><preamble>The following would evaluate as "true"
because the element "/a/b" is defined and the value of element "/a/c/d" is less than
15.</preamble><artwork>
{
"op": "and",
"apply" [
{
"op": "defined",
"path": "/a/b"
},
{
"op": "less",
"path": "/a/c/d",
"value": 15
}
]
}
</artwork></figure>
<figure><preamble>However, the following would evaluate as
"false" because the while element
"/a/c" exists, the value of that element is not a
string.</preamble><artwork>
{
"op": "and",
"apply": [
{
"op": "test",
"path": "/a/c"
},
{
"op": "type",
"path": "/a/c",
"value": "string"
}
]
}
</artwork></figure>
</section>
<section anchor="not" title="not">
<t>The "not" predicate evaluates as
"true" if all of it's contained set of predicate
operations evaluate as "false".</t>
<figure><preamble>For example, given the JSON document:</preamble><artwork>
{
"a" : {
"b" : "foo",
"c" : {
"d": 10
}
}
}
</artwork></figure>
<figure><preamble>The following would evaluate as "true"
because the element "/a/b/e" is undefined and the value of element "/a/c/d" is
not less than 5.</preamble><artwork>
{
"op": "not",
"apply": [
{
"op": "defined",
"path": "/a/b/e"
},
{
"op": "less",
"path": "/a/c/d",
"value": 5
}
]
}
</artwork></figure>
<figure><preamble>However, the following would evaluate as
"false" because the element "/a/c"
exists and the value for element "/a/b" begins with the letter
"f"</preamble><artwork>
{
"op": "not",
"apply": [
{
"op": "undefined",
"path": "/a/c"
},
{
"op": "starts",
"path": "/a/b",
"value": "f"
}
]
}
</artwork></figure>
</section>
<section anchor="or" title="or">
<t>The "or" predicate evaluates as
"true" if at least one of it's contained
set of predicate operations evaluate as "true".</t>
<figure><preamble>For example, given the JSON
document:</preamble><artwork>
{
"a" : {
"b" : "foo",
"c" : {
"d": 10
}
}
}
</artwork></figure>
<figure><preamble>The following would evaluate as "true"
because the element "/a/b" is defined.</preamble><artwork>
{
"op": "or",
"apply": [
{
"op": "defined",
"path": "/a/b"
},
{
"op": "less",
"path": "/a/c/d",
"value": 5
}
]
}
</artwork></figure>
<figure><preamble>However, the following would evaluate as
"false" because neither elements "/a/e" or "/a/f" exist.</preamble><artwork>
{
"op": "or",
"apply": [
{
"op": "test",
"path": "/a/e"
},
{
"op": "test",
"path": "/a/f"
}
]
}
</artwork></figure>
</section>
<section title="Nesting Second Order Predicates">
<t>Second Order Predicates can be combined in a variety
of ways to define more complex test operations. For example:</t>
<figure><artwork>
{
"op": "or",
"apply": [
{
"op": "not",
"apply": [
{
"op": "defined",
"path": "/a/b/c"
},
{
"op": "starts",
"path": "/a/b/c",
"value": "f"
}
]
},
{
"op": "not",
"apply": [
{
"op": "defined",
"path": "/a/b/d"
},
{
"op": "type",
"path": "/a/b/d",
"value": "number"
}
]
}
]
}
</artwork></figure>
</section>
</section>
<section anchor="error-handling" title="Error Handling">
<t>When an error condition is encounted during the processing of a
JSON Predicate, the predicate MUST evaluate as false.</t>
<t>Error conditions can arise in each of the following conditions:
<list style="symbols">
<t>JSON Predicate Objects contained within a document fail to
conform to any normative requirement of this specification, or</t>
<t>The Predicate Object specifies an unknown predicate operation, or</t>
<t>The Predicate Object specifies a JSON Pointer referencing
a value that does not exist and the specified Predicate operation
is not specifically intended to test for the absence of a value
(i.e. the "undefined" predicate), or</t>
<t>A First Order Predicate Object specifies a predicate operation
that requires a "value" member
providing the condition to test but no "value"
member is provided.</t>
</list>
</t>
</section>
<section anchor="json-patch" title="Using JSON Predicate within JSON Patch Documents">
<t>While JSON Predicate objects can be used in a variety of applications,
the syntax has been specifically designed for compatibility with the
JSON Patch Document format. JSON Predicate objects MAY be used directly
within a JSON Patch Document as tests to evaluate whether or not the
application of a set of patch operations should succeed or fail.</t>
<figure><preamble>For example, given the following JSON document:</preamble>
<artwork>
{
"a": {
"b": {
"c": "123"
}
}
}
</artwork></figure>
<figure><preamble>The following JSON Patch + JSON Predicates document will
first test that the path "/a/b/c" references a value matching the given
regular expression prior to replacing that value:</preamble><artwork>
[
{
"op": "matches",
"path": "/a/b/c",
"value": "\\d{3}"
},
{
"op": "replace",
"path": "/a/b/c",
"value": "ABC"
}
]
</artwork></figure>
<t>When a JSON Predicate object within a JSON Patch document evaluates as
false, processing of the JSON Patch Document MUST be handled exactly the
same as an unsuccessful JSON Patch operation would be handled as defined
in <xref target="I-D.ietf-appsawg-json-patch">JSON-PATCH</xref>, Section 5.
Specifically, processing of the JSON Patch document SHOULD terminate and
application of the entire patch document SHALL NOT be deemed successful.</t>
<t>Note that JSON Patch implementations that do not implement or recognize
JSON Predicate objects will treat such objects as unknown patch operations
that will cause evaluation of the Patch document to fail.</t>
</section>
</section>
<section title="Security Considerations">
<t>JSON Predicate objects do not, by themselves, introduce any particular
security concerns. Note that JSON documents that consist of an arbitrary
number of nested Second Order Predicate objects can have a detrimental
impact on overall performance and could be leveraged by a malicious
entity as part of a denial of service attack.</t>
</section>
</middle>
<back>
<references title="Normative References">
&rfc2119;
&jsonpatch;
</references>
</back>
</rfc>
| PAFTECH AB 2003-2026 | 2026-04-24 05:24:29 |