Open Geospatial Consortium

Submission Date: <yyyy-mm-dd>

Approval Date:  <yyyy-mm-dd>

Publication Date:  <yyyy-mm-dd>

External identifier of this OGC® document: http://www.opengis.net/doc/IS/ogcapi-features-3/1.0

Internal reference number of this OGC® document:    19-079

Version: 1.0.0-SNAPSHOT (Editor’s draft)

Latest Published Draft: n/a

Category: OGC® Implementation Specification

Editors: TBD

OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)

Copyright notice

Copyright © 2019 Open Geospatial Consortium

To obtain additional rights of use, visit http://www.opengeospatial.org/legal/

Warning

This document is not an OGC Standard. This document is distributed for review and comment. This document is subject to change without notice and may not be referred to as an OGC Standard.

Recipients of this document are invited to submit, with their comments, notification of any relevant patent rights of which they are aware and to provide supporting documentation.

Document type:    OGC® Standard

Document subtype:    Interface

Document stage:    Draft

Document language:  English

License Agreement

Permission is hereby granted by the Open Geospatial Consortium, ("Licensor"), free of charge and subject to the terms set forth below, to any person obtaining a copy of this Intellectual Property and any associated documentation, to deal in the Intellectual Property without restriction (except as set forth below), including without limitation the rights to implement, use, copy, modify, merge, publish, distribute, and/or sublicense copies of the Intellectual Property, and to permit persons to whom the Intellectual Property is furnished to do so, provided that all copyright notices on the intellectual property are retained intact and that each person to whom the Intellectual Property is furnished agrees to the terms of this Agreement.

If you modify the Intellectual Property, all copies of the modified Intellectual Property must include, in addition to the above copyright notice, a notice that the Intellectual Property includes modifications that have not been approved or adopted by LICENSOR.

THIS LICENSE IS A COPYRIGHT LICENSE ONLY, AND DOES NOT CONVEY ANY RIGHTS UNDER ANY PATENTS THAT MAY BE IN FORCE ANYWHERE IN THE WORLD.

THE INTELLECTUAL PROPERTY IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE DO NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE INTELLECTUAL PROPERTY WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION OF THE INTELLECTUAL PROPERTY WILL BE UNINTERRUPTED OR ERROR FREE. ANY USE OF THE INTELLECTUAL PROPERTY SHALL BE MADE ENTIRELY AT THE USER’S OWN RISK. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY CONTRIBUTOR OF INTELLECTUAL PROPERTY RIGHTS TO THE INTELLECTUAL PROPERTY BE LIABLE FOR ANY CLAIM, OR ANY DIRECT, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM ANY ALLEGED INFRINGEMENT OR ANY LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR UNDER ANY OTHER LEGAL THEORY, ARISING OUT OF OR IN CONNECTION WITH THE IMPLEMENTATION, USE, COMMERCIALIZATION OR PERFORMANCE OF THIS INTELLECTUAL PROPERTY.

This license is effective until terminated. You may terminate it at any time by destroying the Intellectual Property together with all copies in any form. The license will also terminate if you fail to comply with any term or condition of this Agreement. Except as provided in the following sentence, no such termination of this license shall require the termination of any third party end-user sublicense to the Intellectual Property which is in force as of the date of notice of such termination. In addition, should the Intellectual Property, or the operation of the Intellectual Property, infringe, or in LICENSOR’s sole opinion be likely to infringe, any patent, copyright, trademark or other right of a third party, you agree that LICENSOR, in its sole discretion, may terminate this license without any compensation or liability to you, your licensees or any other party. You agree upon termination of any kind to destroy or cause to be destroyed the Intellectual Property together with all copies in any form, whether held by you or by any third party.

Except as contained in this notice, the name of LICENSOR or of any other holder of a copyright in all or part of the Intellectual Property shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Intellectual Property without prior written authorization of LICENSOR or such copyright holder. LICENSOR is and shall at all times be the sole entity that may authorize you or any third party to use certification marks, trademarks or other special designations to indicate compliance with any LICENSOR standards or specifications. This Agreement is governed by the laws of the Commonwealth of Massachusetts. The application to this Agreement of the United Nations Convention on Contracts for the International Sale of Goods is hereby expressly excluded. In the event any provision of this Agreement shall be deemed unenforceable, void or invalid, such provision shall be modified so as to make it valid and enforceable, and as so modified the entire Agreement shall remain in full force and effect. No decision, action or inaction by LICENSOR shall be construed to be a waiver of any rights or remedies available to it.

i. Abstract

OGC API standards define modular API building blocks to spatially enable Web API in a consistent way. The OpenAPI specification is used to define the API building blocks.

OGC API Features provides API building blocks to create, modify and query features on the Web. OGC API Features is comprised of multiple parts, each of them is a separate standard.

A fundamental operation performed on a collection of resources is that of querying in order to obtain a subset of the data which contains resource instances that satisfy some filtering criteria. This part, part 4, defines an encoding for specifying enhanced filtering criteria in a request to a server, beyond what is supported in the core called the Common Query Language.

The common query language defined in this document is used to specify how resource instances in a source collection should be filter to identify a result set. Typically, CQL is used in query operations to identify the subset of resources that should be included in a response document. However, CQL may also be used in other operations (e.g. updates) to identify the subset of resources that should be affected by an operation.

Each resource instance in the source collection is evaluated using a filtering expression encoded using the common query language. The overall filter expression always evaluates to true or false. If the expression evaluates to true, the resource instance satisfies the expression and is marked as being in the result set. If the overall filter expression evaluates to false, the data instance is not in the result set. Thus, the net effect of evaluating a filter expression is a set of resources that satisfy the predicates in the expression.

Caution
This is a DRAFT version of the nth part of the OGC API - Features standards. This draft is not complete and there are open issues that are still under discussion.

ii. Keywords

The following are keywords to be used by search engines and document catalogues.

common query language, filter, expression, query, SQL, CQL, where clause, selection clause,

iii. Preface

Attention is drawn to the possibility that some of the elements of this document may be the subject of patent rights. The Open Geospatial Consortium Inc. shall not be held responsible for identifying any or all such patent rights.

Recipients of this document are requested to submit, with their comments, notification of any relevant patent claims or other intellectual property rights of which they may be aware that might be infringed by any implementation of the standard set forth in this document, and to provide supporting documentation.

iv. Submitting organizations

The following organizations submitted this document to the Open Geospatial Consortium (OGC):

  • CubeWerx Inc.

  • interactive instruments GmbH

  • Heazeltech LLC

v. Submitters

All questions regarding this submission should be directed to the editors or the submitters:

Name

Affiliation

Panagiotis (Peter) A. Vretanos (editor)_

CubeWerx Inc.

Clemens Portele (editor)

interactive instruments GmbH

Charles Heazel (editor)

Heazeltech LLC

1. Scope

This document specifies an extension to the OGC API - Features - Part 1: Core standard that defines the behaviour of a server that supports enhanced filtering capabilities expressed using a common query language (CQL).

Enhanced filtering capabilities in this case means that the server supports the ability to define selection clauses using predicates beyond those supported by the OGC API Common specification (i.e. bbox and datetime).

This document defines a text encoding for a CQL filter suitable for use as a query parameter in a URL.

This document defines a JSON encoding for a CQL filter suitable for use in a HTTP POST body.

This document defines the schema for a JSON document that exposes the set of properties or keys that may be used to construct CQL expressions.

2. Conformance

This standard defines the following conformance classes:

The Filter conformance class defines a set of HTTP query parameters that may be used to specify complex filter expressions on HTTP requests. The specific set of parameters defined in this conformance class are:

  • filter

  • filter-lang

  • filter-crs

This conformance class also defined the resources /queryables and /collections/{collectionId}/queryables that can be used to determine the list of property names and types that may be used to construct filter expressions.

The Features Filter conformance class defines the binding between this the Filter conformance class the OGC API - Features - Part 1: Core standard.

The Simple CQL conformance class defines the Simple Common Query Language (CQL). Simple CQL is intended to be a minimal useful set of predicates that support enhanced fine-grained read-access to collections of resources. In this case enhanced means filtering capabilities beyond those supported by the core OGC API Common specification (i.e. bbox and datetime). The specific set of operators defined in this conformance class are:

  • Logical operators:

    • and

    • or

    • not

  • Comparison operators:

    • equal to

    • less than

    • less than or equal to

    • greater than

    • greater than or equal to

    • like

    • is null

    • between

    • in

  • Spatial operators:

    • intersects.

  • Temporal operators:

    • anyinteracts

An encoding of CQL may be used as the value of the filter parameters defined in the Filter conformance class.

The Enhanced Spatial Operators conformance class specifies requirements for servers that support spatial operators in addition to the intersects operator that is defined in the Simple CQL conformance class. The list of additional spatial operators that must be supported is:

  • equals

  • disjoint

  • touches

  • within

  • overlaps

  • crosses

  • contains

Note
Do we need to add DWITHIN and BEYOND? I think no.

The Enhanced Temporal Operators conformance class specifies requirements for servers that support temporal operators in addition to the anyinteracts operator defined in the Simple CQL conformance class. The list of additional temporal operators that must be supported is:

  • after

  • before

  • begins

  • begunby

  • tcontains

  • during

  • endedby

  • ends

  • tequals

  • meets

  • metby

  • toverlaps

  • overlappedby

  • intersects

The Functions conformance class specifies requirements for supporting function calls (e.g. min, max, etc.) in a CQL expression. Function calls are the primary means of extending the language. This conformance class also defined a resource /functions that may be used to discover the list of available functions.

The Arithmetic operators conformance class specifies requirements for supporting the standard set of arithmetic operators, \(+, -, *, /\) in a CQL expression.

The CQL Text encoding conformance class defines a text encoding for CQL. Such an encoding is suitable for use with HTTP query parameters such as the filter parameter defined by the Filter conformance class.

The CQL JSON encoding conformance class defines a JSON encoding for CQL. Such as encoding is suitable for use with as the body of an HTTP POST request.

Conformance with this standard shall be checked using all the relevant tests specified in Annex A of this document. The framework, concepts, and methodology for testing, and the criteria to be achieved to claim conformance are specified in the OGC Compliance Testing Policies and Procedures and the OGC Compliance Testing web site.

3. Roadmap

The content of the clause is informative.

Because CQL is not exclusively useful for features, it is anticipated that the following conformance classes:

will eventually become parts of the OGC API - Common suite for standards thus leaving the Features Filter conformance class as part 3 of the OGC API - Features specifications.

4. References

The following normative documents contain provisions that, through reference in this text, constitute provisions of this document. For dated references, subsequent amendments to, or revisions of, any of these publications do not apply. For undated references, the latest edition of the normative document referred to applies.

  • Portele, C., Vretanos, P.: OGC 17-069r2, OGC API - Features - Part 1: Core, http://example.com/fixme

  • ISO 19108:2002, Geographic information — Temporal schema

  • Crocker, D.: RFC 5238, Augmented BNF for Syntax Specifications: ABNF

  • Wright A., Andrews H., Hutton B., Dennis G.: draft-handrews-json-schema-02, JSON Schema: A Media Type for Describing JSON Documents

  • Egenhofer, M.J., Herring, J.R., A Mathematical Framework for the Definition of Topological Relationships

5. Terms and Definitions

This document uses the terms defined in Sub-clause 5.3 of [OGC 06-121r9], which is based on the ISO/IEC Directives, Part 2, Rules for the structure and drafting of International Standards. In particular, the word “shall” (not “must”) is the verb form used to indicate a requirement to be strictly followed to conform to this standard.

For the purposes of this document, the following additional terms and definitions apply in addition to the terms defined in OGC API - Features - Part 1: Core.

5.1. term 1

definition [source]

5.2. term 2

definition [source]

6. Conventions and background

See OGC API - Features - Part 1: Core, Clauses 5 and 6.

7. Requirements Class "Filter"

7.1. Overview

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/filter

Target type

Web API

Dependency

The OGC API - Common standard defines two filtering operators at the /items endpoint: bbox and datetime. OGC API - Features - Part 1: Core also adds support, beyond OGC API - Common for simple equality predicates logically joined using the AND operator. This capabilities offer simple resource filtering for HTTP requests.

This conformance class defines additional query parameters that allow more complex filtering expressions to be specified when querying server resources.

Specifically, this clause defines the parameters, filter, filter-lang and filter-crs.

This conformance class also defines resources for discovering the list of resource properties (and their types) that may be used to construct filter expressions.

7.2. Queryables

This extension does not assume that the schema (internal or external) of a resource being queried is available for inspection and thus a means needs to exist to interrogate an endpoint to determine the names and types of the properties or keys that may be used to construct a filter expression.

Requirement 1

/req/filter/get-queryables-op-global

A

A server that implements this conformance class shall support the HTTP GET operation at the '/queryables' path.

B

The queryables accessed at this path shall be valid for all collections identified in the collections response (path /collections).

Requirement 2

/req/filter/get-queryables-op-local

A

For every collection identified in the collections response (path /collections), the server SHALL support the HTTP GET operation at the path /collections/{collectionId}/queryables.

B

The parameter collectionId is each id property in the collections response (JSONPath: $.collections[*].id).

Requirement 3

/req/filter/get-queryables-response

A

A successful execution of the operation SHALL be reported as a response wit h a HTTP status code 200.

B

The content of the response shall have the following characteristics (using an OpenAPI Specification 3.0 fragment):

type: object
required:
  - queryables
properties:
  queryables:
    type: array
    items:
      type: object
      required:
      - queryable
      - type
      properties:
         queryable:
            description: the token that may be used in a CQL predicate
            type: string
         title:
            description: a human readble title for the queryable
            type: string
         description:
         description: a human-readable narrative describing the queryable
            type: string
         language:
            description: the language used for the title and description
            type: string
            default:
               - en
         type:
            description: the data type of the queryable
            type: string
         type-ref:
            description: a reference to the formal definition of the type
            type: string
            format: url
Example 1. Queryables example
{
   "queryables": [
      {
         "queryable": "elevation",
         "title": "Elevation",
         "description": "The average distance of the road segment above sea level.",
         "type": "double"
      },
      {
         "queryable": "nlanes",
         "title": "Temperature",
         "description": "The total number of lanes in all directions.",
         "type": "integer"
      },
      {
         "queryable": "geom",
         "title": "Segment Geometry",
         "description": "The geometry of the road segment",
         "type": "linestring"
      },
      {
         "queryable": "name",
         "title": "Segment Name",
         "description": "The common name of the road segment.",
         "type": "string"
      }
   ]
}

7.3. Parameter filter

This extensions defines a general parameter, filter, whose value is a filter expression to be applied when retrieving resources in order to determine which resources should be included in a result set.

Requirement 4

/req/filter/filter-param

A

The HTTP GET operation on the path that fetches resource instances (e.g. /collections/{collectionId}/items) shall support a parameter filter with the following characteristics (using an OpenAPI Specification 3.0 fragment):

name: filter
in: query
required: false
schema:
  type: string
style: form
explode: false

7.4. Cross-collection queries

The only query path defined in OGC API - Features - Part 1: Core is the /items endpoint which operates on a single collection. However other, higher level, endpoints are also being defined (e.g. /search or /tiles) that potentially operate on multiple collections. The simplest approach for handling such cross-collection queries is one that is consistent with one-collection queries. Specifically, any specified filter parameter should apply to all referenced collections. This, of course, implies that all properties referenced in the filter expression are valid for all referenced collections and should be taken from the global queryables list.

Requirement 5

/req/filter/filter-param-multiple-collections

A

A server that implements this extension and also supports higher-level query endpoints that support queries across multiple collections (e.g. /tiles) shall only allow properties from the global list of queryables to be referenced in a filter expression.

B

If a cross-collection filter expression references properties that are not listed in the global list of queryables, then the server shall respond with an HTTP status code of 400.

The following example illustrates a notional query on a /tiles endpoint that uses a CQL filter and references multiple collections:

Note
Arrays of filter expressions that operate on each collection specified in a query (or subsets thereof) are out of scope for this extension and would be the subject of a different part of the OGC API - Features suite of specifications.

7.5. Parameter filter-lang

Any predicate language that can be suitably expressed as the value of an HTTP query parameter may be specified as the value of the filter parameter. In order to specify that specific language that is being used, this clause defines the filter-lang parameter.

Requirement 6

/req/filter/filter-lang-param

A

The HTTP GET operation on the path that fetches resource instances (e.g. /collections/{collectionId}/items) shall support a parameter filter-lang with the following characteristics (using an OpenAPI Specification 3.0 fragment):

name: filter-lang
in: query
required: false
schema:
  type: string
  enum:
     - 'cql-text'
     - 'cql-json'
  default: "cql-text"
style: form

The enumerated value cql-text is used to indicate that the value of the filter parameter is the text encoding of CQL.

The enumerated value cql-json is used to indicate that the value of the filter parameter is the JSON encoding of CQL.

Servers that support other filtering languages can extend this list of values as necessary although the meaning of any additional values are not described in this standard.

7.6. Parameter filter-crs

Requirement 7

/req/filter/filter-crs-wgs84

A

If a server does not implement the Coords Reference Systems by Reference extension, then all geometry values in a filter expression specified as the value of the filter parameter shall be expressed using CRS84 as per OGC API - Features - Part 1: Core.

Requirement 8

/req/filter/filter-crs-param

A

If the server implementing this extension also supports the Coords Reference Systems by Reference extension, then the HTTP GET operation on the path that fetches resource instances (e.g. /collections/{collectionId}/items') shall support a parameter `filter-crs that asserts the crs being used to encode geomerty value in a filter expression specified as the value of the filter parameter.

B

The following YAML fragment defines the filter-crs parameter:

name: filter-crs
in: query
required: false
schema:
  type: string
  format: uri
style: form
explode: false

7.7. Interaction with existing predicates

Requirement 9

/req/filter/mixing-expression

A

Existing query predicates (e.g. bbox, datetime, etc.) shall be logically connected with the AND operator when mixed in a request with the filter parameter.

7.8. Filter expression language

This extension does not mandate that a specific filter expression language be used as the value of the filter parameter. However, this extension defines a filter expression language called the Common Query Language (CQL). A simple CQL core is defined along with a number of enhancements that add additional, more advanced capabilities to the language. Two encodings, a text encoding and a JSON encoding are also defined and recommended if they are suitable for their intended use.

7.9. Response

Requirement 10

/req/filter/response

A

A CQL filter expression shall be evaluated for each item of a collection.

B

If the CQL filter experssion evalutes to TRUE then the item shall be included in the result set.

C

If the CQL filter expression evaluates to FALSE then the item shall be excluded from the result set.

8. Requirements Class "Features Filter"

8.1. Overview

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/features-fitler

Target type

Web API

Dependency

This clause defines the binding between the OGC API - Features - Part 1: Core standard and the filtering parameters defined in this standard.

8.2. Features

8.2.1. Operation

As per the OGC API - Features - Part 1: Core standard, features are accessed using the HTTP GET method via the /collections/{collectionId}/items path (see Features). The following additional requirements bind the parameters filter, filter-lang and filter-crs to the GET operation on this path.

Requirement 11

/req/features-filter/filter-param

A

The HTTP GET operation on the /collections/{collectionId}/items path shall support the filter parameter as defined in the Parameter filter clause.

Requirement 12

/req/features-filter/filter-lang-param

A

The HTTP GET operation on the /collections/{collectionId}/items path shall support the filter-lang parameter as defined in the Parameter filter-lang clause.

Recommendation 1

/rec/features-filter/text-encoding

A

If a filter expression can be represented for its intended use as text, implemenetations should consider using the CQL text encoding.

Requirement 13

/req/features-filter/cql-text

A

If a filter expression is encoded as text, this shall be indicated using the value cql-text as the value of the filter-lang parameter.

Recommendation 2

/rec/features-filter/JSON-encoding

A

If a filter expression can be represented for its intended use as JSON, implemenetations should consider using the CQL JSON encoding.

Requirement 14

/req/features-filter/cql-json

A

If a filter expression is encoded as JSON, this shall be indicated using the value cql-json as the value of the filter-lang parameter.

Requirement 15

/req/features-filter/filter-crs-param

A

If the server implementing this extension also supports the OGC API - Features - Part 2: Coordinate Reference Systems by Reference extension, then the HTTP GET operation on the /collections/{collectionId}/items path shall support the filter-crs parameter as defined in the Parameter filter-crs clause.

8.2.2. Response

Requirement 16

/req/features-filter/response

A

A CQL filter expression shall be evaluated for each feature of a collection.

B

All other filtering parameters specified (i.e. zero or more of bbox, datetime and property filters) shall be evaluated for each feature of a collection.

C

If the CQL filter expression AND all other specified filtering parameters (i.e. zero or more of bbox, datetime and property filters) evaluates to TRUE then the feature shall be included in the result set.

D

If the CQL filter expression OR any other specified filtering parameter (i.e. zero or more of bbox, datetime and property filters) evaluates to FALSE then the feature shall be excluded from the result set.

9. Requirements Class "Simple CQL"

9.1. Overview

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/simple-cql

Target type

Web API

Dependency

This clause defines the core of a query language called Common Query Language (CQL) that may be used to construct filter expressions. Subsequent clauses define several optional encodings of CQL as well additional filtering capabilities.

9.2. CQL filter expression

A CQL filter expression is an expression that defines a logically connected set of predicates that are evaluated for each item of a collection. A CQL filter expression produces a Boolean value of TRUE is the collection item satisfies all the requirements of the expression; otherwise the CQL filter expression evaluates to `FALSE'.

A CQL filter expression can be constructed by logically connecting zero or more of the following classes of predicates:

  • comparison predicates

  • spatial predicates

  • temporal predicates

  • list predicates

Requirement 17

/req/simple-cql/filter-expression

A

A server that implements this conformance class shall support a CQL filter expression composed of a logically connected series of one or more predicates as described by the following BNF fragment:

cqlFilter = booleanValueExpression;

booleanValueExpression = booleanTerm | booleanValueExpression "OR" booleanTerm;

booleanTerm = booleanFactor | booleanTerm "AND" booleanFactor;

booleanFactor = ["NOT"] booleanPrimary;

booleanPrimary = predicate
               | leftParen cqlFilter rightParen;

predicate = comparisonPredicate
         | spatialPredicate
         | temporalPredicate
         | inPredicate;

9.3. Scalar expressions

A scalar expression is one of a property name, a character literal or a numeric literal.

Requirement 18

/req/simple-cql/scalar-expressions

A

A server that implements this conformance class shall support scalar expressions as defined by the following BNF fragment:

scalarExpression = propertyName
                 | characterLiteral
                 | numericLiteral;

propertyName = identifier;
identifier = identifierStart [ {identifierPart} ];

identifierStart = alpha [{octothorp|dollar|underscore|alpha|digit}];

identifierPart = alpha | digit;

characterLiteral = characterStringLiteral
                 | bitStringLiteral
                 | hexStringLiteral;

characterStringLiteral = quote [ {character} ] quote;

character = alpha | digit | specialCharacter | quoteQuote;

quoteQuote = quote quote;

bitStringLiteral = "B" quote [ {bit} ] quote;

hexStringLiteral = "X" quote [ {hexit} ] quote;

numericLiteral = unsignedNumericLiteral | signedNumericLiteral;

unsignedNumericLiteral = exactNumericLiteral | approximateNumericLiteral;

signedNumericLiteral = [sign] exactNumericLiteral | approximateNumericLiteral;

exactNumericLiteral = unsignedInteger [ period [ unsignedInteger ] ]
                      | period unsignedInteger;

approximateNumericLiteral = mantissa "E" exponent;

mantissa = exactNumericLiteral;

exponent = signedInteger;

signedInteger = [ sign ] unsignedInteger;

unsignedInteger = {digit};

sign = plusSign | minusSign;

alpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
        "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
        "U" | "V" | "W" | "X" | "Y" | "Z" |
        "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
        "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
        "u" | "v" | "w" | "x" | "y" | "z";

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";

hexit = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" |
                 "c" | "d" | "e" | "f";

specialCharacter = percent | ampersand | leftParen | rightParen | asterisk
                 | plusSign | comma | minusSign | period | solidus | colon
                 | semicolon | lt | gt | eq | questionMark | underscore
                 | verticalBar | doubleQuote ;

octothorp = "#";

dollar = "$";

underscore = "_";

quote = "'";

plusSign = "+";

minusSign = "-";

period = ".";

doubleQuote = "\"";

percent = "%";

ampersand = "&";

leftParen = "(";

rightParen = ")";

asterisk = "*";

comma = ",";

solidus = "/";

colon = ":";

semicolon = ";";

lt = "<";

eq = "=";

gt = ">";

questionMark = "?";

verticalBar = "|

bit = "0" | "1";
Note
The alpha production is just an examples that allows the BNF validators that I used to work. In reality this should really be the list of valid UTF-8 characters.

9.4. Comparison predicates

A comparison predicate evaluates two scalar expressions to determine if the expressions satisfy the specified comparison operator. If the requirements of the operator are satisfied, then the prediate evaluates to the Boolean value TRUE; otherwise the predicate evaluates to the Boolean value FALSE;

Requirement 19

/req/simple-cql/comparison-predicates

A

A server that implements this conformance class shall support the comparison operators defined by the following BNF fragment:

comparisonPredicate = binaryComparisonPredicate
                    | propertyIsLikePredicate
                    | propertyIsBetweenPredicate
                    | propertyIsNullPredicate;

binaryComparisonPredicate = scalarExpression comparisonOperator scalarExpression;

propertyIsLikePredicate =  scalarExpression "LIKE" regularExpression;

propertyIsBetweenPredicate = scalarExpression "BETWEEN"
                             scalarExpression "AND" scalarExpression;

propertyIsNullPredicate = scalarExpression "IS" ["NOT"] "NULL";

regularExpression = characterLiteral;

comparisonOperator = eq | neq | lt | gt | lteq | gteq;

neq = lt gt;

gteq = gt eq;

lteq = lt eq;

9.5. Spatial predicates

A spatial predicate evaluates two geometry-valued expressions to determine if the expressions satsify the requirements of the specified spatial operator. If the requirements of the operator are satisfied, then the predicate evaluates to the Boolean value TRUE; otherwise the predicate evaluates to the Boolean value FALSE.

Requirement 20

/req/simple-cql/spatial-predicates

A

A server that implements this conformance class shall support the spatial operators defined by the following BNF fragment:

spatialPredicate = spatialOperator leftParen geomExpression comma geomExpression rightParen;

spatialOperator = "INTERSECTS";

geomExpression = propertyName
               | geomLiteral;

geomLiteral = pointTaggedText
            | linestringTaggedText
            | polygonTaggedText
            | multipointTaggedText
            | multilinestringTaggedText
            | multipolygonTaggedText
            | geometryCollectionTaggedText
            | envelopeTaggedText;

pointTaggedText = "POINT" pointText;

linestringTaggedText = "LINESTRING" lineStringText;

polygonTaggedText = "POLYGON" polygonText;

multipointTaggedText = "MULTIPOINT" multiPointText;

multilinestringTaggedText = "MULTILINESTRING" multiLineStringText;

multipolygonTaggedText = "MULTIPOLYGON" multiPolygonText;

geometryCollectionTaggedText = "GEOMETRYCOLLECTION" geometryCollectionText;

pointText = leftParen point rightParen;

point = xCoord yCoord [zCoord];

xCoord = signedNumericLiteral;

yCoord = signedNumericLiteral;

zCoord = signedNumericLiteral;

lineStringText = leftParen point {comma point} rightParen;

polygonText =  leftParen lineStringText {comma lineStringText} rightParen;

multiPointText = leftParen pointText {comma pointText} rightParen;

multiLineStringText = leftParen lineStringText {comma lineStringText} rightParen;

multiPolygonText = leftParen polygonText {comma polygonText} rightParen;

geometryCollectionText = leftParen geomLiteral {comma geomLiteral} rightParen;

envelopeTaggedText = "ENVELOPE" envelopeText;

envelopeText = leftParen westBoundLon comma eastBoundLon comma northBoundLat comma southBoundLat [comma minElev comma maxElev] rightParen;

westBoundLon = signedNumericLiteral;

eastBoundLon = signedNumericLiteral;

northBoundLat = signedNumericLiteral;

southBoundLat = signedNumericLiteral;

minElev = signedNumericLiteral;

maxElev = signedNumericLiteral;

9.6. CRS considerations

Requirement 21

/req/simple-cql/crs/crs84

A

If a server implementing this conformance class does not support the Coordinate Reference Systems by Reference extension, then all geometry coordinate values shall be expressed using CRS84 as per OGC API - Features - Part 1: Core.

Requirement 22

/req/simple-cql/crs/storage-other

A

If a server implementing this conformance class also supports the Coordinate Reference Systems by Reference extension, then all geometry coordinate values encoded in a CQL expression shall be expressed using the crs specified by the filter-crs parameter as specified in Parameter filter-crs.

9.7. Temporal predicates

A temporal predicate evaluates two time-valued expressions to determine if the expressions satsify the requirements of the specified temporal operator. If the requirements of the operator are satisfied, then the predicate evaluates to the Boolean value TRUE; otherwise the predicate evaluates to the Boolean value FALSE;

Requirement 23

/req/simple-cql/temporal-predicates

A

A server that implements this conformance class shall support the temporal operators defined by the following BNF fragment:

temporalPredicate = temporalExpression temporalOperator temporalExpression;

temporalExpression = propertyName
                   | temporalLiteral;

temporalOperator =  "ANYINTERACTS";

temporalLiteral = instant | interval;

instant = fullDate | fullDate "T" utcTime;

interval = instantInInterval solidus instantInInterval;

instantInInterval = period period | "" | instant;

fullDate   = dateYear minusSign dateMonth minusSign dateDay;

dateYear   = digit digit digit digit;

dateMonth  = digit digit;

dateDay    = digit digit;

utcTime  = timeHour colon timeMinute colon timeSecond [timeZoneOffset];

timeZoneOffset = "Z" | sign timeHour;

timeHour   = digit digit;

timeMinute = digit digit;

timeSecond = digit digit [period digit {digit}];

9.8. List predicate

A list predicate tests, for equality, the value of a scalar expression against a list of literal values of the same type. If the value of the named property is equal to one or more of the values in the list of literals, the list predicate evaluates to the Boolean value TRUE; otherwise the list predicate evaluates to the Boolean value FALSE.

Requirement 24

/req/simple-cql/in-predicate

A

A server that implements this conformance class shall support an in-list predicate as defined by the following BNF fragment:

inPredicate = propertyName "IN" leftParen inList rightParen;

inList = listItem [ {comma listItem} ];

listItem = characterLiteral

numericLiteral

geomLiteral

temporalLiteral

function;

Requirement 25

/req/simple-cql/in-predicate-function

A

The items in the list of an in-list predicate (i.e. the items on the right hand side of the expression) shall be of the same type as the property being tested by the expression.

B

If an item in the list is a function, then that function shall return a literal values of the same type as the property being tested by the expression.

9.9. Simple CQL Encodings

This standard defines a text encoding and a JSON encoding of CQL and makes the following recommendations:

Recommendation 3

/rec/simple-cql/simple-cql-text

A

If a filter expression can be represented for the intended use as a text string, implementations should consider supporting the text encoding of CQL for the expression.

Recommendation 4

/rec/simple-cql/simple-cql-json

A

If a filter expression can be represented for the intended use as JSON, implementations should consider supporting the JSON encoding of CQL for the expression.

10. Common Query Language enhancements

10.1. Overview

This clause specifies requirements for enhancements to Simple CQL. Specifically, this clause defined requirements for:

  • additional spatial operators

  • additional temporal operators

  • support for functions in CQL

  • support for arithmetic expression in CQL

In each case, the clause also ammends and extends CQL’s BNF and the text and JSON encodings of CQL to introduce the enhanced capabilities.

10.2. Requirements Class "Enhanced Spatial Operators"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/enhanced-spatial-operators

Target type

Web API

Dependency

The Simple CQL clause specifies the use of the INTERSECTS spatial operator. This requirement adds the remaining Eignehoffer operators to the list of spatial operators that an implementation of this extension might offer.

Requirement 26

/req/enhanced/spatial-operators

A

A server that implements this requirements class shall, in addition to INTERSECTS, support the additional spatial operators defined by the following BNF fragment which extends the list of spatial operators specified for the Simple CQL Spatial Predicates requirements class:

   spatialOperator = "EQUALS" | "DISJOINT" | "TOUCHES" | "WITHIN"
                  | "OVERLAPS" | "CROSSES" | "INTERSECTS" | "CONTAINS";

10.3. Requirements Class "Enhanced Temporal Operators"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/enhanced-temporal-operators

Target type

Web API

Dependency

The Simple CQL clause specifies the use of the ANYINTERACTS temporal operator. This requirements class adds the remaining ISO temporal operators to the list of temporal operators that an implementations of this extension might offer.

Requirement 27

/req/enhanced-temporal-operators

A

A server that implements this requirements class shall, in addition to ANYINTERACTS, support the additional temporal operators defined by the following BNF fragment which extends the list of temporal operators specified for the Simple CQL Temporal Predicates requirements class:

   temporalOperator = "AFTER" | "BEFORE" | "BEGINS" | "BEGUNBY"
                   | "TCONTAINS" | "DURING" | "ENDEDBY" | "ENDS"
                   | "TEQUALS" | "MEETS" | "METBY" | "TOVERLAPS"
                   | "OVERLAPPEDBY" | "ANYINTERACTS" | "INTERSECTS";

10.4. Requirements Class "Functions"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/functions

Target type

Web API

Dependency

This clause specifies requirements for supporting functions in CQL. Functions allow implementations to extend the language.

A resource, /functions is also defined that allows clients to discover the list of function that an implementation offers.

Requirement 28

/req/functions/functions

A

A server that implements this requirement shall support functions as defined by the following BNF fragment which extends and ammends the Simple CQL requirements class BNF:

   function = identifier {argumentList};

   argumentList = leftParen [positionalArgument]  rightParen;

   positionalArgument = argument [ { comma argument } ];

   argument = characterLiteral
           | numericLiteral
           | geomLiteral
           | propertyName

   scalarExpression = propertyName
                    | characterLiteral
                    | numericLiteral
                    | function

   geomExpression = propertyName
                  | geomLiteral
                  | function;

   temporalExpression = propertyName
                      | temporalLiteral
                      | function;

   inPredicate = propertyName "IN" leftParen { characterLiteral |
                                               numericLiteral |
                                               geomLiteral |
                                               temporalLiteral |
                                               function } rightParen;

B

The list of valid function names can be discovered via the functions resource (i.e. path /functions).

Requirement 29

/req/functions/get-functions-operation

A

A server shall support the HTTP GET operation at the '/functions' path.

Requirement 30

/req/functions/get-functions-response-json

A

A successful execution of the operation SHALL be reported as a response wit h a HTTP status code 200.

B

The JSON content of the response shall validate against the following JSON schema:

   {
     "$id": "https://example.com/person.schema.json",
     "$schema": "http://json-schema.org/draft-07/schema#",
     "type": "object",
     "required": [
       "functions"
     ],
     "properties": {
       "functions": {
         "type": "array",
         "items": {
           "type": "object",
           "required": [
             "name",
             "returns"
           ],
           "properties": {
             "name": {
               "type": "string"
             },
             "description": {
               "type": "string"
             },
             "metadataURL": {
               "type": "string",
               "format": "url"
             },
             "arguments": {
               "type": "array",
               "items": {
                 "type": "object",
                 "required": [
                   "type"
                 ],
                 "properties": {
                   "title": {
                      "type": "string"
                   },
                   "description": {
                     "type": "string"
                   },
                   "type": {
                     "type": "array",
                     "items": {
                       "type": "string",
                       "enum": [
                         "string",
                         "number",
                         "datetime",
                         "geometry",
                         "boolean"
                       ]
                     }
                   }
                 }
               }
             },
             "returns": {
               "type": "array",
               "items": {
                 "type": "string",
                 "enum": [
                   "string",
                   "number",
                   "datetime",
                   "geomtry",
                   "boolean"
                 ]
               }
             }
           }
         }
       }
     }
   }

Requirement 31

/req/functions/get-functions-response-xml

A

A successful execution of the operation SHALL be reported as a response wit h a HTTP status code 200.

B

The XML content of the response shall validate against the following XML schema:

Example 3. Get functions JSON response example
   {
      "functions": [
         {
            "name": "min",
            "arguments": [
               {
                  "type": ["string","number","datetime"]
               },
               {
                  "type": ["string","number","datetime"]
               },
            ],
            "retuns": ["string","number","datetime"]
         },
         {
            "name": "max",
            "arguments": [
               {
                  "type": ["string","number","datetime"]
               },
               {
                  "type": ["string","number","datetime"]
               },
            ],
            "retuns": ["string","number","datetime"]
         },
         {
            "name": "geometryType",
            "arguments": [
               {
                  "type": ["geometry"]
               }
            ],
            "returns": ["string"]
         }
      ]
   }
Example 4. Get functions XML response example

10.5. Requirements Class "Arithmetic Expressions"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/arithmetic

Target type

Web API

Dependency

This clause specifies requirements for supporting arithmetic expressions in CQL. An arithemtic expression is an expression composed of an arithmetic operand (a property name, a number or a function that returns a number), an arithmetic operator (i.e. one of +,-,*,/) and another arithmetic operand.

Requirement 32

/req/arithmetic/arithmetic

A

A server that implements this requirement shall support arithmetic expressions as defined by the following BNF fragment which extends and ammends the Simple CQL requirements class BNF:

   arithmeticExpression = arithmeticOperand
                          arithmeticOperator
                          arithmeticOperand;

   arithmeticOperator = plusSign | minusSign | asterisk | solidus;

   arithmeticOperand = propertyName
                    | numericLiteral
                    | function;

   argument = characterLiteral
            | numericLiteral
            | geomLiteral
            | propertyName
            | arithmeticExpression;

   scalarExpression = propertyName
                    | characterLiteral
                    | numericLiteral
                    | function
                    | arithmeticExpression;
Example 5. Arithmetic expression example in JSON

11. Requirements classes for encodings

11.1. Overview

This clause specifies requirements for a text encoding and a JSON encoding of Simple CQL.

11.2. Requirements Class "CQL Text"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/cql-text

Target type

Web API

Dependency

This requirements class defines a well know text encoding of CQL. Such an encoding would be suitable for use with the a GET query parameter such as filter parameter.

Requirement 33

/req/cql-text/simple-cql

A

A server that implements the Simple CQL requirements class and also implements this requirement shall be able to parse a filter expression encoded as a text string that validates against the BNF productions found in the Simple CQL requirements class.

Requirement 34

/req/cql-text/enhanced_spatial-operators

A

A server that implements the Enhanced Spatial Operators requirement class and also implements this requirement shall be able to parse a spatial operator encoded as a text string that validates against the BNF production fragment in the Enhanced Spatial Operators requirement.

A

A server that implements the Enhanced Temporal Operators requirement class and also implements this requirement shall be able to parse a temporal operator encoded as a text string that validates against the BNF production fragment in the Enhanced Temporal Operators requirement.

Requirement 35

/req/cql-text/functions

A

A server that implements the Functions requirement class and also implements this requirement shall be able to parse a function call expression encoded as a text string that validates against the BNF production fragment in the Functions requirement.

Requirement 36

/req/cql-text/arithmetic

A

A server that implements the Arithmetic Expressions requirements class and also implements this requirement shall be able to parse an arithmetic expression encoded as a text string that validates against the BNF production fragment in the Arithmetic Expressions requirement.

11.3. Requirements Class "CQL JSON"

Requirements Class

http://www.opengis.net/spec/ogcapi-features-3/1.0/req/cql-json

Target type

Web API

Dependency

This requirements class defines a JSON encoding of Simple CQL. Such an encoding would be suitable as the body of an HTTP POST request.

Requirement 37

/req/cql-json/simple-cql

A

A server that implements the Simple CQL requirements class and also implements this requirement shall be able to parse a filter expression encoded as JSON that validates against the following JSON Schema fragment:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$ref": "#/definitions/predicates",

    "definitions": {

      "predicates": {
        "type": "object",
        "allOf": [
            { "$ref": "#/definitions/logicalExpression" },
            { "$ref": "#/definitions/comparisonExpressions" },
            { "$ref": "#/definitions/spatialExpressions" },
            { "$ref": "#/definitions/temporalExpressions" }
        ],
        "minProperties": 1,
        "maxProperties": 1
      },

      "logicalExpression" : {
        "type": "object",
        "properties": {
            "and": {"$ref": "#/definitions/and" },
            "or": {"$ref": "#/definitions/or" },
            "not": {"$ref": "#/definitions/not" }
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "comparisonExpressions" : {
        "type": "object",
        "properties": {
            "eq": {"$ref": "#/definitions/eq"},
            "lt": {"$ref": "#/definitions/lt"},
            "gt": {"$ref": "#/definitions/gt"},
            "lte": {"$ref": "#/definitions/lte"},
            "gte": {"$ref": "#/definitions/gte"},

            "between": {"$ref": "#/definitions/between"},

            "like": { "$ref": "#/definitions/like" },
            "in": { "$ref": "#/definitions/in" }
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "spatialExpressions" : {
        "type": "object",
        "properties": {
            "intersects": {"$ref": "#/definitions/intersects"}
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "temporalExpressions" : {
        "type": "object",
        "properties": {
            "anyinteracts": {"$ref": "#/definitions/anyinteracts"}
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "and": { "$ref": "#/definitions/booleanOperands" },
      "or":  { "$ref": "#/definitions/booleanOperands" },
      "not": { "$ref": "#/definitions/predicates" },

      "eq":  { "$ref": "#/definitions/scalarOperands" },
      "lt":  { "$ref": "#/definitions/scalarOperands" },
      "gt":  { "$ref": "#/definitions/scalarOperands" },
      "lte": { "$ref": "#/definitions/scalarOperands" },
      "gte": { "$ref": "#/definitions/scalarOperands" },

      "between": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "lower": { "$ref": "#/definitions/scalarLiteral" },
            "upper": { "$ref": "#/definitions/scalarLiteral" }
         },
         "required" : [ "property", "lower", "upper" ]
      },

      "like": {
         "type": "object",
         "properties": {
            "wildcard": { "type": "string", "default": "%" },
            "singleChar": { "type": "string", "default": "_" },
            "escape": { "type": "string", "default": "\\" },
            "nocase": { "type": "boolean", "default": true },
            "property": { "type": "string" },
            "value": { "$ref": "#/definitions/scalarLiteral" }
         }
      },

      "in": {
         "type": "object",
         "properties": {
            "nocase": { "type": "boolean", "default": true },
            "property": { "type": "string" },
            "values": {
               "type": "array",
               "items": { "$ref": "#/definitions/scalarLiteral" }
            }
         }
      },

      "intersects": { "$ref": "#/definitions/spatialOperands" },
      "anyinteracts": { "$ref": "#/definitions/temporalOperands" },

      "booleanOperands": {
         "type": "array",
         "items": {
             "$ref": "#/definitions/predicates",
             "minItems": 2
         }
      },

      "scalarOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "value": { "$ref": "#/definitions/scalarLiteral" }
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "spatialOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "value": {  "$ref": "#/definitions/geometryLiteral" }
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "temporalOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "value": { "$ref": "#/definitions/temporalLiteral" }
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "scalarLiteral": {
         "oneOf": [
            { "type": "string" },
            { "type": "number" },
            { "type": "boolean"}
         ]
      },

      "geometryLiteral": {
         "type": "object"
      },

      "bbox": {
        "type": "array",
        "items": {
            "type": "number",
            "oneOf": [
              { "minItems": 4, "maxItems": 4},
              { "minItems": 6, "maxItems": 6}
            ]
        }
      },

      "envelopeLiteral": {
         "type": "object",
         "properties": {
            "bbox": { "$ref": "#/definitions/bbox" }
         }
      },

      "temporalLiteral": {
         "oneOf": [
            { "$ref": "#/definitions/timeLiteral" },
            { "$ref": "#/definitions/periodLiteral" }
         ]
      },

      "timeLiteral": {
         "type": "string",
         "pattern": "[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-9][0-9](T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](.[0-9]*)?)?"
      },

      "periodLiteral": {
         "type": "array",
         "items": {
            "$ref": "#/definitions/timeLiteral",
            "minItems": 2,
            "maxItems": 2
        }
     }
   }
}
Note
Attention is drawn to the fact that there exists an alternative JSON encoding for CQL based on the use of arrays that can be found here: https://github.com/tschaub/ogcapi-features/tree/json-array-expression/extensions/cql/jfe. The SWG will need to review both encodings and decide which one to adopt.

Requirement 38

/req/cql-json/enhanced_spatial-operators

A

A server that implements the Enhanced Spatial Operators requirement class and also implements this requirement shall be able to parse a spatial operator encoded as JSON that validates against the following JSON Schema fragment:

   "spatialExpressions" : {
     "type": "object",
     "properties": {
         "equals": {"$ref": "#/definitions/equals"},
         "disjoint": {"$ref": "#/definitions/disjoint"},
         "touches": {"$ref": "#/definitions/touches"},
         "within": {"$ref": "#/definitions/within"},
         "overlaps": {"$ref": "#/definitions/overlaps"},
         "crosses": {"$ref": "#/definitions/crosses"},
         "intersects": {"$ref": "#/definitions/intersects"},
         "contains": {"$ref": "#/definitions/contains"}
     },
     "minProperties": 1,
     "maxProperties": 1
   },

   "equals":     { "$ref": "#/definitions/spatialOperands" },
   "disjoint":   { "$ref": "#/definitions/spatialOperands" },
   "touches":    { "$ref": "#/definitions/spatialOperands" },
   "within":     { "$ref": "#/definitions/spatialOperands" },
   "overlaps":   { "$ref": "#/definitions/spatialOperands" },
   "crosses":    { "$ref": "#/definitions/spatialOperands" },
   "intersects": { "$ref": "#/definitions/spatialOperands" },
   "contains":   { "$ref": "#/definitions/spatialOperands" },

Requirement 39

/req/cql-json/enhanced-temporal-operators

A

A server that implements the Enhanced Temporal Operators requirement class and also implements this requirement shall be able to parse a temporal operator encoded as JSON that validates against the following JSON Schema fragment:

   "temporalExpressions" : {
     "type": "object",
     "properties": {
         "after": {"$ref": "#/definitions/after"},
         "before": {"$ref": "#/definitions/before"},
         "begins": {"$ref": "#/definitions/begins"},
         "begunby": {"$ref": "#/definitions/begunby"},
         "tcontains": {"$ref": "#/definitions/tcontains"},
         "during": {"$ref": "#/definitions/during"},
         "endedby": {"$ref": "#/definitions/endedby"},
         "ends": {"$ref": "#/definitions/ends"},
         "tequals": {"$ref": "#/definitions/tequals"},
         "meets": {"$ref": "#/definitions/meets"},
         "metby": {"$ref": "#/definitions/metby"},
         "toverlaps": {"$ref": "#/definitions/toverlaps"},
         "overlappedby": {"$ref": "#/definitions/overlappedby"}
     },
     "minProperties": 1,
     "maxProperties": 1
   },

   "after":        { "$ref": "#/definitions/temporalOperands" },
   "before":       { "$ref": "#/definitions/temporalOperands" },
   "begins":       { "$ref": "#/definitions/temporalOperands" },
   "begunby":      { "$ref": "#/definitions/temporalOperands" },
   "tcontains":    { "$ref": "#/definitions/temporalOperands" },
   "during":       { "$ref": "#/definitions/temporalOperands" },
   "endedby":      { "$ref": "#/definitions/temporalOperands" },
   "ends":         { "$ref": "#/definitions/temporalOperands" },
   "tequals":      { "$ref": "#/definitions/temporalOperands" },
   "meets":        { "$ref": "#/definitions/temporalOperands" },
   "metby":        { "$ref": "#/definitions/temporalOperands" },
   "toverlaps":    { "$ref": "#/definitions/temporalOperands" },
   "overlappedby": { "$ref": "#/definitions/temporalOperands" },
   "anyinteracts": { "$ref": "#/definitions/temporalOperands" },
   "tintersects":  { "$ref": "#/definitions/temporalOperands" },

Requirement 40

/req/cql-json/functions

A

A server that implements the Functions requirement class and also implements this requirement shall be able to parse a function call expression encoded as JSON that validates against the following JSON Schema fragment:

   "function": {
      "type": "object",
      "properties": {
         "name": { "type": "string" },
         "arguments": {
            "type": "array",
            "items": {
               "oneOf": [
                  { "type": "string" },
                  { "type": "number" },
                  { "type": "boolean" },
                  { "$ref": "#/definitions/functionObjectArgument" }
               ]
            }
         }
      }
   },

   "functionObjectArgument": {
      "type": "object",
      "properties": {
         "property": { "type": "string" },
         "function": { "$ref": "#/definitions/function" },
         "geometry": { "$ref": "#/definitions/geometryLiteral" },
         "bbox": { "$ref": "#/definitions/bbox" },
         "temporalValue": { "$ref": "#/definitions/temporalLiteral" }
      }
   },

   "scalarOperands": {
      "type": "object",
      "properties": {
         "property": { "type": "string" },
         "function": { "$ref": "#/definitions/function" },
         "value": { "$ref": "#/definitions/scalarLiteral" }
      },
      "minProperties": 2,
      "maxProperties": 2
   },

   "spatialOperands": {
      "type": "object",
      "properties": {
         "property": { "type": "string" },
         "function": { "$ref": "#/definitions/function" },
         "value": {  "$ref": "#/definitions/geometryLiteral" }
      },
      "minProperties": 2,
      "maxProperties": 2
   },

   "temporalOperands": {
      "type": "object",
      "properties": {
         "property": { "type": "string" },
         "function": { "$ref": "#/definitions/function" },
         "value": { "$ref": "#/definitions/temporalLiteral" }
      },
      "minProperties": 2,
      "maxProperties": 2
   },

B

The list of valid function names can be discovered via the functions resource (i.e. path /functions).

Requirement 41

/req/cql-json/arithmetic

A

A server that implements the Arithmetic Expressions requirements class and also implements this requirement shall be able to parse an arithmetic expression encoded as JSON that validates against the following JSON Schema fragment:

   "arithmeticOperands": {
      "type": "object",
      "properties": {
         "property": { "type": "string" },
         "function": { "$ref": "#/definitions/function" },
         "value": { "type": "number" },
         "+": {"$ref": "#/definitions/add"},
         "-": {"$ref": "#/definitions/sub"},
         "*": {"$ref": "#/definitions/mul"},
         "/": {"$ref": "#/definitions/div"}
      },
      "minProperties": 2,
      "maxProperties": 2
   },

   "add": { "$ref": "#/definitions/arithmeticOperands" },
   "sub": { "$ref": "#/definitions/arithmeticOperands" },
   "mul": { "$ref": "#/definitions/arithmeticOperands" },
   "div": { "$ref": "#/definitions/arithmeticOperands" },

12. Media Types

13. Security Considerations

Annex A: Abstract Test Suite (Normative)

add test cases

include::abstract_tests/cc/TEST001.adoc[]

Annex B: CQL BNF (Normative)

#
# MODULE:  cql.bnf
# PURPOSE: A BNF grammar for the Common Query Language (CQL).
# HISTORY:
# DATE         EMAIL                     DESCRIPTION
# 13-SEP-2019  pvretano[at]cubewerx.com  Initial creation
# 28-OCT-2019  pvretano[at]cubewerx.com  Initial checkin into github.
#

#=============================================================================#
# A CQL filter is a logically connected expression of one or more predicates.
#=============================================================================#
cqlFilter = booleanValueExpression;

booleanValueExpression = booleanTerm | booleanValueExpression "OR" booleanTerm;

booleanTerm = booleanFactor | booleanTerm "AND" booleanFactor;

booleanFactor = ["NOT"] booleanPrimary;

booleanPrimary = predicate
               | leftParen cqlFilter rightParen;

#=============================================================================#
#  CQL supports scalar, spatial and temporal predicates.
#=============================================================================#
predicate = comparisonPredicate
          | spatialPredicate
          | temporalPredicate
          | inPredicate;

#=============================================================================#
# A comparison predicate evaluates if two scalar expression statisfy the
# specified comparison operator.  The comparion operators include an operator
# to evaluate regular expressions (LIKE), a range evaluation operator and
# an operator to test if a scalar expression is NULL or not.
#=============================================================================#
comparisonPredicate = binaryComparisonPredicate
                    | propertyIsLikePredicate
                    | propertyIsBetweenPredicate
                    | propertyIsNullPredicate;

binaryComparisonPredicate = scalarExpression comparisonOperator scalarExpression;

propertyIsLikePredicate =  scalarExpression "LIKE" regularExpression;

propertyIsBetweenPredicate = scalarExpression "BETWEEN"
                             scalarExpression "AND" scalarExpression;

propertyIsNullPredicate = scalarExpression "IS" ["NOT"] "NULL";

#
# A scalar expression is the property name, a chracter literal, a numeric
# literal or a function/method invocation that returns a scalar value.
#
scalarExpression = propertyName
                 | characterLiteral
                 | numericLiteral
                 | function
                 | arithmeticExpression;

# NOTE: This is just a place holder for a regular expression
#       We want to be able to say stuff like "<prop> LIKE 'Toronto%'" where
#       the '%' character means "match zero or more characters".
regularExpression = characterLiteral;

comparisonOperator = eq | neq | lt | gt | lteq | gteq;

neq = lt gt;

gteq = gt eq;

lteq = lt eq;

#=============================================================================#
# A spatial predicate evaluates if two spatial expressions satisfy the
# specified spatial operator.
#=============================================================================#
spatialPredicate =  spatialOperator leftParen geomExpression comma geomExpression rightParen;

# NOTE: The buffer operators (DWITHIN and BEYOND) are not included because
#       these are outside the scope of a "simple" core for CQL.  These
#       can be added as extensions.
#
spatialOperator = "EQUALS" | "DISJOINT" | "TOUCHES" | "WITHIN" | "OVERLAPS"
                | "CROSSES" | "INTERSECTS" | "CONTAINS";

# A geometric expression is a property name of a geometry-valued property,
# a geometric literal (expressed as WKT) or a function that returns a
# geometric value.
#
geomExpression = propertyName
               | geomLiteral
               | function;

#=============================================================================#
# A temporal predicate evaluates if two temporal expressions satisfy the
# specified temporal operator.
#=============================================================================#
temporalPredicate = temporalExpression temporalOperator
                    temporalExpression;

temporalExpression = propertyName
                   | temporalLiteral
                   | function;

temporalOperator = "AFTER" | "BEFORE" | "BEGINS" | "BEGUNBY" | "TCONTAINS"
                 | "DURING" | "ENDEDBY" | "ENDS" | "TEQUALS" | "MEETS"
                 | "METBY" | "TOVERLAPS" | "OVERLAPPEDBY" | "ANYINTERACTS"
                 | "INTERSECTS";

#=============================================================================#
# The IN predicate
#=============================================================================#
inPredicate = propertyName "IN" leftParen inList rightParen;

inList = listItem [ {comma listItem} ];

listItem = characterLiteral |
           numericLiteral |
           geomLiteral |
           temporalLiteral |
           function;

#=============================================================================#
# Definition of a FUNCTION
# NOTE: How do we advertise which functions an implementation offer?
#       In the OpenAPI document I suppose!
#=============================================================================#
function = identifier {argumentList};

argumentList = leftParen [positionalArgument]  rightParen;

positionalArgument = argument [ { comma argument } ];

argument = characterLiteral
         | numericLiteral
         | geomLiteral
         | propertyName
         | arithmeticExpression;

#=============================================================================#
# An arithemtic expression is an expression composed of an arithmetic
# operand (a property name, a number or a function that returns a number),
# an arithmetic operators (+,-,*,/) and another arithmetic operand.
#=============================================================================#
arithmeticExpression = arithmeticOperand arithmeticOperator arithmeticOperand;

arithmeticOperator = plusSign | minusSign | asterisk | solidus;

arithmeticOperand = propertyName
                   | numericLiteral
                   | function;

#=============================================================================#
# Definition of NUMERIC literals
#=============================================================================#
numericLiteral = unsignedNumericLiteral | signedNumericLiteral;

unsignedNumericLiteral = exactNumericLiteral | approximateNumericLiteral;

signedNumericLiteral = [sign] exactNumericLiteral | approximateNumericLiteral;

exactNumericLiteral = unsignedInteger [ period [ unsignedInteger ] ]
                      | period unsignedInteger;

approximateNumericLiteral = mantissa "E" exponent;

mantissa = exactNumericLiteral;

exponent = signedInteger;

signedInteger = [ sign ] unsignedInteger;

unsignedInteger = {digit};

sign = plusSign | minusSign;

#=============================================================================#
# Definition of CHARACTER literals
#=============================================================================#
characterLiteral = characterStringLiteral
                 | bitStringLiteral
                 | hexStringLiteral;

characterStringLiteral = quote [ {character} ] quote;

bitStringLiteral = "B" quote [ {bit} ] quote;

hexStringLiteral = "X" quote [ {hexit} ] quote;

propertyName = identifier;

identifier = identifierStart [ {identifierPart} ];

identifierStart = alpha [{octothorp|dollar|underscore|alpha|digit}];

identifierPart = alpha | digit;

character = alpha | digit | specialCharacter | quoteQuote;

quoteQuote = quote quote;

# NOTE: This production is supposed to be any alphabetic character from
#       the character set.
#
#       I use the A-Z, a-z range here as placeholders because:
#       (a) I have no idea how to indicate that alpha can be
#           any alphabetic UTF-8 character
#       (b) the validators I am using can only handle ASCII chars
#
alpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" |
        "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" |
        "W" | "X" | "Y" | "Z" |
        "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" |
        "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" |
        "w" | "x" | "y" | "z";

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";

specialCharacter = percent | ampersand | leftParen | rightParen | asterisk
                 | plusSign | comma | minusSign | period | solidus | colon
                 | semicolon | lt | gt | eq | questionMark | underscore
                 | verticalBar | doubleQuote | dotdot;

octothorp = "#";

dollar = "$";

underscore = "_";

doubleQuote = "\"";

percent = "%";

ampersand = "&";

quote = "'";

leftParen = "(";

rightParen = ")";

asterisk = "*";

plusSign = "+";

comma = ",";

minusSign = "-";

period = ".";

dotdot = "..";

solidus = "/";

colon = ":";

semicolon = ";";

lt = "<";

eq = "=";

gt = ">";

questionMark = "?";

verticalBar = "|";

bit = "0" | "1";

hexit = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f";

#=============================================================================#
# Definition of TEMPORAL literals
#
# NOTE: Is the fact the time zones are supported too complicated for a
#       simple CQL?  Perhaps the "core" of CQL should just support UTC.
#=============================================================================#
temporalLiteral = instant | interval;

instant = fullDate | fullDate "T" utcTime;

interval = solidus |
           solidus dotdot |
           dotdot solidus |
           instant solidus |
           solidus instant |
           instant solidus dotdot |
           dotdot solidus instant |
           instant solidus instant;

fullDate   = dateYear "-" dateMonth "-" dateDay;

dateYear   = digit digit digit digit;

dateMonth  = digit digit;

dateDay    = digit digit;

utcTime  = timeHour ":" timeMinute ":" timeSecond [timeZoneOffset];

timeZoneOffset = "Z" | sign timeHour;

timeHour   = digit digit;

timeMinute = digit digit;

timeSecond = digit digit [period digit {digit}];

#=============================================================================#
# Definition of GEOMETRIC literals
#
# NOTE: This is basically BNF that define WKT encoding; it would be nice
#       to instead reference some normative BNF for WKT.
#=============================================================================#
geomLiteral = pointTaggedText
            | linestringTaggedText
            | polygonTaggedText
            | multipointTaggedText
            | multilinestringTaggedText
            | multipolygonTaggedText
            | geometryCollectionTaggedText
            | envelopeTaggedText;

pointTaggedText = "POINT" pointText;

linestringTaggedText = "LINESTRING" lineStringText;

polygonTaggedText = "POLYGON" polygonText;

multipointTaggedText = "MULTIPOINT" multiPointText;

multilinestringTaggedText = "MULTILINESTRING" multiLineStringText;

multipolygonTaggedText = "MULTIPOLYGON" multiPolygonText;

geometryCollectionTaggedText = "GEOMETRYCOLLECTION" geometryCollectionText;

pointText = leftParen point rightParen;

point = xCoord yCoord [zCoord];

xCoord = signedNumericLiteral;

yCoord = signedNumericLiteral;

zCoord = signedNumericLiteral;

lineStringText = leftParen point {comma point} rightParen;

polygonText =  leftParen lineStringText {comma lineStringText} rightParen;

multiPointText = leftParen pointText {comma pointText} rightParen;

multiLineStringText = leftParen lineStringText {comma lineStringText} rightParen;

multiPolygonText = leftParen polygonText {comma polygonText} rightParen;

geometryCollectionText = leftParen geomLiteral {comma geomLiteral} rightParen;

envelopeTaggedText = "ENVELOPE" envelopeText;

envelopeText = leftParen westBoundLon comma eastBoundLon comma northBoundLat comma southBoundLat [comma minElev comma maxElev] rightParen;

westBoundLon = signedNumericLiteral;

eastBoundLon = signedNumericLiteral;

northBoundLat = signedNumericLiteral;

southBoundLat = signedNumericLiteral;

minElev = signedNumericLiteral;

maxElev = signedNumericLiteral;

Annex C: JSON Schema for CQL (Normative)

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$ref": "#/definitions/predicates",

    "definitions": {

      "predicates": {
        "type": "object",
        "allOf": [
            { "$ref": "#/definitions/logicalExpression" },
            { "$ref": "#/definitions/comparisonExpressions" },
            { "$ref": "#/definitions/spatialExpressions" },
            { "$ref": "#/definitions/temporalExpressions" }
        ],
        "minProperties": 1,
        "maxProperties": 1
      },

      "logicalExpression" : {
        "type": "object",
        "properties": {
            "and": {"$ref": "#/definitions/and" },
            "or": {"$ref": "#/definitions/or" },
            "not": {"$ref": "#/definitions/not" }
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "comparisonExpressions" : {
        "type": "object",
        "properties": {
            "eq": {"$ref": "#/definitions/eq"},
            "lt": {"$ref": "#/definitions/lt"},
            "gt": {"$ref": "#/definitions/gt"},
            "lte": {"$ref": "#/definitions/lte"},
            "gte": {"$ref": "#/definitions/gte"},

            "between": {"$ref": "#/definitions/between"},

            "like": { "$ref": "#/definitions/like" },
            "in": { "$ref": "#/definitions/in" }
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "spatialExpressions" : {
        "type": "object",
        "properties": {
            "equals": {"$ref": "#/definitions/equals"},
            "disjoint": {"$ref": "#/definitions/disjoint"},
            "touches": {"$ref": "#/definitions/touches"},
            "within": {"$ref": "#/definitions/within"},
            "overlaps": {"$ref": "#/definitions/overlaps"},
            "crosses": {"$ref": "#/definitions/crosses"},
            "intersects": {"$ref": "#/definitions/intersects"},
            "contains": {"$ref": "#/definitions/contains"}
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "temporalExpressions" : {
        "type": "object",
        "properties": {
            "after": {"$ref": "#/definitions/after"},
            "before": {"$ref": "#/definitions/before"},
            "begins": {"$ref": "#/definitions/begins"},
            "begunby": {"$ref": "#/definitions/begunby"},
            "tcontains": {"$ref": "#/definitions/tcontains"},
            "during": {"$ref": "#/definitions/during"},
            "endedby": {"$ref": "#/definitions/endedby"},
            "ends": {"$ref": "#/definitions/ends"},
            "tequals": {"$ref": "#/definitions/tequals"},
            "meets": {"$ref": "#/definitions/meets"},
            "metby": {"$ref": "#/definitions/metby"},
            "toverlaps": {"$ref": "#/definitions/toverlaps"},
            "overlappedby": {"$ref": "#/definitions/overlappedby"}
        },
        "minProperties": 1,
        "maxProperties": 1
      },

      "and": { "$ref": "#/definitions/booleanOperands" },
      "or":  { "$ref": "#/definitions/booleanOperands" },
      "not": { "$ref": "#/definitions/predicates" },

      "eq":  { "$ref": "#/definitions/scalarOperands" },
      "lt":  { "$ref": "#/definitions/scalarOperands" },
      "gt":  { "$ref": "#/definitions/scalarOperands" },
      "lte": { "$ref": "#/definitions/scalarOperands" },
      "gte": { "$ref": "#/definitions/scalarOperands" },

      "between": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "lower": { "$ref": "#/definitions/scalarLiteral" },
            "upper": { "$ref": "#/definitions/scalarLiteral" }
         },
         "required" : [ "property", "lower", "upper" ]
      },

      "like": {
         "type": "object",
         "properties": {
            "wildcard": { "type": "string", "default": "%" },
            "singleChar": { "type": "string", "default": "_" },
            "escape": { "type": "string", "default": "\\" },
            "nocase": { "type": "boolean", "default": true },
            "property": { "type": "string" },
            "value": { "$ref": "#/definitions/scalarLiteral" }
         }
      },

      "in": {
         "type": "object",
         "properties": {
            "nocase": { "type": "boolean", "default": true },
            "property": { "type": "string" },
            "values": {
               "type": "array",
               "items": { "$ref": "#/definitions/scalarLiteral" }
            }
         }
      },

      "equals":     { "$ref": "#/definitions/spatialOperands" },
      "disjoint":   { "$ref": "#/definitions/spatialOperands" },
      "touches":    { "$ref": "#/definitions/spatialOperands" },
      "within":     { "$ref": "#/definitions/spatialOperands" },
      "overlaps":   { "$ref": "#/definitions/spatialOperands" },
      "crosses":    { "$ref": "#/definitions/spatialOperands" },
      "intersects": { "$ref": "#/definitions/spatialOperands" },
      "contains":   { "$ref": "#/definitions/spatialOperands" },

      "after":        { "$ref": "#/definitions/temporalOperands" },
      "before":       { "$ref": "#/definitions/temporalOperands" },
      "begins":       { "$ref": "#/definitions/temporalOperands" },
      "begunby":      { "$ref": "#/definitions/temporalOperands" },
      "tcontains":    { "$ref": "#/definitions/temporalOperands" },
      "during":       { "$ref": "#/definitions/temporalOperands" },
      "endedby":      { "$ref": "#/definitions/temporalOperands" },
      "ends":         { "$ref": "#/definitions/temporalOperands" },
      "tequals":      { "$ref": "#/definitions/temporalOperands" },
      "meets":        { "$ref": "#/definitions/temporalOperands" },
      "metby":        { "$ref": "#/definitions/temporalOperands" },
      "toverlaps":    { "$ref": "#/definitions/temporalOperands" },
      "overlappedby": { "$ref": "#/definitions/temporalOperands" },
      "anyinteracts": { "$ref": "#/definitions/temporalOperands" },
      "tintersects":  { "$ref": "#/definitions/temporalOperands" },

      "booleanOperands": {
         "type": "array",
         "items": {
             "$ref": "#/definitions/predicates",
             "minItems": 2
         }
      },

      "arithmeticOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "function": { "$ref": "#/definitions/function" },
            "value": { "type": "number" },
            "+": {"$ref": "#/definitions/add"},
            "-": {"$ref": "#/definitions/sub"},
            "*": {"$ref": "#/definitions/mul"},
            "/": {"$ref": "#/definitions/div"}
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "add": { "$ref": "#/definitions/arithmeticOperands" },
      "sub": { "$ref": "#/definitions/arithmeticOperands" },
      "mul": { "$ref": "#/definitions/arithmeticOperands" },
      "div": { "$ref": "#/definitions/arithmeticOperands" },

      "scalarOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "function": { "$ref": "#/definitions/function" },
            "value": { "$ref": "#/definitions/scalarLiteral" },
            "+": {"$ref": "#/definitions/add"},
            "-": {"$ref": "#/definitions/sub"},
            "*": {"$ref": "#/definitions/mul"},
            "/": {"$ref": "#/definitions/div"}
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "spatialOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "function": { "$ref": "#/definitions/function" },
            "value": {  "$ref": "#/definitions/geometryLiteral" }
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "temporalOperands": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "function": { "$ref": "#/definitions/function" },
            "value": { "$ref": "#/definitions/temporalLiteral" }
         },
         "minProperties": 2,
         "maxProperties": 2
      },

      "function": {
         "type": "object",
         "properties": {
            "name": { "type": "string" },
            "arguments": {
               "type": "array",
               "items": {
                  "oneOf": [
                     { "type": "string" },
                     { "type": "number" },
                     { "type": "boolean" },
                     { "$ref": "#/definitions/functionObjectArgument" }
                  ]
               }
            }
         }
      },

      "functionObjectArgument": {
         "type": "object",
         "properties": {
            "property": { "type": "string" },
            "function": { "$ref": "#/definitions/function" },
            "geometry": { "$ref": "#/definitions/geometryLiteral" },
            "bbox": { "$ref": "#/definitions/bbox" },
            "temporalValue": { "$ref": "#/definitions/temporalLiteral" },
            "+": {"$ref": "#/definitions/add"},
            "-": {"$ref": "#/definitions/sub"},
            "*": {"$ref": "#/definitions/mul"},
            "/": {"$ref": "#/definitions/div"}
         }
      },

      "scalarLiteral": {
         "oneOf": [
            { "type": "string" },
            { "type": "number" },
            { "type": "boolean"}
         ]
      },

      "geometryLiteral": {
         "type": "object"
      },

      "bbox": {
        "type": "array",
        "items": {
            "type": "number",
            "oneOf": [
              { "minItems": 4, "maxItems": 4},
              { "minItems": 6, "maxItems": 6}
            ]
        }
      },

      "envelopeLiteral": {
         "type": "object",
         "properties": {
            "bbox": { "$ref": "#/definitions/bbox" }
         }
      },

      "temporalLiteral": {
         "oneOf": [
            { "$ref": "#/definitions/timeLiteral" },
            { "$ref": "#/definitions/periodLiteral" }
         ]
      },

      "timeLiteral": {
         "type": "string",
         "pattern": "[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-9][0-9](T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](.[0-9]*)?)?"
      },

      "periodLiteral": {
         "type": "array",
         "items": {
            "$ref": "#/definitions/timeLiteral",
            "minItems": 2,
            "maxItems": 2
        }
     }
   }
}

Annex D: Revision History

Date Release Editor Primary clauses modified Description

2020-04-06

1.0.0-DRAFT

P. Vretanos

all

initial version

Annex E: Bibliography