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-draft.2

Latest Published Draft: n/a

Category: OGC® Implementation Specification

Editors: Panagiotis (Peter) A. Vretanos, Clemens Portele

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

Copyright notice

Copyright © 2020 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.

Table of Contents

i. Abstract

OGC API standards define modular API building blocks to spatially enable Web APIs 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 part is a separate standard.

A fundamental operation performed on a collection of features is that of filtering in order to obtain a subset of the data which contains feature instances that satisfy some filtering criteria. Part three of the OGC API - Feature Standard defines

  • Query parameters (filter, filter-lang, filter-crs) to specify filter criteria in a request to an API;

  • A filter grammar called Common Query Language (CQL) for specifying enhanced filtering criteria beyond what is supported in the Core;

  • Two encodings for CQL - a text and a JSON encoding.

The Common Query Language (CQL) defined in this document is a generic filter grammar that can be used to specify how resource instances in a source collection of any item type, including features, can be filtered to identify a results set. Typically, CQL is used in query operations to identify the subset of resources, such as features, that should be included in a response document. However, CQL can also be used in other operations, such as updates, to identify the subset of resources that should be affected by an operation.

Each resource instance in the source collection is evaluated against a filtering expression. The filter expression always evaluates to true, false or null. 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 or null, 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.

CQL and its text encoding are not new, but this is the first time CQL is properly specified. CQL was created as a text encoding based on the capabilities defined in the OGC Filter Encoding standard for use in the OGC Catalogue Service standard. It was one of the design goals to keep CQL as compatible as possible with existing implementations. For example, the classification of operators into logical, comparison, spatial and temporal operators as well as their names and syntax are unchanged from the original definitions in OGC Filter Encoding. For the spatial and temporal operators this document either defines the operator or references to definition of the operator.

Caution
This is a DRAFT version of the 3rd 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.

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

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.

  • GeoSolutions di Giannecchini Simone & C. s.a.s.

  • interactive instruments GmbH

  • US Army Geospatial Center (AGC)

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

Andrea Aime

GeoSolutions di Giannecchini Simone & C. s.a.s.

Jeff Harrison

US Army Geospatial Center (AGC)

1. Scope

This document specifies an extension to the OGC API - Features - Part 1: Core standard that defines the behavior 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 Part 1 (i.e., bbox and datetime).

This document defines

  • Query parameters for specifying a filter in a request to a Web API;

  • A text encoding for a CQL filter suitable for use as a query parameter in a URL;

  • A JSON encoding for a CQL filter suitable for use in a HTTP POST body;

  • How the set of properties or keys that can be used to construct CQL expressions ("queryables") are published by a Web API.

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 is:

  • filter - The filter expression.

  • filter-lang - The language used in the filter expression.

  • filter-crs - The Coordinate Reference System used in the filter expression.

This conformance class also defines the Queryables resource (at paths /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 the Filter conformance class and the OGC API - Features - Part 1: Core standard.

The Simple CQL conformance class defines the minimal subset of the Common Query Language (CQL) that all implementations must support ("Simple 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 standard (i.e., bbox, datetime and optionally collection-specific properties).

Note
OGC API - Common is still in draft form and is not an official OGC standard.

The specific set of operators defined in this conformance class is:

  • 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

Note
The anyinteracts temporal operator is defined in this document by requirement /req/simple-cql/temporal-predicate.

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

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 Functions resource (at path /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 Arrays conformance class specifies requirements for comparison operators for sets of values. The operators that must be supported are:

  • aequals

  • acontains

  • containedby

  • aoverlaps

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.

2.1. Roadmap

The content of this sub-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 of standards thus leaving the Features Filter conformance class as part 3 of the OGC API Features specifications.

3. 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.

  • Open Geospatial Consortium (OGC). OGC 17-069r3: OGC API - Features - Part 1: Core [online]. Edited by C. Portele, P. Vretanos, C. Heazel. 2019 [viewed 2020-11-22]. Available at http://docs.opengeospatial.org/is/17-069r3/17-069r3.html

  • Open Geospatial Consortium (OGC). OGC 18-058: OGC API - Features - Part 2: Coordinate Reference Systems by Reference [online]. Edited by C. Portele, P. Vretanos. 2020 [viewed 2020-12-03]. Available at http://docs.opengeospatial.org/is/18-058/18-058.html

  • Open Geospatial Consortium (OGC). OGC 06-103r4: OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture [online]. Edited by J. Herring. 2011 [viewed 2020-11-22]. Available at http://portal.opengeospatial.org/files/?artifact_id=25355

  • Open Geospatial Consortium (OGC) / World Wide Web Consortium (W3C). OGC 16-071r3: Time Ontology in OWL [online]. Edited by S. Cox, C. Little. 2020 [viewed 2020-11-22]. Available at https://www.w3.org/TR/owl-time

  • Egenhofer M.J., Herring J.R., A Mathematical Framework for the Definition of Topological Relationships, Fourth International Symposium on Spatial Data Handling, Zurich, Switzerland, July 1990

4. Terms, Definitions and Symbols

4.1. 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.

4.1.1. collection

a body of resources that belong or are used together; an aggregate, set, or group of related resources (OGC 20-024, OGC API - Common - Part 2: Collections).

4.1.2. endpoint

a web address (URI) at which access can be gained to a service or resource

4.1.3. filter

predicate encoded for transmission between systems

4.1.4. predicate

set of computational operations applied to a data instance which evaluate to true or false (OGC Filter Encoding 2.0 Encoding Standard - With Corrigendum)

4.1.5. publisher

entity responsible for making a resource available (Dublic Core Metadata Initiative - DCMI Metadata Terms)

Note
As content of OGC API standards, a resource is typically published at an endpoint.

4.1.6. queryable

a token that represents a property of a resource that can be used in a filter expression

4.1.7. resource / web resource

any information that can be named and is the intended conceptual target of a hypertext reference (Architectural Styles and the Design of Network-based Software Architectures)

4.2. Symbols

  • intersection, operation on two or more sets

  • and, logical intersection

  • empty set, the set having no members

  • not equal

  • if and only if, logical equivalence between statements

  • is a subset of

  • dim(x) returns the maximum dimension (-1, 0, 1, or 2) of the geometric object x

  • I(x) represents the interior of the geometric object x

  • B(x) represents the boundary of the geometric object x

  • E(x) represents the exterior of the geometric object x

5. Conventions and background

5.1. General remarks

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

5.2. Identifiers

The normative provisions in this standard are denoted by the URI http://www.opengis.net/spec/ogcapi-features-3/1.0.

All requirements and conformance tests that appear in this document are denoted by partial URIs which are relative to this base.

The following OGC link relation types are introduced in this document (no applicable registered link relation type could be identified):

  • http://www.opengis.net/def/rel/ogc/1.0/queryables: Refers to a resource that lists properties that can be used to query items in the collection represented by the link’s context.

5.4. Use of BNF

BNF as specified in Augmented BNF for Syntax Specifications is used to formally specify the grammar of the Common Query Language (CQL).

5.5. Use of JSON Schema

JSON Schema draft 2019-09 ([JSONSCHEMA], [JSONSCHEMAVALIDATION]) is used to formally specify the schema of the JSON encoding of CQL (CQL-JSON).

5.6. Dependencies to other requirements classes

The requirements classes in this extension distinguish two types of dependencies to other specifications or requirements classes:

First, there are the "regular" dependencies. Every server implementing the requirements class has to conform to the referenced specification or requirements class.

In addition, requirements classes can also have "conditional dependencies". Servers implementing the requirements class do not have to conform to the referenced specification or requirements class, but if they do, they have to conform to the requirements that identify the conditional dependency as a pre-condition for the normative statement.

6. Requirements Class "Filter"

6.1. Overview

Requirements Class

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

Target type

Web API

Conditional Dependency

OGC API - Features - Part 2: Coordinate Reference Systems by Reference

OGC API - Features - Part 1: Core (and the draft OGC API - Common - Part 2: Geospatial Data standard) define two filtering parameters on the resource at path /collections/{collectionId}/items: bbox and datetime. OGC API - Features - Part 1: Core also adds support for simple equality predicates logically joined using the AND operator. These capabilities offer simple resource filtering for HTTP requests.

The Filter requirements 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.

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

6.2. Queryables

This standard does not assume that the content schema of a resource being queried is available for inspection. Therefore, 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 ("queryables").

In addition, a publisher may want to support queryables that are not directly represented as resource properties in the content schema of the resource. Or the publisher may want to restrict filtering on certain properties. For example, because the backend datastore has not been configured to allow high-performance queries on those properties.

Requirement 1

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

A

A server that implements this requirements class SHALL support the HTTP GET operation at the path /queryables and the media type application/schema+json.

B

The queryables accessed at this path SHALL be valid for all collections identified in the Collections resource (path /collections).

C

The Queryables resource SHALL be referenced from the Landing Page resource with a link with the link relation type http://www.opengis.net/def/rel/ogc/1.0/queryables.

Requirement 2

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

A

For every collection identified in the Collections resource (path /collections), the server SHALL support the HTTP GET operation at the path /collections/{collectionId}/queryables and the media type application/schema+json.

B

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

C

The Queryable resource SHALL be referenced from the Collection resource with a link with the link relation type http://www.opengis.net/def/rel/ogc/1.0/queryables.

Requirement 3

/req/filter/get-queryables-response

A

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

B

For responses that use application/schema+json as the Content-Type of the response, the response SHALL have the following characteristics:

  • The property $schema is http://json-schema.org/draft-07/schema# or https://json-schema.org/draft/2019-09/schema.

  • The property $id is the URI of the resource without query parameters.

  • The type is object and each property is a queryable.

To support clients, providing additional detail about the meaning of the property and the possible values is recommended:

Recommendation 1

/rec/filter/queryables-schema

A

Each property SHOULD have a human readable title (title) and where necessary a description (description).

B

Each property SHOULD have a single type (type).

C

For string properties minLength, maxLength, enum and/or pattern SHOULD be provided, where applicable.

D

For numeric properties multipleOf, minimum, exclusiveMinimum, maximum, exclusiveMaximum SHOULD be provided, where applicable.

E

For integer properties that represent enumerated values, enum SHOULD be provided.

F

For temporal properties, the property SHOULD be a string literal with the appropriate format date-time, date, time, or duration.

G

For spatial properties, the property SHOULD reference a well-known JSON schema of the geometry object.

H

For geometry types according to the Simple Features standard, the JSON Schema of the GeoJSON geometry object SHOULD be referenced; for example, https://geojson.org/schema/Point.json for a point geometry.

I

For array properties, the property SHOULD consist of items that are strings or numbers.

Example 1. Queryables example
{
  "$schema" : "https://json-schema.org/draft/2019-09/schema",
  "$id" : "https://demo.ldproxy.net/daraa/collections/CulturePnt/queryables",
  "type" : "object",
  "title" : "Cultural (Points)",
  "description" : "Cultural: Information about features on the landscape with a point geometry that have been constructed by man.",
  "properties" : {
    "F_CODE" : {
      "title" : "Feature Type",
      "type" : "string",
      "enum" : [ "AK121", "AL012", "AL030", "AL130", "BH075" ]
    },
    "ZI001_SDV" : {
      "title" : "Last Change",
      "type" : "string",
      "format" : "date-time"
    },
    "ZI037_REL" : {
      "title" : "Religious Designation",
      "type" : "integer",
      "enum" : [ -999999, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]
    },
    "geometry" : {
      "$ref" : "https://geojson.org/schema/Point.json"
    }
  }
}

6.3. Parameter filter

The Filter requirements class defines a general parameter, filter, whose value is a filter expression to be applied when retrieving resources. This is necessary 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

6.4. Cross-collection queries

The only filterable resource defined in OGC API - Features - Part 1: Core is the Features resource at /collections/{collectionId}/items which operates on a single collection. However an API can provide other, higher level, resources 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, the filter parameter, if provided, applies to all referenced collections. Of course this 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 queries across multiple collections 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 hypothetical Query resource that uses a CQL filter and references multiple collections:

Multi-collection filter example
http://www.someserver.com/ogcapi/search?
  collections=collection1,collection3&
  filter-lang=cql-text&
  filter=prop1=10 AND prop2>45
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.

6.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

B

The enum array in the schema of filter-lang SHALL list the filter encodings that the server supports for the resource.

C

The default value in the schema of filter-lang SHALL identify the filter encoding that the server will assume, if a filter is provided, but no filter-lang.

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.

6.6. Parameter filter-crs

For reasons discussed in the W3C/OGC Spatial Data on the Web Best Practices document, OGC API - Features - Part 1: Core uses WGS 84 longitude and latitude and the default Coordinate Reference System. OGC API - Features - Part 2: Coordinate Reference Systems by Reference extends the capabilities of Part 1 to allow other coordinate systems to be used. The filter-crs parameter defined in this clause allows clients to indicate to servers that support other CRSs, which CRS is being used to encode geometric values in a filter expression.

Requirement 7

/req/filter/filter-crs-wgs84

A

If a HTTP GET operation on the path that fetches resource instances (e.g. /collections/{collectionId}/items) includes a filter parameter, but no filter-crs parameter, the server SHALL process all geometries in the filter expression using CRS84 (for coordinates without height) or CRS84h (for coordinates with height) as the coordinate reference system (CRS).

Requirement 8

/req/filter/filter-crs-param

Condition

A

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

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

B

If a HTTP GET operation on the path that fetches resource instances (e.g. /collections/{collectionId}/items) includes the filter and the filter-crs parameter, the server SHALL process all geometries in the filter expression using the CRS identified by the URI in filter-crs.

C

The server SHALL return an error, if it does not support the CRS identified in filter-crs for the resource.

6.7. Interaction with other predicates

OGC API - Features - Part 1: Core defines the parameters bbox, datetime and parameters for filtering on feature properties. This clause defines how the filter parameter and these core parameters should interact if specified in a single request.

Requirement 9

/req/filter/mixing-expression

A

Other filter predicates supported by the server (e.g. bbox, datetime, etc.) SHALL be logically connected with the AND operator when mixed in a request with the filter parameter.

6.8. Filter expression languages

This standard defines a filter expression language called the Common Query Language (CQL). However, support for this filter expression language is not mandatory and other languages can be used as the value of the filter parameter, too.

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 the intended use.

6.9. Response

A filter expression defines a subset of items from a collection that should be presented in a query response.

Requirement 10

/req/filter/response

A

The filter expression SHALL be evaluated for each item of the collection being queried.

B

If the filter expression evaluates to TRUE then the item SHALL be included in the result set.

C

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

7. Requirements Class "Features Filter"

7.1. Overview

Requirements Class

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

Target type

Web API

Dependency

Requirements Class "Filter"

Dependency

OGC API - Features - Part 1: Core, Requirements Class "Core"

Conditional Dependency

OGC API - Features - Part 2: Coordinate Reference Systems by Reference

This clause defines the binding between the OGC API - Features - Part 1: Core standard and the filter parameters defined in the Filter conformance class.

7.2. Features

7.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 2

/rec/features-filter/text-encoding

A

If a filter expression can be represented for its intended use as text, servers SHOULD consider supporting the CQL text encoding.

Recommendation 3

/rec/features-filter/JSON-encoding

A

If a filter expression can be represented for its intended use as JSON, servers SHOULD consider supporting the CQL JSON encoding.

Requirement 13

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

Condition

A

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

7.2.2. Response

Requirement 14

/req/features-filter/response

A

A 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 filter expression AND all other specified filtering parameters (i.e. zero or more of bbox, datetime and property filters) evaluate to TRUE then the feature SHALL be included in the result set.

D

If the 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.

8. Requirements Class "Simple CQL"

8.1. Overview

Requirements Class

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

Target type

Web API

This clause defines the core of a query language called Common Query Language (CQL) that may be used to construct filter expressions. This core is called Simple CQL.

Subsequent clauses define additional filtering capabilities as well as several encodings of CQL.

8.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 predicate is an expression that evaluates to the Boolean values of TRUE or FALSE or that evaluates to the value NULL when dealing with unknown values.

If a predicate evaluates to TRUE for an item, the item qualifies for further processing such as presentation in the result set, being passed on to the next predicate in the filter for further evaluation, and so forth.

If the predicate evaluates to FALSE or NULL for an item, the item is not available for further processing.

A collection item that satisfies ALL the requirements of a CQL filter expression evaluates to a Boolean value of TRUE; otherwise the CQL filter expression evaluates to FALSE.

Requirement 15

/req/simple-cql/cqlfilter

A

A server SHALL support a CQL filter expression composed of a logically connected series of one or more predicates as described by the BNF rule booleanValueExpression in CQL BNF with the following exceptions:

  • the rules arrayPredicate, function and arithmeticExpression do not have to be supported;

  • in rule spatialOperator only "INTERSECTS" has to be supported;

  • in rule temporalOperator only "ANYINTERACTS" has to be supported.

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

  • comparison predicates

  • spatial predicates

  • temporal predicates

Support for the parts of CQL that are not part of Simple CQL is added in additional requirements classes in Common Query Language enhancements:

Examples of Simple CQL filter expressions are included in the subsequent sub-clauses.

8.3. Literal values

A literal value is any part of an CQL filter expression that is used exactly as it is specified in the expression. Literal values include:

  • character strings (rule characterLiteral),

  • numbers (rule numericLiteral),

  • booleans (rule booleanLiteral),

  • spatial geometries (rule spatialLiteral) and

  • temporal geometries (rule temporalLiteral).

Example 2. Literal examples
  • character string

'This is a literal string.'
  • number

-100
3.14159
  • boolean

true
false
t
f
  • spatial geometry (text)

POLYGON((43.5845 -79.5442, 43.6079 -79.4893, 43.5677 -79.4632, 43.6129 -79.3925, 43.6223 -79.3238, 43.6576 -79.3163, 43.7945 -79.1178, 43.8144 -79.1542, 43.8555 -79.1714, 43.7509 -79.6390, 43.5845 -79.5442))
  • spatial geometry (JSON)

{
   "type": "Polygon",
   "coordinates": [
       [
          [43.5845,-79.5442],
          [43.6079,-79.4893],
          [43.5677,-79.4632],
          [43.6129,-79.3925],
          [43.6223,-79.3238],
          [43.6576,-79.3163],
          [43.7945,-79.1178],
          [43.8144,-79.1542],
          [43.8555,-79.1714],
          [43.7509,-79.6390],
          [43.5845,-79.5442]
      ]
   ]
}
  • temporal geometry (instants, text)

1969-07-20
1969-07-20T20:17:40Z
  • temporal geometry (instants, JSON)

"1969-07-20"
"1969-07-20T20:17:40Z"
  • temporal geometry (intervals, text)

1969-07-16/1969-07-24
1969-07-16T05:32:00Z/1969-07-24T16:50:35Z
2019-09-09/..
  • temporal geometry (intervals, JSON)

[ "1969-07-16", "1969-07-24" ]
[ "1969-07-16T05:32:00Z", "1969-07-24T16:50:35Z" ]
[ "2019-09-09", ".." ]
Note
The current BNF rule for temporal literals supports timestamps in any time zone. Should this be restricted to UTC ("Z"), at least in Simple CQL? See issue 483.

8.4. Property references

Properties in an object being evaluated in the CQL filter expression can be referenced by their name (rule propertyName).

Requirement 16

/req/simple-cql/property

A

The property name (rule propertyName) SHALL be a queryable of the items in the collection.

B

The property name reference SHALL evaluate to a literal value or NULL.

C

The data type of the literal value SHALL match the expected data type for the expression within which the property name reference appears.

For example, a property name used in a scalar expression (rule scalarExpression) has to be a queryable of type string, number, integer or boolean.

Example 3. Property reference in a scalar expression

In this example, the property windSpeed is used in a function that returns a number.

avg(windSpeed)
{ "function": { "name": "avg", "arguments": [ { "property": "windSpeed" } ] } }

8.5. Comparison predicates

Requirement 17

/req/simple-cql/binary-comparison-predicate

A

A binary comparison predicate as specified by rule binaryComparisonPredicate evaluates two scalar expressions to determine if the expressions satisfy the specified comparison operator. If the requirements of the operator are satisfied, then the predicate SHALL evaluate to the Boolean value TRUE; otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

Both scalar expressions (rules scalarExpression) in rule binaryComparisonPredicate SHALL evaluate to the same type of literal.

Example 4. Binary comparison predicates
city='Toronto'
{ "eq": [ { "property": "city" }, "Toronto" ] }
avg(windSpeed) < 4
{
  "lt": [
    { "function": { "name": "avg", "arguments": [ { "property": "windSpeed" } ] } },
    4
  ]
}
balance-150.0 > 0
{
  "gt": [
    { "-": [ { "property": "windSpeed" }, 150.0 ] },
    0
  ]
}

Requirement 18

/req/simple-cql/like-predicate

A

The like predicate (rule isLikePredicate) tests whether a string value matches the specified pattern. If the value matches the pattern (rule patternExpression), then the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

The scalar expression (rule scalarExpression) in rule isLikePredicate SHALL evaluate to a characterLiteral.

C

The character specified using the WILDCARD modifier SHALL match zero of more characters in the test value.

D

The wildchar character SHALL not match the NULL value.

E

If the WILDCHAR modifier is not specified, the default wildcard character SHALL be "%".

F

The character specified using the SINGLECHAR modifier SHALL match exactly one characters in the test value.

G

If the SINGLECHAR modifier is not specified, the default singlechar character SHALL be "_".

H

The character specified using the ESCAPECHAR modifier SHALL be used to escape the WILDCHAR and/or SINGLECAHR characters in the pattern string.

I

If the ESCAPECHAR modifier is not specified, the default escapechar character SHALL be "\".

J

If NOCASE is TRUE, the comparison SHALL be case insensitive, if it is FALSE it SHALL be case sensitive. The default is TRUE.

Example 5. Example of a LIKE predicate
name LIKE 'Smith.' SINGLECHAR '.' NOCASE true
{
  "like": [
    { "property": "name" },
    "Smith."
  ],
  "singleChar": ".",
  "nocase": true
}

Requirement 19

/req/simple-cql/between-predicate

A

The between predicate (rule isBetweenPredicate) tests whether a numeric value lies within the specified range. The between operator is inclusive. If the value lies within the specified range, then the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

Any function (rule function) or property (rule propertyName) in rule isBetweenPredicate SHALL evaluate to a numericLiteral.

Example 6. Examples of a BETWEEN predicate
depth BETWEEN 100.0 and 150.0
{
  "between": {
     "value": { "property": "depth" },
     "lower": 100.0,
     "upper": 150.0
  }
}

Requirement 20

/req/simple-cql/in-predicate

A

The in-list predicate (rule isInListPredicate) tests, for equality, the value of a scalar expression against a list of values of the same type. If the value on the left side of the predicate is equal to one or more of the values in the list on the right side of the predicate, the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

The items in the list of an in-list predicate (rule inListOperand, i.e., the items on the right hand side of the predicate) SHALL be of the same literal type as the value being tested by the predicate (rule inListOperand, i.e., the left hand side of the predicate), if evaluated.

Example 7. Examples of a IN predicate
cityName IN ('Toronto','Franfurt','Tokyo','New York') NOCASE false
{
  "in": {
     "value": { "property": "cityName" },
     "list": [ "Toronto", "Franfurt", "Tokyo", "New York" ],
     "nocase": false
  }
}
category NOT IN (1,2,3,4)
{
  "not": {
    "in": {
       "value": { "property": "category" },
       "list": [ 1, 2, 3, 4 ]
    }
  }
}

Requirement 21

/req/simple-cql/null-predicate

A

The null predicate (rule isNullPredicate) tests whether the value of a scalar expression is null. If the value of the scalar expression is null, the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the null predicate SHALL evaluate to the Boolean value FALSE.

Example 8. Examples of a NULL predicate
geometry IS NOT NULL
{ "not": { "isNull" : { "property": "geometry" } } }

8.6. Spatial predicates

A spatial predicate evaluates two geometry-valued expressions to determine if the expressions satisfy the requirements of the specified spatial operator.

In this conformance class, the only required spatial operator is intersects. Additional spatial operators are specified in the Enhanced Spatial Operators requirements class.

Requirement 22

/req/simple-cql/spatial-predicate

A

If the requirements of the spatial operator are satisfied, then the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

The INTERSECTS operator SHALL be evaluated as defined in clause 6.1.15 of OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture (except that in CQL the predicates evaluate to a Boolean, not as an Integer).

Note
The spatial predicates currently use a different pattern than the comparison and temporal predicates and are written like function calls. This difference is inherited from previous versions of CQL. It is an open issue, whether this version of CQL should change the spatial predicates to be consistent with the other predicates or to keep the legacy because of existing CQL implementations. Comments are welcome in the GitHub issue on this topic.

CQL uses Well-Known-Text (WKT) to encode geometry literals. Since WKT does not provide a capability to specify the CRS of a geometry literal, the server has to determine the CRS of the geometry literals in a filter expression through another mechanism. In this standard, the filter-crs query parameter is used to pass the CRS information to the server.

Example 9. Example spatial predicate
INTERSECTS(geometry,POLYGON((36.319836 32.288087,36.320041 32.288032,36.320210 32.288402,36.320008 32.288458,36.319836 32.288087)))
{ "intersects": [
   { "property": "geometry" },
   {
      "type": "Polygon",
      "coordinates": [
         [
            [36.319836, 32.288087],
            [36.320041, 32.288032],
            [36.320210, 32.288402],
            [36.320008, 32.288458],
            [36.319836, 32.288087]
         ]
      ]
   }
] }
Example 10. Example for the filter-crs query parameter
...filter-lang=cql-text&
   filter-crs=http://www.opengis.net/def/crs/EPSG/0/32635&
   filter=INTERSECTS(geometry,POLYGON((1379213.867288 3610774.164192,1379233.837424 3610769.696029,1379246.149564 3610812.389132,1379226.494235 3610816.884823,1379213.867288 3610774.164192)))...

8.7. Temporal predicates

A temporal predicate evaluates two time-valued expressions to determine if the expressions satisfy the requirements of the specified temporal operator.

In this conformance class, the only required temporal operator is anyinteracts. The anyinteracts operator is not defined in any of the cited references. Rather, it is defined in this standard as an analogous temporal operator to the intersects spatial operator.

Additional temporal operators are specified in the Enhanced Temporal Operators requirements class.

Requirement 23

/req/simple-cql/temporal-predicate

A

If the requirements of the temporal operator are satisfied, then the predicate SHALL evaluate to the Boolean value TRUE. Otherwise the predicate SHALL evaluate to the Boolean value FALSE.

B

The ANYINTERACTS operator SHALL evaluate as (using the temporal operators from Requirements Class "Enhanced Temporal Operators"):

ANYINTERACTS(i,j) = NOT( BEFORE(i,j) OR MEETS(i,j) OR METBY(i,j) OR AFTER(i,j) )

All temporal literals are in the Gregorian Calendar.

Note
This is a deliberate restriction to keep implementations of CQL simple, avoiding requirements to transformation time instants to other temporal coordinate reference systems, but still cover a large number of use cases. This is consistent with the use of RFC 3339 as a key standard for expressing date and time on the internet, including in the OGC API standards.
Example 11. Examples temporal predicate
event_date ANYINTERACTS 1969-07-16T05:32:00Z/1969-07-24T16:50:35Z
{
   "anyinteracts": [
      { "property": "event_date" },
      [ "1969-07-16T05:32:00Z","1969-07-24T16:50:35Z" ]
   ]
}

8.8. CQL Encodings

This OGC API - Features - Part 3 standard defines a text encoding and a JSON encoding of CQL that covers Simple CQL and all enhanced capabilities specified in the next clause.

9. Common Query Language enhancements

9.1. Overview

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

  • Additional spatial operators;

  • Additional temporal operators;

  • Support for functions in CQL;

  • Support for arithmetic expression in CQL;

  • Support for arrays in CQL.

In each case, this clause specifies requirements for the rules in CQL BNF not supported by Simple CQL.

9.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

Requirements Class "Simple CQL"

The Simple CQL clause specifies the use of the INTERSECTS spatial operator. This requirement adds additional Dimensionally Extended Nine-intersection Model (DE-9IM) relation operators to the list of spatial operators that an implementation of this extension might offer.

Requirement 24

/req/enhanced/spatial-operators

A

The server SHALL support all spatial operators as defined by the BNF rule spatialOperator in CQL BNF.

B

The spatial operators in addition to INTERSECTS SHALL be evaluated as defined in clause 6.1.15 of OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture (except that in CQL the predicates evaluate to a Boolean, not an Integer).

Note
The spatial predicates currently use a different pattern than the comparison and temporal predicates and are written like function calls. This difference is inherited from previous versions of CQL. This is an open issue: Whether this version of CQL used in the OGC API - Features - Part 3 standard should change the spatial predicates to be consistent with the other predicates or to keep the legacy because of existing CQL implementations. Comments are welcome in the GitHub issue on this topic.

The following table lists the mathematical definitions of each spatial operator as described in OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture.

Table 1. Mathematical definitions of spatial operators
Spatial operator Definition

EQUALS

EQUALS(a,b) ⬄ a ⊆ b ∧ b ⊆ a

DISJOINT

DISJOINT(a,b) ⬄ a ∩ b = ∅

TOUCHES

TOUCHES(a,b) ⬄ (I(a) ∩ I(b) = ∅) ∧ (a ∩ b) ≠ ∅

WITHIN

WITHIN(a,b) ⬄ (a ∩ b = a) ∧ (I(a) ∩ E(b) ≠ ∅)

OVERLAPS

OVERLAPS(a,b) ⬄ (dim(I(a)) = dim(I(b)) = dim(I(a) ∩ I(b))) ∧ (a ∩ b ≠ a) ∧ (a ∩ b ≠ b)

CROSSES

CROSSES(a,b) ⬄ [I(a) ∩ I(b) = ∅) ∧ (a ∩ b ≠ a) ∧ (a ∩ b ≠ b)]

INTERSECTS

INTERSECTS(a,b) ⬄ ! a DISJOINT b

CONTAINS

CONTAINS(a,b) ⬄ b CONTAINS a

The following diagrams illustrate the meaning of the TOUCHES, WITHIN, OVERLAPS, and CROSSES operators.

Touches
Figure 1. Examples of the TOUCHES relationship
Within
Figure 2. Examples of the WITHIN relationship Polygon/Polygon(a), Polygon/LineString(b), LineString/LineString(c), and Polygon/Point(d)
Note
If geometry a CONTAINS geometry b, then geometry b is WITHIN geometry a.
Overlaps
Figure 3. Examples of the OVERLAPS relationship Polygon/LineString(a) and LineString/LineString(b).
Crosses
Figure 4. Examples of the CROSSES relationship Polygon/LineString(a) and LineString/LineString(b).
Example 12. Example of a spatial relationship between two literal geometries.
CROSSES(LINESTRING(43.72992 -79.2998, 43.73005 -79.2991, 43.73006 -79.2984,
                   43.73140 -79.2956, 43.73259 -79.2950, 43.73266 -79.2945,
                   43.73320 -79.2936, 43.73378 -79.2936, 43.73486 -79.2917),
        POLYGON((43.7286 -79.2986, 43.7311 -79.2996, 43.7323 -79.2972, 43.7326 -79.2971,
                 43.7350 -79.2981, 43.7350 -79.2982, 43.7352 -79.2982, 43.7357 -79.2956,
                 43.7337 -79.2948, 43.7343 -79.2933, 43.7339 -79.2923, 43.7327 -79.2947,
                 43.7320 -79.2942, 43.7322 -79.2937, 43.7306 -79.2930, 43.7303 -79.2930,
                 43.7299 -79.2928, 43.7286 -79.2986)))
{
   "crosses": [
      {
         "type": "LineString",
         "coordinates": [
            [43.72992,-79.2998], [43.73005,-79.2991], [43.73006,-79.2984],
            [43.73140,-79.2956], [43.73259,-79.2950], [43.73266,-79.2945],
            [43.73320,-79.2936], [43.73378,-79.2936], [43.73486,-79.2917]
         ]
      },
      {
         "type": "Polygon",
         "coordinates": [
            [43.7286,-79.2986], [43.7311,-79.2996], [43.7323,-79.2972],
            [43.7326,-79.2971], [43.7350,-79.2981], [43.7350,-79.2982],
            [43.7352,-79.2982], [43.7357,-79.2956], [43.7337,-79.2948],
            [43.7343,-79.2933], [43.7339,-79.2923], [43.7327,-79.2947],
            [43.7320,-79.2942], [43.7322,-79.2937], [43.7306,-79.2930],
            [43.7303,-79.2930], [43.7299,-79.2928], [43.7286,-79.2986]
         ]
      }
   ]
}
Example 13. Example of a spatial relationship between a property and a literal geometry.
CROSSES(road,POLYGON((43.7286 -79.2986, 43.7311 -79.2996, 43.7323 -79.2972,
                      43.7326 -79.2971, 43.7350 -79.2981, 43.7350 -79.2982,
                      43.7352 -79.2982, 43.7357 -79.2956, 43.7337 -79.2948,
                      43.7343 -79.2933, 43.7339 -79.2923, 43.7327 -79.2947,
                      43.7320 -79.2942, 43.7322 -79.2937, 43.7306 -79.2930,
                      43.7303 -79.2930, 43.7299 -79.2928, 43.7286 -79.2986)))
{
   "crosses": [
      {"property": "road"},
      {
         "type": "Polygon",
         "coordinates": [
            [43.7286,-79.2986], [43.7311,-79.2996], [43.7323,-79.2972],
            [43.7326,-79.2971], [43.7350,-79.2981], [43.7350,-79.2982],
            [43.7352,-79.2982], [43.7357,-79.2956], [43.7337,-79.2948],
            [43.7343,-79.2933], [43.7339,-79.2923], [43.7327,-79.2947],
            [43.7320,-79.2942], [43.7322,-79.2937], [43.7306,-79.2930],
            [43.7303,-79.2930], [43.7299,-79.2928], [43.7286,-79.2986]
         ]
      }
   ]
}
Example 14. Example of a spatial relationship between a property and a function that return a geometry value.

It should be noted that the function "Buffer()" in this example is not part of CQL but is an example of a function that an implementation may offer that returns a geometry value.

WITHIN(road,Buffer(geometry,10,"m"))
{
   "within": [{"property": "road"},
              {"function": {"name":"Buffer",
                            "arguments": [{"property": "geometry"},10,"m"]}}
   ]
}

9.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

Requirements Class "Simple CQL"

The Simple CQL clause specifies the use of the ANYINTERACTS temporal operator. This requirements class adds additional commonly used temporal operators that an implementation of this extension might offer.

Requirement 25

/req/enhanced-temporal-operators

A

The server SHALL support all temporal operators as defined by the BNF rule temporalOperator in CQL BNF.

B

The spatial operators in addition to ANYINTERACTS SHALL be evaluated as defined in the Time Ontology in OWL with the following mapping between CQL temporal operator names and the property names defined in the Time Ontology in OWL:

CQL supports date and timestamps as time instants, but even the smallest "instant" has a duration and can also be evaluated as an interval. For the purposes of determining the temporal relationship between two temporal expressions, an instant is treated as the interval from the beginning to the end of the instant. The following diagram illustrates the meaning of the temporal operators.

TemporalOps
Figure 5. The elementary relations between time intervals
Example 15. Examples of temporal relationships using temporal literals.
    1969-07-20T20:17:40Z DURING 1969-07-16T13:32:00Z/1969-07-24T16:50:35Z
{
   "during": ["1969-07-20T20:17:40Z",["1969-07-16T13:32:00Z",
                                      "1969-07-24T16:50:35Z"]]
}
Example 16. Examples of temporal relationships using a property and a temporal literal.
    touchdown DURING 1969-07-16T13:32:00Z/1969-07-24T16:50:35Z
{
   "during": [{"property": "touchdown"},["1969-07-16T13:32:00Z",
                                         "1969-07-24T16:50:35Z"]]
}

9.4. Requirements Class "Functions"

Requirements Class

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

Target type

Web API

Dependency

Requirements Class "Simple CQL"

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

Requirement 26

/req/functions/functions

A

The server SHALL support functions as defined by the BNF rules function in CQL BNF with the exception of the rule arithmeticExpression in argument.

B

The function SHALL evaluate to a literal value that is allowed in the same rule in which the function is used.

Note
Support for the BNF rule arithmeticExpression is added by the requirements class Arithmetic Expressions.

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

Requirement 27

/req/functions/get-functions-operation

A

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

Requirement 28

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

A

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

B

The content of that response SHALL be based upon the following OpenAPI 3.0 schema and list all functions that the server supports:

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: uri-reference
        arguments:
          type: array
          items:
            type: object
            required:
            - type
            properties:
              title:
                type: string
              description:
                type: string
              type:
                type: array
                items:
                  type: string
                  enum:
                  - string
                  - number
                  - integer
                  - datetime
                  - geometry
                  - boolean
        returns:
          type: array
          items:
            type: string
            enum:
            - string
            - number
            - integer
            - datetime
            - geometry
            - boolean
Example 17. 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"]
      }
   ]
}

9.5. Requirements Class "Arithmetic Expressions"

Requirements Class

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

Target type

Web API

Dependency

Requirements Class "Simple CQL"

This clause specifies requirements for supporting arithmetic expressions in CQL. An arithmetic 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 29

/req/arithmetic/arithmetic

A

The server SHALL support arithmetic expressions as defined by the BNF rules arithmeticExpression in CQL BNF with the exception of the rule function in arithmeticOperand.

Note
Support for the BNF rule function is added by the requirements class Functions.
Example 18. Predicate with an arithmetic expression finding all vehicles that are too tall to pass under a bridge.
vehicle_height > (bridge_height-1)
{
   "gt": [{"property":"vehicle_height"},{"-":[{"property":"bridge_height"},1]}]
}

9.6. Requirements class "Arrays"

Requirements Class

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

Target type

Web API

Dependency

Requirements Class "Simple CQL"

This clause specifies requirements for supporting array expression in CQL. Array expressions can be tested in a predicate for equality, if one array is a subset of another, if one array is a superset of another or if two arrays overlap or share elements.

Requirement 30

/req/arrays/array-predicate

A

The server SHALL support arrays as defined by the BNF rule arrayPredicate in CQL BNF with the exception of the following rules:

  • function in arrayExpression, arrayElement

  • arithmeticExpression and function in arrayElement.

B

Both array expressions SHALL be evaluated as sets. No inherent order SHALL be implied in a array of values.

C

The semantics of the array operators SHALL be evaluated as follows:

  • AEQUALS evaluates to the Boolean value TRUE, if both sets are identical; otherwise the predicate SHALL evaluate to the Boolean value FALSE.

  • ACONTAINS evaluates to the Boolean value TRUE, if the first set is a superset of the second set; otherwise the predicate SHALL evaluate to the Boolean value FALSE.

  • CONTAINED BY evaluates to the Boolean value TRUE, if the first set is a subset of the second set; otherwise the predicate SHALL evaluate to the Boolean value FALSE.

  • AOVERLAPS evaluates to the Boolean value TRUE, if both sets share at least one common element; otherwise the predicate SHALL evaluate to the Boolean value FALSE.

Note
Support for the BNF rule function is added by the requirements class Functions. Support for the BNF rule arithmeticExpression is added by the requirements class Arithmetic Expressions.
Example 19. Evalute if the value of an array property contains the specified subset of values.
layer:ids ACONTAINS ["layers-ca","layers-us"]
{
   "acontains": [{"property": "layer:ids"},["layers-ca","layers-us"]]
}

10. Requirements classes for encodings

10.1. Overview

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

10.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

Requirements Class "Simple CQL"

Conditional Dependency

Requirements Class "Enhanced Spatial Operators"

Conditional Dependency

Requirements Class "Enhanced Temporal Operators"

Conditional Dependency

Requirements Class "Functions"

Conditional Dependency

Requirements Class "Arithmetic Expressions"

Conditional Dependency

Requirements Class "Arrays"

Conditional Dependency

Requirements Class "Filter"

This requirements class defines a Well Known Text (WKT) encoding of CQL. Such an encoding would be suitable for use with the GET query parameter such as the filter parameter.

The "CQL Text" encoding is defined by the BNF grammar defined in CQL BNF.

Keywords in the BNF grammar are case-insensitive. Augmented BNF for Syntax Specifications states:

ABNF strings are case insensitive and the character set for these strings is US-ASCII.

The list of CQL keywords includes:

  • "ACONTAINS"

  • "AEQUALS"

  • "AFTER"

  • "AND"

  • "ANYINTERACTS"

  • "AOVERLAPS"

  • "B"

  • "BEFORE"

  • "BEGINS"

  • "BEGUNBY"

  • "BETWEEN"

  • "CONTAINED BY"

  • "CONTAINS"

  • "CROSSES"

  • "DISJOINT"

  • "DURING"

  • "E"

  • "ENDEDBY"

  • "ENDS"

  • "ENVELOPE"

  • "EQUALS"

  • "F"

  • "FALSE"

  • "GEOMETRYCOLLECTION"

  • "IN"

  • "INTERSECTS"

  • "LIKE"

  • "LINESTRING"

  • "MEETS"

  • "METBY"

  • "MULTILINESTRING"

  • "MULTIPOINT"

  • "MULTIPOLYGON"

  • "NOCASE"

  • "NOT"

  • "NULL";

  • "OR"

  • "OVERLAPPEDBY"

  • "OVERLAPS"

  • "POINT"

  • "POLYGON"

  • "T"

  • "TCONTAINS"

  • "TEQUALS"

  • "TOUCHES"

  • "TOVERLAPS"

  • "TRUE"

  • "WITHIN"

  • "X"

  • "Z"

Requirement 31

/req/cql-text/filter-lang

Condition

Server implements requirements class Filter

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.

Requirement 32

/req/cql-text/simple-cql

A

The server SHALL be able to parse and evaluate all filter expressions encoded as a text string that validate against the BNF rules identified in the Simple CQL requirements class.

Requirement 33

/req/cql-text/enhanced-spatial-operators

Condition

Server implements requirements class Enhanced Spatial Operators

A

The server SHALL be able to parse and evaluate all spatial operators encoded as a text string that validate against the BNF production fragment identified in the Enhanced Spatial Operators requirement.

Requirement 34

/req/cql-text/temporal-operators

Condition

Server implements requirements class Enhanced Temporal Operators

A

The server SHALL be able to parse and evaluate all spatial operators encoded as a text string that validate against the BNF production fragment identified in the Enhanced Temporal Operators requirement.

Requirement 35

/req/cql-text/functions

Condition

Server implements requirements class Functions

A

The server SHALL be able to parse and evaluate all function call expressions encoded as a text string that validate against the BNF production fragment identified in the Functions requirement.

The list of supported functions can be discovered via the Functions resource (i.e. path /functions).

Requirement 36

/req/cql-text/arithmetic

Condition

Server implements requirements class Arithmetic Expressions

A

The server SHALL be able to parse and evaluate all arithmetic expressions encoded as a text string that validate against the BNF production fragment identified in the Arithmetic Expressions requirement.

Requirement 37

/req/cql-text/arrays

Condition

Server implements requirements class Arrays

A

The server SHALL be able to parse and evaluate all array expressions encoded as a text string that validate against the BNF production fragment identified in the Array Expressions requirement.

10.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

Requirements Class "Simple CQL"

Conditional Dependency

Requirements Class "Enhanced Spatial Operators"

Conditional Dependency

Requirements Class "Enhanced Temporal Operators"

Conditional Dependency

Requirements Class "Functions"

Conditional Dependency

Requirements Class "Arithmetic Expressions"

Conditional Dependency

Requirements Class "Arrays"

Conditional Dependency

Requirements Class "Filter"

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

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 OGC API - Features Standards Working Group will review both encodings and decide which one to adopt. Feedback from implementers is welcome.

Requirement 38

/req/cql-json/filter-lang

Condition

Server implements requirements class Filter

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 39

/req/cql-json/simple-cql

A

The server SHALL be able to parse and evaluate all filter expressions encoded as JSON that validate against the JSON Schema in JSON Schema for CQL and that do not use the following schema components:

  • "#/$defs/functionRef"

  • "#/$defs/arithmeticExpression"

  • "#/$defs/arrayPredicate"

  • "#/$defs/equalsExpression"

  • "#/$defs/disjointExpression"

  • "#/$defs/touchesExpression"

  • "#/$defs/withinExpression"

  • "#/$defs/overlapsExpression"

  • "#/$defs/crossesExpression"

  • "#/$defs/containsExpression"

  • "#/$defs/beforeExpression"

  • "#/$defs/afterExpression"

  • "#/$defs/meetsExpression"

  • "#/$defs/metbyExpression"

  • "#/$defs/toverlapsExpression"

  • "#/$defs/overlappedbyExpression"

  • "#/$defs/beginsExpression"

  • "#/$defs/begunbyExpression"

  • "#/$defs/duringExpression"

  • "#/$defs/tcontainsExpression"

  • "#/$defs/endsExpression"

  • "#/$defs/endedbyExpression"

  • "#/$defs/tequalsExpression"

Requirement 40

/req/cql-json/enhanced-spatial-operators

Condition

Server implements requirements class Enhanced Spatial Operators

A

In addition to the Simple CQL requirement, the server SHALL be able to parse and evaluate filter expressions encoded as JSON that use the following schema components:

  • "#/$defs/equalsExpression"

  • "#/$defs/disjointExpression"

  • "#/$defs/touchesExpression"

  • "#/$defs/withinExpression"

  • "#/$defs/overlapsExpression"

  • "#/$defs/crossesExpression"

  • "#/$defs/containsExpression"

Requirement 41

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

Condition

Server implements requirements class Enhanced Temporal Operators

A

In addition to the Simple CQL requirement, the server SHALL be able to parse and evaluate filter expressions encoded as JSON that use the following schema components:

  • "#/$defs/beforeExpression"

  • "#/$defs/afterExpression"

  • "#/$defs/meetsExpression"

  • "#/$defs/metbyExpression"

  • "#/$defs/toverlapsExpression"

  • "#/$defs/overlappedbyExpression"

  • "#/$defs/beginsExpression"

  • "#/$defs/begunbyExpression"

  • "#/$defs/duringExpression"

  • "#/$defs/tcontainsExpression"

  • "#/$defs/endsExpression"

  • "#/$defs/endedbyExpression"

  • "#/$defs/tequalsExpression"

Requirement 42

/req/cql-json/functions

Condition

Server implements requirements class Functions

A

In addition to the Simple CQL requirement, the server SHALL be able to parse and evaluate filter expressions encoded as JSON that use the following schema component:

  • "#/$defs/functionRef"

The list of supported functions can be discovered via the Functions resource (i.e. path /functions).

Requirement 43

/req/cql-json/arithmetic

Condition

Server implements requirements class Arithmetic Expressions

A

In addition to the Simple CQL requirement, the server SHALL be able to parse and evaluate filter expressions encoded as JSON that use the following schema component:

  • "#/$defs/arithmeticExpression"

Requirement 44

/req/cql-json/arrays

Condition

Server implements requirements class Arrays

A

In addition to the Simple CQL requirement, the server SHALL be able to parse and evaluate filter expressions encoded as JSON that use the following schema component:

  • "#/$defs/arrayPredicate"

10.4. XML encoding

This OGC API - Features - Part 3 standard does not specifically define an XML-encoding for CQL. However, it is recognized that XML is still in common use and so implementers are directed to review the OGC Filter Encoding 2.0 standard which defines a XML-encoding for filter expressions that closely matches most of the functionality of CQL.

11. Media Types

Note
Currently, there have not been plans to register media types for the CQL encodings. The reason is the assumption that filter expressions as such will rarely be used as requests or responses, but usually be part of a request or response and be embedded in it. If you have use cases where a CQL media type would be important, please consider adding a comment in this GitHub issue.

12. Security Considerations

Annex A: Abstract Test Suite (Normative)

Note
Add conformance classes and test cases for all requirements classes and requirements once the requirements are final.

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
# 22-NOV-2020  pvretano[at]cubewerx.com               Updates based on issues
# 22-NOV-2020  portele[at]interactive-instruments.de  Document restructuring
# 21-DEC-2020  pvretano[at]cubewerx.com               Updates to resolve issues

#=============================================================================#
# A CQL filter is a logically connected expression of one or more predicates.
# Predicates include scalar or comparison predicates, spatial predicates or
# temporal predicates.
#=============================================================================#
booleanValueExpression = andExpression
                       | orExpression
                       | notExpression
                       | comparisonPredicate
                       | spatialPredicate
                       | temporalPredicate
                       | arrayPredicate
                       | subExpression;

andExpression = booleanValueExpression "AND" booleanValueExpression;

orExpression = booleanValueExpression "OR" booleanValueExpression;

notExpression = "NOT" booleanValueExpression;

subExpression = leftParen booleanValueExpression rightParen;

#=============================================================================#
# A comparison predicate evaluates if two scalar expression statisfy the
# specified comparison operator.  The comparion operators includes an operator
# to evaluate pattern matching expressions (LIKE), a range evaluation operator
# and an operator to test if a scalar expression is NULL or not.
#=============================================================================#
comparisonPredicate = binaryComparisonPredicate
                    | isLikePredicate
                    | isBetweenPredicate
                    | isInListPredicate
                    | isNullPredicate;

# Binary comparison predicate
#
binaryComparisonPredicate = scalarExpression
                            comparisonOperator
                            scalarExpression;

scalarExpression = characterLiteral
                 | numericLiteral
                 | booleanLiteral
                 | propertyName
                 | function
                 | arithmeticExpression;

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

neq = lt gt;

gteq = gt eq;

lteq = lt eq;

# LIKE predicate
#
isLikePredicate =  scalarExpression "LIKE" patternExpression
                   ["WILDCARD" quote alpha quote]
                   ["SINGLECHAR" quote alpha quote]
                   ["ESCAPECHAR" quote alpha quote]
                   ["NOCASE" booleanLiteral] ;

patternExpression = characterLiteral;

# BETWEEN predicate
#
isBetweenPredicate = numericExpression ["NOT"] "BETWEEN"
                     numericExpression "AND" numericExpression;

numericExpression = numericLiteral
                  | propertyName
                  | function
                  | arithmeticExpression;

# IN LIST predicate
#
isInListPredicate = inListOperand ["NOT"] "IN" leftParen inList rightParen;

inList = inListOperand [ {comma inListOperand} ];

inListOperand = scalarExpression
              | temporalLiteral
              | spatialLiteral;

# IS NULL predicate
#
isNullPredicate = scalarExpression "IS" ["NOT"] "NULL";

#=============================================================================#
# 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 = "INTERSECTS"
                | "EQUALS"
                | "DISJOINT"
                | "TOUCHES"
                | "WITHIN"
                | "OVERLAPS"
                | "CROSSES"
                | "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 = spatialLiteral
               | propertyName
               | function;

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

temporalExpression = temporalLiteral
                   | propertyName
                   | function;

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

#=============================================================================#
# An array predicate evaluates if two array expressions statisfy the
# specified comparison operator.  The comparion operators include equality,
# not equal, less than, greater than, less than or equal, greater than or equal,
# superset, subset and overlap operators.
#=============================================================================#
arrayPredicate = arrayExpression arrayOperator arrayExpression;

# An array expression is a bracket-delimited, comma-separated list of array
# elements.  An array element is either a character literal, a numeric literal,
# a geometric literal, a temporal literal, a property name, a function, an
# arithmetic expression or an array.
#
arrayExpression = propertyName | function | arrayLiteral;

arrayLiteral = leftBracket rightBracket
             | leftBracket arrayElement [ { comma arrayElement } ] rightBracket;

arrayElement = characterLiteral
             | numericLiteral
             | booleanLiteral
             | spatialLiteral
             | temporalLiteral
             | propertyName
             | function
             | arithmeticExpression
             | arrayLiteral;

arrayOperator = "AEQUALS"
              | "ACONTAINS"
              | "CONTAINED BY"
              | "AOVERLAPS";

#=============================================================================#
# 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
                     | leftParen arithmeticExpression rightParen;

arithmeticOperator = plusSign | minusSign | asterisk | solidus;

arithmeticOperand = numericLiteral
                  | propertyName
                  | function;

#=============================================================================#
# Definition of a PROPERTYNAME
#=============================================================================#
propertyName = identifier;

identifier = identifierStart [ {colon | period | identifierPart} ]
           | doubleQuote identifier doubleQuote;

identifierStart = alpha;

identifierPart = alpha | digit | dollar | underscore;

#=============================================================================#
# Definition of a FUNCTION
# The functions offered by an implementation are provided at `/functions`
#=============================================================================#
function = identifier leftParen {argumentList} rightParen;

argumentList = argument [ { comma argument } ];

argument = characterLiteral
         | numericLiteral
         | booleanLiteral
         | spatialLiteral
         | temporalLiteral
         | propertyName
         | function
         | arithmeticExpression
         | arrayExpression;

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

characterStringLiteral = quote [ {character} ] quote;

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

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

character = alpha | digit | extendedDigit | ideographic |
            combiningChar | extender;

# alpha, digit, extendedDigit, ideographic, combiningChar and extender
# productions copied from https://www.w3.org/TR/REC-xml/#CharClasses
#
alpha = "\x0041".."\x005A" | "\x0061".."\x007A" | "\x00C0".."\x00D6" |
        "\x00D8".."\x00F6" | "\x00F8".."\x00FF" | "\x0100".."\x0131" |
        "\x0134".."\x013E" | "\x0141".."\x0148" | "\x014A".."\x017E" |
        "\x0180".."\x01C3" | "\x01CD".."\x01F0" | "\x01F4".."\x01F5" |
        "\x01FA".."\x0217" | "\x0250".."\x02A8" | "\x02BB".."\x02C1" |
        "\x0386"           | "\x0388".."\x038A" | "\x038C"           |
        "\x038E".."\x03A1" | "\x03A3".."\x03CE" | "\x03D0".."\x03D6" |
        "\x03DA"           | "\x03DC"           | "\x03DE"           |
        "\x03E0"           | "\x03E2".."\x03F3" | "\x0401".."\x040C" |
        "\x040E".."\x044F" | "\x0451".."\x045C" | "\x045E".."\x0481" |
        "\x0490".."\x04C4" | "\x04C7".."\x04C8" | "\x04CB".."\x04CC" |
        "\x04D0".."\x04EB" | "\x04EE".."\x04F5" | "\x04F8".."\x04F9" |
        "\x0531".."\x0556" | "\x0559"           | "\x0561".."\x0586" |
        "\x05D0".."\x05EA" | "\x05F0".."\x05F2" | "\x0621".."\x063A" |
        "\x0641".."\x064A" | "\x0671".."\x06B7" | "\x06BA".."\x06BE" |
        "\x06C0".."\x06CE" | "\x06D0".."\x06D3" | "\x06D5"           |
        "\x06E5".."\x06E6" | "\x0905".."\x0939" | "\x093D"           |
        "\x0958".."\x0961" | "\x0985".."\x098C" | "\x098F".."\x0990" |
        "\x0993".."\x09A8" | "\x09AA".."\x09B0" | "\x09B2"           |
        "\x09B6".."\x09B9" | "\x09DC".."\x09DD" | "\x09DF".."\x09E1" |
        "\x09F0".."\x09F1" | "\x0A05".."\x0A0A" | "\x0A0F".."\x0A10" |
        "\x0A13".."\x0A28" | "\x0A2A".."\x0A30" | "\x0A32".."\x0A33" |
        "\x0A35".."\x0A36" | "\x0A38".."\x0A39" | "\x0A59".."\x0A5C" |
        "\x0A5E"           | "\x0A72".."\x0A74" | "\x0A85".."\x0A8B" |
        "\x0A8D"           | "\x0A8F".."\x0A91" | "\x0A93".."\x0AA8" |
        "\x0AAA".."\x0AB0" | "\x0AB2".."\x0AB3" | "\x0AB5".."\x0AB9" |
        "\x0ABD"           | "\x0AE0"           | "\x0B05".."\x0B0C" |
        "\x0B0F".."\x0B10" | "\x0B13".."\x0B28" | "\x0B2A".."\x0B30" |
        "\x0B32".."\x0B33" | "\x0B36".."\x0B39" | "\x0B3D"           |
        "\x0B5C".."\x0B5D" | "\x0B5F".."\x0B61" | "\x0B85".."\x0B8A" |
        "\x0B8E".."\x0B90" | "\x0B92".."\x0B95" | "\x0B99".."\x0B9A" |
        "\x0B9C"           | "\x0B9E".."\x0B9F" | "\x0BA3".."\x0BA4" |
        "\x0BA8".."\x0BAA" | "\x0BAE".."\x0BB5" | "\x0BB7".."\x0BB9" |
        "\x0C05".."\x0C0C" | "\x0C0E".."\x0C10" | "\x0C12".."\x0C28" |
        "\x0C2A".."\x0C33" | "\x0C35".."\x0C39" | "\x0C60".."\x0C61" |
        "\x0C85".."\x0C8C" | "\x0C8E".."\x0C90" | "\x0C92".."\x0CA8" |
        "\x0CAA".."\x0CB3" | "\x0CB5".."\x0CB9" | "\x0CDE"           |
        "\x0CE0".."\x0CE1" | "\x0D05".."\x0D0C" | "\x0D0E".."\x0D10" |
        "\x0D12".."\x0D28" | "\x0D2A".."\x0D39" | "\x0D60".."\x0D61" |
        "\x0E01".."\x0E2E" | "\x0E30"           | "\x0E32".."\x0E33" |
        "\x0E40".."\x0E45" | "\x0E81".."\x0E82" | "\x0E84"           |
        "\x0E87".."\x0E88" | "\x0E8A"           | "\x0E8D"           |
        "\x0E94".."\x0E97" | "\x0E99".."\x0E9F" | "\x0EA1".."\x0EA3" |
        "\x0EA5"           | "\x0EA7"           | "\x0EAA".."\x0EAB" |
        "\x0EAD".."\x0EAE" | "\x0EB0"           | "\x0EB2".."\x0EB3" |
        "\x0EBD"           | "\x0EC0".."\x0EC4" | "\x0F40".."\x0F47" |
        "\x0F49".."\x0F69" | "\x10A0".."\x10C5" | "\x10D0".."\x10F6" |
        "\x1100"           | "\x1102".."\x1103" | "\x1105".."\x1107" |
        "\x1109"           | "\x110B".."\x110C" | "\x110E".."\x1112" |
        "\x113C"           | "\x113E"           | "\x1140"           |
        "\x114C"           | "\x114E"           | "\x1150"           |
        "\x1154".."\x1155" | "\x1159"           | "\x115F".."\x1161" |
        "\x1163"           | "\x1165"           | "\x1167"           |
        "\x1169"           | "\x116D".."\x116E" | "\x1172".."\x1173" |
        "\x1175"           | "\x119E"           | "\x11A8"           |
        "\x11AB"           | "\x11AE".."\x11AF" | "\x11B7".."\x11B8" |
        "\x11BA"           | "\x11BC".."\x11C2" | "\x11EB"           |
        "\x11F0"           | "\x11F9"           | "\x1E00".."\x1E9B" |
        "\x1EA0".."\x1EF9" | "\x1F00".."\x1F15" | "\x1F18".."\x1F1D" |
        "\x1F20".."\x1F45" | "\x1F48".."\x1F4D" | "\x1F50".."\x1F57" |
        "\x1F59"           | "\x1F5B"           | "\x1F5D"           |
        "\x1F5F".."\x1F7D" | "\x1F80".."\x1FB4" | "\x1FB6".."\x1FBC" |
        "\x1FBE"           | "\x1FC2".."\x1FC4" | "\x1FC6".."\x1FCC" |
        "\x1FD0".."\x1FD3" | "\x1FD6".."\x1FDB" | "\x1FE0".."\x1FEC" |
        "\x1FF2".."\x1FF4" | "\x1FF6".."\x1FFC" | "\x2126"           |
        "\x212A".."\x212B" | "\x212E"           | "\x2180".."\x2182" |
        "\x3041".."\x3094" | "\x30A1".."\x30FA" | "\x3105".."\x312C" |
        "\xAC00".."\xD7A3";

digit = "\x0030".."\x0039";

ideographic = "\x4E00".."\x9FA5" | "\x3007" | "\x3021".."\x3029";

combiningChar = "\x0300".."\x0345" | "\x0360".."\x0361" | "\x0483".."\x0486" |
                "\x0591".."\x05A1" | "\x05A3".."\x05B9" | "\x05BB".."\x05BD" |
                "\x05BF"           | "\x05C1".."\x05C2" | "\x05C4"           |
                "\x064B".."\x0652" | "\x0670"           | "\x06D6".."\x06DC" |
                "\x06DD".."\x06DF" | "\x06E0".."\x06E4" | "\x06E7".."\x06E8" |
                "\x06EA".."\x06ED" | "\x0901".."\x0903" | "\x093C"           |
                "\x093E".."\x094C" | "\x094D"           | "\x0951".."\x0954" |
                "\x0962".."\x0963" | "\x0981".."\x0983" | "\x09BC"           |
                "\x09BE"           | "\x09BF"           | "\x09C0".."\x09C4" |
                "\x09C7".."\x09C8" | "\x09CB".."\x09CD" | "\x09D7"           |
                "\x09E2".."\x09E3" | "\x0A02"           | "\x0A3C"           |
                "\x0A3E"           | "\x0A3F"           | "\x0A40".."\x0A42" |
                "\x0A47".."\x0A48" | "\x0A4B".."\x0A4D" | "\x0A70".."\x0A71" |
                "\x0A81".."\x0A83" | "\x0ABC"           | "\x0ABE".."\x0AC5" |
                "\x0AC7".."\x0AC9" | "\x0ACB".."\x0ACD" | "\x0B01".."\x0B03" |
                "\x0B3C"           | "\x0B3E".."\x0B43" | "\x0B47".."\x0B48" |
                "\x0B4B".."\x0B4D" | "\x0B56".."\x0B57" | "\x0B82".."\x0B83" |
                "\x0BBE".."\x0BC2" | "\x0BC6".."\x0BC8" | "\x0BCA".."\x0BCD" |
                "\x0BD7"           | "\x0C01".."\x0C03" | "\x0C3E".."\x0C44" |
                "\x0C46".."\x0C48" | "\x0C4A".."\x0C4D" | "\x0C55".."\x0C56" |
                "\x0C82".."\x0C83" | "\x0CBE".."\x0CC4" | "\x0CC6".."\x0CC8" |
                "\x0CCA".."\x0CCD" | "\x0CD5".."\x0CD6" | "\x0D02".."\x0D03" |
                "\x0D3E".."\x0D43" | "\x0D46".."\x0D48" | "\x0D4A".."\x0D4D" |
                "\x0D57"           | "\x0E31"           | "\x0E34".."\x0E3A" |
                "\x0E47".."\x0E4E" | "\x0EB1"           | "\x0EB4".."\x0EB9" |
                "\x0EBB".."\x0EBC" | "\x0EC8".."\x0ECD" | "\x0F18".."\x0F19" |
                "\x0F35"           | "\x0F37"           | "\x0F39"           |
                "\x0F3E"           | "\x0F3F"           | "\x0F71".."\x0F84" |
                "\x0F86".."\x0F8B" | "\x0F90".."\x0F95" | "\x0F97"           |
                "\x0F99".."\x0FAD" | "\x0FB1".."\x0FB7" | "\x0FB9"           |
                "\x20D0".."\x20DC" | "\x20E1"           | "\x302A".."\x302F" |
                "\x3099"           | "\x309A";

extendedDigit = "\x0660".."\x0669" | "\x06F0".."\x06F9" | "\x0966".."\x096F" |
                "\x09E6".."\x09EF" | "\x0A66".."\x0A6F" | "\x0AE6".."\x0AEF" |
                "\x0B66".."\x0B6F" | "\x0BE7".."\x0BEF" | "\x0C66".."\x0C6F" |
                "\x0CE6".."\x0CEF" | "\x0D66".."\x0D6F" | "\x0E50".."\x0E59" |
                "\x0ED0".."\x0ED9" | "\x0F20".."\x0F29";

extender =      "\x00B7"           | "\x02D0"           | "\x02D1"           |
                "\x0387"           | "\x0640"           | "\x0E46"           |
                "\x0EC6"           | "\x3005"           | "\x3031".."\x3035" |
                "\x309D".."\x309E" | "\x30FC".."\x30FE";

dollar = "$";

underscore = "_";

doubleQuote = "\"";

quote = "'";

leftBracket = "[";

rightBracket = "]";

leftParen = "(";

rightParen = ")";

asterisk = "*";

plusSign = "+";

comma = ",";

minusSign = "-";

period = ".";

dotdot = "..";

solidus = "/";

colon = ":";

lt = "<";

eq = "=";

gt = ">";

bit = "0" | "1";

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

#=============================================================================#
# 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;

#=============================================================================#
# Boolean literal
#=============================================================================#
#
booleanLiteral = "TRUE" | "true" | "FALSE" | "false" |
                 "T" | "t" | "F" | "f" | "1" | "0";

#=============================================================================#
# 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.
#=============================================================================#
spatialLiteral = 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
                         spatialLiteral {comma spatialLiteral} rightParen;

envelopeTaggedText = "ENVELOPE" envelopeText;

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

westBoundLon = signedNumericLiteral;

eastBoundLon = signedNumericLiteral;

northBoundLat = signedNumericLiteral;

southBoundLat = signedNumericLiteral;

minElev = signedNumericLiteral;

maxElev = signedNumericLiteral;

#=============================================================================#
# 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 [[colon] timeMinute];

timeHour   = digit digit;

timeMinute = digit digit;

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

Annex C: JSON schemas for CQL (Normative)

C.1. JSON Schema for CQL

The following document specifies the schema for CQL according to JSON Schema version '2019-09':

{
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "type": "object",
   "oneOf": [
      {"$ref": "#/$defs/andExpression"},
      {"$ref": "#/$defs/orExpression"},
      {"$ref": "#/$defs/notExpression"},
      {"$ref": "#/$defs/comparisonPredicate"},
      {"$ref": "#/$defs/spatialPredicate"},
      {"$ref": "#/$defs/temporalPredicate"},
      {"$ref": "#/$defs/arrayPredicate"}
   ],
   "$recursiveAnchor": true,
   "$defs": {
      "$comment": "=======================================================",
      "$comment": "=  BOOLEAN VALUE EXPRESSION                           =",
      "$comment": "=======================================================",

      "andExpression": {
         "type": "object",
         "required": ["and"],
         "properties": {
            "and": {
               "type": "array",
               "minItems": 2,
               "items": {
                  "$recursiveRef": "#"
               }
            }
         }
      },

      "orExpression": {
         "type": "object",
         "required": ["or"],
         "properties": {
            "or": {
               "type": "array",
               "minItems": 2,
               "items": {
                  "$recursiveRef": "#"
               }
            }
         }
      },

      "notExpression": {
         "type": "object",
         "required": ["not"],
         "properties": {
            "not": {
               "type": "array",
               "minItems": 1,
               "maxItems": 1,
               "items": {
                  "$recursiveRef": "#"
               }
            }
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  COMPARISON PREDICATES                              =",
      "$comment": "=======================================================",

      "comparisonPredicate" : {
         "oneOf": [
            {"$ref": "#/$defs/binaryComparisonPredicate"},
            {"$ref": "#/$defs/isLikePredicate" },
            {"$ref": "#/$defs/isBetweenPredicate"},
            {"$ref": "#/$defs/isInListPredicate" },
            {"$ref": "#/$defs/isNullPredicate" }
         ]
      },

      "binaryComparisonPredicate": {
         "oneOf": [
            { "$ref": "#/$defs/eqExpression" },
            { "$ref": "#/$defs/ltExpression" },
            { "$ref": "#/$defs/gtExpression" },
            { "$ref": "#/$defs/lteExpression" },
            { "$ref": "#/$defs/gteExpression" }
         ]
      },

      "eqExpression": {
         "type": "object",
         "required": ["eq"],
         "properties": {
            "eq": { "$ref": "#/$defs/scalarOperands" }
         }
      },

      "ltExpression": {
         "type": "object",
           "required": ["lt"],
           "properties": {
              "lt": { "$ref": "#/$defs/scalarOperands" }
         }
      },

      "gtExpression": {
         "type": "object",
         "required": ["gt"],
         "properties": {
            "gt": { "$ref": "#/$defs/scalarOperands" }
         }
      },

      "lteExpression": {
         "type": "object",
         "required": ["lte"],
         "properties": {
            "lte": { "$ref": "#/$defs/scalarOperands" }
         }
      },

      "gteExpression": {
         "type": "object",
         "required": ["gte"],
         "properties": {
            "gte": { "$ref": "#/$defs/scalarOperands" }
         }
      },

      "isBetweenPredicate": {
         "type": "object",
         "required": ["between"],
         "properties": {
            "between": {
               "type": "object",
               "required" : [ "value", "lower", "upper" ],
               "properties": {
                  "value": { "$ref": "#/$defs/valueExpression" },
                  "lower": { "$ref": "#/$defs/scalarExpression" },
                  "upper": { "$ref": "#/$defs/scalarExpression" }
               }
            }
         }
      },

      "isLikePredicate": {
         "type": "object",
         "required": ["like"],
         "properties": {
            "like": { "$ref": "#/$defs/scalarOperands" },
            "wildcard": { "type": "string", "default": "%" },
            "singleChar": { "type": "string", "default": "." },
            "escapeChar": { "type": "string", "default": "\\" },
            "nocase": { "type": "boolean", "default": true }
         }
      },

      "isInListPredicate": {
         "type": "object",
         "required": ["in"],
         "properties": {
            "in": {
               "type": "object",
               "required": ["value","list"],
               "properties": {
                  "value": { "$ref": "#/$defs/valueExpression" },
                  "list": {
                     "type": "array",
                     "items": {
                        "$ref": "#/$defs/valueExpression"
                     }
                  },
                  "nocase": {
                     "type": "boolean",
                     "default": true
                  }
               }
            }
         }
      },

      "valueExpression": {
         "oneOf": [
            {"$ref": "#/$defs/scalarExpression"},
            {"$ref": "#/$defs/spatialLiteral"},
            {"$ref": "#/$defs/typedTemporalLiteral"}
         ]
      },

      "scalarOperands": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "$ref": "#/$defs/scalarExpression"
         }
      },

      "scalarExpression": {
         "oneOf": [
            {"$ref": "#/$defs/scalarLiteral"},
            {"$ref": "#/$defs/propertyRef"},
            {"$ref": "#/$defs/functionRef"},
            {"$ref": "#/$defs/arithmeticExpression"}
         ]
      },

      "isNullPredicate": {
         "type": "object",
         "required": [ "isNull" ],
         "properties": {
            "isNull": {
               "$ref": "#/$defs/scalarExpression"
            }
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  SPATIAL PREDICATES                                 =",
      "$comment": "=======================================================",

      "spatialPredicate" : {
         "oneOf": [
           {"$ref": "#/$defs/intersectsExpression"},
           {"$ref": "#/$defs/equalsExpression"},
           {"$ref": "#/$defs/disjointExpression"},
           {"$ref": "#/$defs/touchesExpression"},
           {"$ref": "#/$defs/withinExpression"},
           {"$ref": "#/$defs/overlapsExpression"},
           {"$ref": "#/$defs/crossesExpression"},
           {"$ref": "#/$defs/containsExpression"}
         ]
      },

      "intersectsExpression": {
         "type": "object",
         "required": ["intersects"],
         "properties": {
            "intersects": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "equalsExpression": {
         "type": "object",
         "required": ["equals"],
         "properties": {
            "equals": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "disjointExpression": {
         "type": "object",
         "required": ["disjoint"],
         "properties": {
            "disjoint": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "touchesExpression": {
         "type": "object",
         "required": ["touches"],
         "properties": {
            "touches": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "withinExpression": {
         "type": "object",
         "required": ["within"],
         "properties": {
            "within": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "overlapsExpression": {
         "type": "object",
         "required": ["overlaps"],
         "properties": {
            "overlaps": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "crossesExpression": {
         "type": "object",
         "required": ["crosses"],
         "properties": {
            "crosses": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "containsExpression": {
         "type": "object",
         "required": ["contains"],
         "properties": {
            "contains": { "$ref": "#/$defs/spatialOperands" }
         }
      },

      "spatialOperands": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "$ref": "#/$defs/geomExpression"
         }
      },

      "geomExpression": {
         "oneOf": [
            {"$ref": "#/$defs/spatialLiteral"},
            {"$ref": "#/$defs/propertyRef"},
            {"$ref": "#/$defs/functionRef"}
         ]
      },

      "$comment": "=======================================================",
      "$comment": "=  TEMPORAL EXPRESSIONS                               =",
      "$comment": "=======================================================",

      "temporalPredicate" : {
         "oneOf": [
           {"$ref": "#/$defs/beforeExpression"},
           {"$ref": "#/$defs/afterExpression"},
           {"$ref": "#/$defs/meetsExpression"},
           {"$ref": "#/$defs/metbyExpression"},
           {"$ref": "#/$defs/toverlapsExpression"},
           {"$ref": "#/$defs/overlappedbyExpression"},
           {"$ref": "#/$defs/beginsExpression"},
           {"$ref": "#/$defs/begunbyExpression"},
           {"$ref": "#/$defs/duringExpression"},
           {"$ref": "#/$defs/tcontainsExpression"},
           {"$ref": "#/$defs/endsExpression"},
           {"$ref": "#/$defs/endedbyExpression"},
           {"$ref": "#/$defs/tequalsExpression"},
           {"$ref": "#/$defs/anyinteractsExpression"}
         ]
      },

      "beforeExpression": {
         "type": "object",
         "required": ["before"],
         "properties": {
            "before": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "afterExpression": {
         "type": "object",
         "required": ["after"],
         "properties": {
            "after": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "meetsExpression": {
         "type": "object",
         "required": ["meets"],
         "properties": {
            "meets": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "metbyExpression": {
         "type": "object",
         "required": ["metby"],
         "properties": {
            "metby": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "toverlapsExpression": {
         "type": "object",
         "required": ["toverlaps"],
         "properties": {
            "toverlaps": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "overlappedbyExpression": {
         "type": "object",
         "required": ["overlappedby"],
         "properties": {
            "overlappedby": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "beginsExpression": {
         "type": "object",
         "required": ["begins"],
         "properties": {
            "begins": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "begunbyExpression": {
         "type": "object",
         "required": ["begunby"],
         "properties": {
            "begunby": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "duringExpression": {
         "type": "object",
         "required": ["during"],
         "properties": {
            "during": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "tcontainsExpression": {
         "type": "object",
         "required": ["tcontains"],
         "properties": {
            "tcontains": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "endsExpression": {
         "type": "object",
         "required": ["ends"],
         "properties": {
            "ends": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "endedbyExpression": {
         "type": "object",
         "required": ["endedby"],
         "properties": {
            "endedby": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "tequalsExpression": {
         "type": "object",
         "required": ["tequals"],
         "properties": {
            "tequals": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "anyinteractsExpression": {
         "type": "object",
         "required": ["anyinteracts"],
         "properties": {
            "anyinteracts": { "$ref": "#/$defs/temporalOperands" }
         }
      },

      "temporalOperands": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "$ref": "#/$defs/temporalExpression"
         }
      },

      "temporalExpression": {
         "oneOf": [
            {"$ref": "#/$defs/temporalLiteral"},
            {"$ref": "#/$defs/propertyRef"},
            {"$ref": "#/$defs/functionRef"}
         ]
      },

      "$comment": "=======================================================",
      "$comment": "=  ARRAY PREDICATE                                    =",
      "$comment": "=======================================================",

      "arrayPredicate" : {
         "oneOf": [
            {"$ref": "#/$defs/aequalsExpression"},
            {"$ref": "#/$defs/acontainsExpression"},
            {"$ref": "#/$defs/acontainedByExpression"},
            {"$ref": "#/$defs/aoverlapsExpression"}
         ]
      },

      "aequalsExpression": {
         "type": "object",
         "required": ["aequals"],
         "properties": {
            "aequals": { "$ref": "#/$defs/arrayExpression" }
         }
      },

      "acontainsExpression": {
         "type": "object",
         "required": ["acontains"],
         "properties": {
            "acontains": { "$ref": "#/$defs/arrayExpression" }
         }
      },

      "acontainedByExpression": {
         "type": "object",
         "required": ["acontainedBy"],
         "properties": {
            "acontainedBy": { "$ref": "#/$defs/arrayExpression" }
         }
      },

      "aoverlapsExpression": {
         "type": "object",
         "required": ["aoverlaps"],
         "properties": {
            "aoverlaps": { "$ref": "#/$defs/arrayExpression" }
         }
      },

      "arrayExpression": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "oneOf": [
               { "$ref": "#/$defs/propertyRef" },
               { "$ref": "#/$defs/functionRef" },
               { "$ref": "#/$defs/arrayLiteral" }
            ]
         }
      },

      "arrayLiteral": {
         "type": "array",
         "items": {
            "oneOf": [
               {"$ref": "#/$defs/scalarLiteral"},
               {"$ref": "#/$defs/spatialLiteral"},
               {"$ref": "#/$defs/typedTemporalLiteral"},
               { "$ref": "#/$defs/propertyRef" },
               { "$ref": "#/$defs/functionRef" },
               {"$ref": "#/$defs/arithmeticExpression"},
               { "$ref": "#/$defs/arrayLiteral" }
            ]
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  ARITHMETIC EXPRESSIONS                             =",
      "$comment": "=======================================================",

      "arithmeticExpression": {
         "oneOf": [
            {"$ref": "#/$defs/addExpression" },
            {"$ref": "#/$defs/subExpression" },
            {"$ref": "#/$defs/mulExpression" },
            {"$ref": "#/$defs/divExpression" }
         ]
      },

      "addExpression": {
         "type": "object",
         "required": ["+"],
         "properties": {
            "+": { "$ref": "#/$defs/arithmeticOperands" }
         }
      },

      "subExpression": {
         "type": "object",
         "required": ["-"],
         "properties": {
            "-": { "$ref": "#/$defs/arithmeticOperands" }
         }
      },

      "mulExpression": {
         "type": "object",
         "required": ["*"],
         "properties": {
            "*": { "$ref": "#/$defs/arithmeticOperands" }
         }
      },

      "divExpression": {
         "type": "object",
         "required": ["*"],
         "properties": {
            "/": { "$ref": "#/$defs/arithmeticOperands" }
         }
      },

      "arithmeticOperands": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "oneOf": [
               {"$ref": "#/$defs/arithmeticExpression"},
               {"$ref": "#/$defs/propertyRef"},
               {"$ref": "#/$defs/functionRef"},
               {"type": "number" }
            ]
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  PROPERTY REFERENCE                                 =",
      "$comment": "=======================================================",
      "propertyRef": {
         "type": "object",
         "required": ["property"],
         "properties": {
            "propertyName": { "type": "string" }
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  FUNCTIONS                                          =",
      "$comment": "=======================================================",

      "functionRef": {
         "type": "object",
         "required": ["function"],
         "properties": {
            "function": { "$ref": "#/$defs/function" }
         }
      },

      "function": {
         "type": "object",
         "required": [ "name" ],
         "properties": {
            "name": { "type": "string" },
            "arguments": {
               "type": "array",
               "items": {
                  "oneOf": [
                     { "$ref": "#/$defs/scalarLiteral" },
                     { "$ref": "#/$defs/spatialLiteral" },
                     { "$ref": "#/$defs/typedTemporalLiteral" },
                     { "$ref": "#/$defs/propertyRef" },
                     { "$ref": "#/$defs/functionRef" },
                     { "$ref": "#/$defs/arithmeticExpression" },
                     { "$ref": "#/$defs/arrayLiteral" }
                  ]
               }
            }
         }
      },

      "$comment": "=======================================================",
      "$comment": "=  LITERALS                                           =",
      "$comment": "=======================================================",

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

      "spatialLiteral": {
         "oneOf": [
            { "$ref": "#/$defs/geometryLiteral" },
            { "$ref": "#/$defs/envelopeLiteral" }
         ]
      },

      "geometryLiteral": {
         "oneOf": [
            { "$ref": "#/$defs/point" },
            { "$ref": "#/$defs/linestring" },
            { "$ref": "#/$defs/polygon" },
            { "$ref": "#/$defs/multipoint" },
            { "$ref": "#/$defs/multilinestring" },
            { "$ref": "#/$defs/multipolygon" }
         ]
      },

      "point": {
         "title": "GeoJSON Point",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["Point"]
            },
            "coordinates": {
               "type": "array",
               "minItems": 2,
               "items": {
                  "type": "number"
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "linestring": {
         "title": "GeoJSON LineString",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["LineString"]
            },
            "coordinates": {
               "type": "array",
               "minItems": 2,
               "items": {
                  "type": "array",
                  "minItems": 2,
                  "items": {
                     "type": "number"
                  }
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "polygon": {
         "title": "GeoJSON Polygon",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["Polygon"]
            },
            "coordinates": {
               "type": "array",
               "items": {
                  "type": "array",
                  "minItems": 4,
                  "items": {
                     "type": "array",
                     "minItems": 2,
                     "items": {
                        "type": "number"
                     }
                  }
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "multipoint": {
         "title": "GeoJSON MultiPoint",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["MultiPoint"]
            },
            "coordinates": {
               "type": "array",
               "items": {
                  "type": "array",
                  "minItems": 2,
                  "items": {
                     "type": "number"
                  }
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "multilinestring": {
         "title": "GeoJSON MultiLineString",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["MultiLineString"]
            },
            "coordinates": {
               "type": "array",
               "items": {
                  "type": "array",
                  "minItems": 2,
                  "items": {
                     "type": "array",
                     "minItems": 2,
                     "items": {
                        "type": "number"
                     }
                  }
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "multipolygon": {
         "title": "GeoJSON MultiPolygon",
         "type": "object",
         "required": ["type","coordinates"],
         "properties": {
            "type": {
               "type": "string",
               "enum": ["MultiPolygon"]
            },
            "coordinates": {
               "type": "array",
               "items": {
                  "type": "array",
                  "items": {
                     "type": "array",
                     "minItems": 4,
                     "items": {
                        "type": "array",
                        "minItems": 2,
                        "items": {
                           "type": "number"
                        }
                     }
                  }
               }
            },
            "bbox": {
               "type": "array",
               "minItems": 4,
               "items": {
                  "type": "number"
               }
            }
         }
      },

      "envelopeLiteral": {
         "type": "object",
         "required": [ "bbox" ],
         "properties": {
            "bbox": { "$ref": "#/$defs/bbox" }
         }
      },

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

      "temporalLiteral": {
         "oneOf": [
            { "$ref": "#/$defs/timeString" },
            { "$ref": "#/$defs/periodString" }
         ]
      },

      "timeString": {
         "oneOf": [
            { "type": "string", "format": "date" },
            { "type": "string", "format": "date-time" }
         ]
      },

      "periodString": {
         "type": "array",
         "minItems": 2,
         "maxItems": 2,
         "items": {
            "oneOf": [
               { "$ref": "#/$defs/timeString" },
               { "type": "string", "enum": [".."] }
            ]
         }
      },

      "typedTemporalLiteral": {
         "oneOf": [
            { "$ref": "#/$defs/typedTimeString" },
            { "$ref": "#/$defs/typedPeriodString" }
         ]
      },

      "typedTimeString": {
         "type": "object",
         "required": ["datetime"],
         "properties": {
            "datetime": {
               "$ref": "#/$defs/timeString"
            }
         }
      },

      "typedPeriodString": {
         "type": "object",
         "required": ["datetime"],
         "properties": {
            "datetime": {
               "$ref": "#/$defs/periodString"
            }
         }
      }
   }
}

C.2. OpenAPI 3.0 schema for CQL

The following document specifies the schema for CQL as an OpenAPI 3.0 schema in YAML:

---
openapi: 3.0.3
info:
  title: Schema of Common Query Language (CQL)
  description: 'For use in OpenAPI 3.0 documents'
  version: '1.0.0-draft.1'
paths: {}
components:
  schemas:
    booleanValueExpression:
      type: object
      oneOf:
      - "$ref": "#/components/schemas/andExpression"
      - "$ref": "#/components/schemas/orExpression"
      - "$ref": "#/components/schemas/notExpression"
      - "$ref": "#/components/schemas/comparisonPredicate"
      - "$ref": "#/components/schemas/spatialPredicate"
      - "$ref": "#/components/schemas/temporalPredicate"
      - "$ref": "#/components/schemas/arrayPredicate"
    andExpression:
      type: object
      required:
      - and
      properties:
        and:
          type: array
          minItems: 2
          items:
            "$ref": "#/components/schemas/booleanValueExpression"
    orExpression:
      type: object
      required:
      - or
      properties:
        or:
          type: array
          minItems: 2
          items:
            "$ref": "#/components/schemas/booleanValueExpression"
    notExpression:
      type: object
      required:
      - not
      properties:
        not:
          type: array
          minItems: 1
          maxItems: 1
          items:
            "$ref": "#/components/schemas/booleanValueExpression"
    comparisonPredicate:
      oneOf:
      - "$ref": "#/components/schemas/binaryComparisonPredicate"
      - "$ref": "#/components/schemas/isLikePredicate"
      - "$ref": "#/components/schemas/isBetweenPredicate"
      - "$ref": "#/components/schemas/isInListPredicate"
      - "$ref": "#/components/schemas/isNullPredicate"
    binaryComparisonPredicate:
      oneOf:
      - "$ref": "#/components/schemas/eqExpression"
      - "$ref": "#/components/schemas/ltExpression"
      - "$ref": "#/components/schemas/gtExpression"
      - "$ref": "#/components/schemas/lteExpression"
      - "$ref": "#/components/schemas/gteExpression"
    eqExpression:
      type: object
      required:
      - eq
      properties:
        eq:
          "$ref": "#/components/schemas/scalarOperands"
    ltExpression:
      type: object
      required:
      - lt
      properties:
        lt:
          "$ref": "#/components/schemas/scalarOperands"
    gtExpression:
      type: object
      required:
      - gt
      properties:
        gt:
          "$ref": "#/components/schemas/scalarOperands"
    lteExpression:
      type: object
      required:
      - lte
      properties:
        lte:
          "$ref": "#/components/schemas/scalarOperands"
    gteExpression:
      type: object
      required:
      - gte
      properties:
        gte:
          "$ref": "#/components/schemas/scalarOperands"
    isBetweenPredicate:
      type: object
      required:
      - between
      properties:
        between:
          type: object
          required:
          - value
          - lower
          - upper
          properties:
            value:
              "$ref": "#/components/schemas/valueExpression"
            lower:
              "$ref": "#/components/schemas/scalarExpression"
            upper:
              "$ref": "#/components/schemas/scalarExpression"
    isLikePredicate:
      type: object
      required:
      - like
      properties:
        like:
          "$ref": "#/components/schemas/scalarOperands"
        wildcard:
           type: string
           default: "%"
        singleChar:
           type: string
           default: "."
        escapeChar:
           type: string
           default: "\\"
        nocase:
          type: boolean
          default: true
    isInListPredicate:
      type: object
      required:
      - in
      properties:
        in:
          type: object
          required:
          - value
          - list
          properties:
            value:
              "$ref": "#/components/schemas/valueExpression"
            list:
              type: array
              items:
                "$ref": "#/components/schemas/valueExpression"
            nocase:
              type: boolean
              default: true
    valueExpression:
      oneOf:
      - "$ref": "#/components/schemas/scalarExpression"
      - "$ref": "#/components/schemas/spatialLiteral"
      - "$ref": "#/components/schemas/typedTemporalLiteral"
    scalarOperands:
      type: array
      minItems: 2
      maxItems: 2
      items:
        "$ref": "#/components/schemas/scalarExpression"
    scalarExpression:
      oneOf:
      - "$ref": "#/components/schemas/scalarLiteral"
      - "$ref": "#/components/schemas/propertyRef"
      - "$ref": "#/components/schemas/functionRef"
      - "$ref": "#/components/schemas/arithmeticExpression"
    isNullPredicate:
      type: object
      required:
      - isNull
      properties:
        isNull:
          "$ref": "#/components/schemas/scalarExpression"
    spatialPredicate:
      oneOf:
      - "$ref": "#/components/schemas/intersectsExpression"
      - "$ref": "#/components/schemas/equalsExpression"
      - "$ref": "#/components/schemas/disjointExpression"
      - "$ref": "#/components/schemas/touchesExpression"
      - "$ref": "#/components/schemas/withinExpression"
      - "$ref": "#/components/schemas/overlapsExpression"
      - "$ref": "#/components/schemas/crossesExpression"
      - "$ref": "#/components/schemas/containsExpression"
    intersectsExpression:
      type: object
      required:
      - intersects
      properties:
        intersects:
          "$ref": "#/components/schemas/spatialOperands"
    equalsExpression:
      type: object
      required:
      - equals
      properties:
        equals:
          "$ref": "#/components/schemas/spatialOperands"
    disjointExpression:
      type: object
      required:
      - disjoint
      properties:
        disjoint:
          "$ref": "#/components/schemas/spatialOperands"
    touchesExpression:
      type: object
      required:
      - touches
      properties:
        touches:
          "$ref": "#/components/schemas/spatialOperands"
    withinExpression:
      type: object
      required:
      - within
      properties:
        within:
          "$ref": "#/components/schemas/spatialOperands"
    overlapsExpression:
      type: object
      required:
      - overlaps
      properties:
        overlaps:
          "$ref": "#/components/schemas/spatialOperands"
    crossesExpression:
      type: object
      required:
      - crosses
      properties:
        crosses:
          "$ref": "#/components/schemas/spatialOperands"
    containsExpression:
      type: object
      required:
      - contains
      properties:
        contains:
          "$ref": "#/components/schemas/spatialOperands"
    spatialOperands:
      type: array
      minItems: 2
      maxItems: 2
      items:
        "$ref": "#/components/schemas/geomExpression"
    geomExpression:
      oneOf:
      - "$ref": "#/components/schemas/spatialLiteral"
      - "$ref": "#/components/schemas/propertyRef"
      - "$ref": "#/components/schemas/functionRef"
    temporalPredicate:
      oneOf:
      - "$ref": "#/components/schemas/beforeExpression"
      - "$ref": "#/components/schemas/afterExpression"
      - "$ref": "#/components/schemas/meetsExpression"
      - "$ref": "#/components/schemas/metbyExpression"
      - "$ref": "#/components/schemas/toverlapsExpression"
      - "$ref": "#/components/schemas/overlappedbyExpression"
      - "$ref": "#/components/schemas/beginsExpression"
      - "$ref": "#/components/schemas/begunbyExpression"
      - "$ref": "#/components/schemas/duringExpression"
      - "$ref": "#/components/schemas/tcontainsExpression"
      - "$ref": "#/components/schemas/endsExpression"
      - "$ref": "#/components/schemas/endedbyExpression"
      - "$ref": "#/components/schemas/tequalsExpression"
      - "$ref": "#/components/schemas/anyinteractsExpression"
    beforeExpression:
      type: object
      required:
      - before
      properties:
        before:
          "$ref": "#/components/schemas/temporalOperands"
    afterExpression:
      type: object
      required:
      - after
      properties:
        after:
          "$ref": "#/components/schemas/temporalOperands"
    meetsExpression:
      type: object
      required:
      - meets
      properties:
        meets:
          "$ref": "#/components/schemas/temporalOperands"
    metbyExpression:
      type: object
      required:
      - metby
      properties:
        metby:
          "$ref": "#/components/schemas/temporalOperands"
    toverlapsExpression:
      type: object
      required:
      - toverlaps
      properties:
        toverlaps:
          "$ref": "#/components/schemas/temporalOperands"
    overlappedbyExpression:
      type: object
      required:
      - overlappedby
      properties:
        overlappedby:
          "$ref": "#/components/schemas/temporalOperands"
    beginsExpression:
      type: object
      required:
      - begins
      properties:
        begins:
          "$ref": "#/components/schemas/temporalOperands"
    begunbyExpression:
      type: object
      required:
      - begunby
      properties:
        begunby:
          "$ref": "#/components/schemas/temporalOperands"
    duringExpression:
      type: object
      required:
      - during
      properties:
        during:
          "$ref": "#/components/schemas/temporalOperands"
    tcontainsExpression:
      type: object
      required:
      - tcontains
      properties:
        tcontains:
          "$ref": "#/components/schemas/temporalOperands"
    endsExpression:
      type: object
      required:
      - ends
      properties:
        ends:
          "$ref": "#/components/schemas/temporalOperands"
    endedbyExpression:
      type: object
      required:
      - endedby
      properties:
        endedby:
          "$ref": "#/components/schemas/temporalOperands"
    tequalsExpression:
      type: object
      required:
      - tequals
      properties:
        tequals:
          "$ref": "#/components/schemas/temporalOperands"
    anyinteractsExpression:
      type: object
      required:
      - anyinteracts
      properties:
        anyinteracts:
          "$ref": "#/components/schemas/temporalOperands"
    temporalOperands:
      type: array
      minItems: 2
      maxItems: 2
      items:
        "$ref": "#/components/schemas/temporalExpression"
    temporalExpression:
      oneOf:
      - "$ref": "#/components/schemas/temporalLiteral"
      - "$ref": "#/components/schemas/propertyRef"
      - "$ref": "#/components/schemas/functionRef"
    arrayPredicate:
      oneOf:
      - "$ref": "#/components/schemas/aequalsExpression"
      - "$ref": "#/components/schemas/acontainsExpression"
      - "$ref": "#/components/schemas/acontainedByExpression"
      - "$ref": "#/components/schemas/aoverlapsExpression"
    aequalsExpression:
      type: object
      required:
      - aequals
      properties:
        aequals:
          "$ref": "#/components/schemas/arrayExpression"
    acontainsExpression:
      type: object
      required:
      - acontains
      properties:
        acontains:
          "$ref": "#/components/schemas/arrayExpression"
    acontainedByExpression:
      type: object
      required:
      - acontainedBy
      properties:
        acontainedBy:
          "$ref": "#/components/schemas/arrayExpression"
    aoverlapsExpression:
      type: object
      required:
      - aoverlaps
      properties:
        aoverlaps:
          "$ref": "#/components/schemas/arrayExpression"
    arrayExpression:
      type: array
      minItems: 2
      maxItems: 2
      items:
        oneOf:
        - "$ref": "#/components/schemas/propertyRef"
        - "$ref": "#/components/schemas/functionRef"
        - "$ref": "#/components/schemas/arrayLiteral"
    arrayLiteral:
      type: array
      items:
        oneOf:
        - "$ref": "#/components/schemas/scalarLiteral"
        - "$ref": "#/components/schemas/spatialLiteral"
        - "$ref": "#/components/schemas/typedTemporalLiteral"
        - "$ref": "#/components/schemas/propertyRef"
        - "$ref": "#/components/schemas/functionRef"
        - "$ref": "#/components/schemas/arithmeticExpression"
        - "$ref": "#/components/schemas/arrayLiteral"
    arithmeticExpression:
      oneOf:
      - "$ref": "#/components/schemas/addExpression"
      - "$ref": "#/components/schemas/subExpression"
      - "$ref": "#/components/schemas/mulExpression"
      - "$ref": "#/components/schemas/divExpression"
    addExpression:
      type: object
      required:
      - "+"
      properties:
        "+":
          "$ref": "#/components/schemas/arithmeticOperands"
    subExpression:
      type: object
      required:
      - "-"
      properties:
        "-":
          "$ref": "#/components/schemas/arithmeticOperands"
    mulExpression:
      type: object
      required:
      - "*"
      properties:
        "*":
          "$ref": "#/components/schemas/arithmeticOperands"
    divExpression:
      type: object
      required:
      - "/"
      properties:
        "/":
          "$ref": "#/components/schemas/arithmeticOperands"
    arithmeticOperands:
      type: array
      minItems: 2
      maxItems: 2
      items:
        oneOf:
        - "$ref": "#/components/schemas/arithmeticExpression"
        - "$ref": "#/components/schemas/propertyRef"
        - "$ref": "#/components/schemas/functionRef"
        - type: number
    propertyRef:
      type: object
      required:
      - property
      properties:
        propertyName:
          type: string
    functionRef:
      type: object
      required:
      - function
      properties:
        function:
          "$ref": "#/components/schemas/function"
    function:
      type: object
      required:
      - name
      properties:
        name:
          type: string
        arguments:
          type: array
          items:
            oneOf:
            - "$ref": "#/components/schemas/scalarLiteral"
            - "$ref": "#/components/schemas/spatialLiteral"
            - "$ref": "#/components/schemas/typedTemporalLiteral"