From faca4aaf349b9fdbd87b9463d62d138f86eb85ff Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Thu, 13 Jun 2024 12:18:55 -0400 Subject: [PATCH] 13-hierarchy: Fixes to reflect changes agreed to in #298 - NOTE: Using descendants=immediate rather than 'children' as this has clearer meaning --- .../clause_13_hierarchical_collections.adoc | 174 +++++++++--------- .../PER_descendants_default_html.adoc | 6 + .../hierarchy/PER_parent_default_html.adoc | 6 - .../hierarchy/REC_parent_convention.adoc | 7 - .../hierarchy/REQ_ancestor_parameter.adoc | 7 - .../hierarchy/REQ_descendants_parameter.adoc | 8 + .../hierarchy/REQ_parent_parameter.adoc | 6 +- .../hierarchy/REQ_parent_property.adoc | 1 - 8 files changed, 106 insertions(+), 109 deletions(-) create mode 100644 collections/recommendations/hierarchy/PER_descendants_default_html.adoc delete mode 100644 collections/recommendations/hierarchy/PER_parent_default_html.adoc delete mode 100644 collections/recommendations/hierarchy/REC_parent_convention.adoc delete mode 100644 collections/requirements/hierarchy/REQ_ancestor_parameter.adoc create mode 100644 collections/requirements/hierarchy/REQ_descendants_parameter.adoc diff --git a/collections/clause_13_hierarchical_collections.adoc b/collections/clause_13_hierarchical_collections.adoc index 88e3b596..8665dea8 100644 --- a/collections/clause_13_hierarchical_collections.adoc +++ b/collections/clause_13_hierarchical_collections.adoc @@ -11,7 +11,7 @@ This capability addresses two primary use cases: The hierarchical organization also allows to present the list of collections in a hierarchical manner, for example using a tree view control, and makes it easier to discover or browse to a particular collection of interest using such an interface, with the ability to expand and collapse branches of the hierarchy. For example, data collections may be organized as a hierarchy of countries, states, and cities. -- The `ancestor` parameter defined herein allows to load a limited subset of interest from the available collections. +- Loading a limited subset of interest from the available collections. In conjunction with the "Searchable Collections" and/or "Filtering collections using CQL2" requirement classes, this parameter also allows to narrow down a search to a particular branch of the hierarchy. NOTE: This requirement class does not address the use cases of defining simultaneous multiple hierarchies -- a collection can have a single `parent` collection. @@ -39,16 +39,14 @@ The property is omitted or set to a _null_ value for top-level collections. include::requirements/hierarchy/REQ_parent_property.adoc[] -Although not required, it is recommended that the identifier of children collections start by their parent collection identifier, -followed by a specific separator (such as the colon `:`), followed by their distinctive part. -Programmatic clients should not establish the hierarchical relationships based on the presence of that separator nor of the parent collecton identifier -within a collection identifier, but it is a useful hint for users, including to allow editing the URLs of a collection in a browser's address bar to directly access the parent collection. +Although not required, implementations could opt for using a specific character (such as the colon `:`) to separate the hierarchical parts of collection identifiers. +This notably facilitates directly accessing a parent collection in a browser environment by editing URLs in the browser address bar. -include::recommendations/hierarchy/REC_parent_convention.adoc[] +CAUTION: Clients cannot rely on the use of any particular separator character to establish the hierarchical relationships between collections. Instead, they need to use the `parent` property specifying the identifier of the parent collection when applicable. In the HTML representation of a collection description resource (`/collections/{collectionId}`), it can be useful to directly show the list of children collections, allowing a user to directly click and explore the hierarchy this way. -For programmatic clients, a separate `/collections?parent={parentId}` request is performed instead to retrieve the list of children collections (see below). +For programmatic clients wishing not to retrieve an entire hierarchy of collections, separate `/collections?parent={parentId}&descendants=immediate` requests are performed to retrieve the list of immediate children collections (see below). include::recommendations/hierarchy/PER_collection_children.adoc[] @@ -76,15 +74,15 @@ Example of a hierarchical collection listing response for `/collections`: { "id": "Canada", "links": [ - { "rel": "self", "href": "/collections/can" }, - { "rel": "[ogc-rel:map]", "href": "/collections/can/map" } + { "rel": "self", "href": "/collections/Canada" }, + { "rel": "[ogc-rel:map]", "href": "/collections/Canada/map" } ] }, { "id": "USA", "links": [ - { "rel": "self", "href": "/collections/usa" }, - { "rel": "[ogc-rel:map]", "href": "/collections/usa/map" } + { "rel": "self", "href": "/collections/USA" }, + { "rel": "[ogc-rel:map]", "href": "/collections/USA/map" } ] }, { @@ -165,12 +163,12 @@ Example of a hierarchical collection listing response for `/collections`: ] }, { - "id": "Summerhill", "parent": "NewYork", + "id": "Syracuse", "parent": "NewYork", "links": [ - { "rel": "self", "href": "/collections/Summerhill" }, - { "rel": "items", "href": "/collections/Summerhill/items" }, - { "rel": "[ogc-rel:map]", "href": "/collections/Summerhill/map" }, - { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Summerhill/tiles" } + { "rel": "self", "href": "/collections/Syracuse" }, + { "rel": "items", "href": "/collections/Syracuse/items" }, + { "rel": "[ogc-rel:map]", "href": "/collections/Syracuse/map" }, + { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Syracuse/tiles" } ] }, { @@ -198,43 +196,14 @@ Example of a hierarchical collection listing response for `/collections`: === `parent` query parameter for `/collections` -A `parent` query parameter is defined to filter the list of collections returned to only those whose immediate parent is identified by the specified parent id. +A `parent` query parameter is defined to filter the list of collections returned to only those within the hierarchy of a specified parent collection. -A special value of `none` (which must be avoided as a collection id) takes the special meaning of returning only the top-level collections without a parent. +Depending on the value of the `descendants` parameter, either the entire hierarchy underneath (`descendants=all`), or only the immediate children (`descendants=immediate`) of that parent are returned. +By default, all descendants of the specified parent, or all collections of the dataset if no parent is specified, are returned. include::requirements/hierarchy/REQ_parent_parameter.adoc[] -In order to allow implementations and deployments to present a list of collections in a hierarchical manner by default in a browser, -a permission specific to an HTML representation is introduced. -Since such an HTML representation is not primarily intended for consumption by programmatic clients, this should not impact compatibility with clients not implementing this extension. - -include::recommendations/hierarchy/PER_parent_default_html.adoc[] - -Example response, based on the hierarchical collections listed earlier, for `/collections?parent=none`: - -```json -{ - "collections": [ - { - "id": "Canada", - "links": [ - { "rel": "self", "href": "/collections/can" }, - { "rel": "[ogc-rel:map]", "href": "/collections/can/map" } - ] - }, - { - "id": "USA", - "links": [ - { "rel": "self", "href": "/collections/usa" }, - { "rel": "[ogc-rel:map]", "href": "/collections/usa/map" } - ] - } - ] - ... -} -``` - -Example response, based on the hierarchical collections listed earlier, for `/collections?parent=can`: +Example response, based on the hierarchical collections listed earlier, for `/collections?parent=Canada`: ```json { @@ -254,17 +223,7 @@ Example response, based on the hierarchical collections listed earlier, for `/co { "rel": "[ogc-rel:map]", "href": "/collections/Ontario/map" }, { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Ontario/tiles" } ] - } - ] - ... -} -``` - -Example response, based on the hierarchical collections listed earlier, for `/collections?parent=Quebec`: - -```json -{ - "collections": [ + }, { "id": "QuebecCity", "parent": "Quebec", "links": [ @@ -283,18 +242,62 @@ Example response, based on the hierarchical collections listed earlier, for `/co { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Montreal/tiles" } ] }, + { + "id": "Toronto", "parent": "Ontario", + "links": [ + { "rel": "self", "href": "/collections/Toronto" }, + { "rel": "items", "href": "/collections/Toronto/items" }, + { "rel": "[ogc-rel:map]", "href": "/collections/Toronto/map" }, + { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Toronto/tiles" } + ] + }, + { + "id": "Ottawa", "parent": "Ontario", + "links": [ + { "rel": "self", "href": "/collections/Ottawa" }, + { "rel": "items", "href": "/collections/Ottawa/items" }, + { "rel": "[ogc-rel:map]", "href": "/collections/Ottawa/map" }, + { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Ottawa/tiles" } + ] + } ] ... } ``` -=== `ancestor` query parameter for `/collections` -An `ancestor` query parameter is also defined to filter the list of collections returned to only those having parent identified by the specified parent id as an ancestor. +=== `descendants` query parameter for `/collections` + +A `descendants` query parameter is also defined to retrieve only the immediate children of a specified parent, or only the top-level collections, when using the value `immediate`. +The default value `all` returns all collections as usual, or the whole hierarchy under a parent if `parent` is specified. -include::requirements/hierarchy/REQ_ancestor_parameter.adoc[] +include::requirements/hierarchy/REQ_descendants_parameter.adoc[] -Example response, based on the hierarchical collections listed earlier, for `/collections?ancestor=can`: +Example response, based on the hierarchical collections listed earlier, retrieving only the top-level collections with `/collections?descendants=immediate`: + +```json +{ + "collections": [ + { + "id": "Canada", + "links": [ + { "rel": "self", "href": "/collections/Canada" }, + { "rel": "[ogc-rel:map]", "href": "/collections/Canada/map" } + ] + }, + { + "id": "USA", + "links": [ + { "rel": "self", "href": "/collections/USA" }, + { "rel": "[ogc-rel:map]", "href": "/collections/USA/map" } + ] + } + ] + ... +} +``` + +Example response, based on the hierarchical collections listed earlier, for retrieving only the immediate children of the `Canada` collection `/collections?parent=Canada&descendants=immediate`: ```json { @@ -314,7 +317,17 @@ Example response, based on the hierarchical collections listed earlier, for `/co { "rel": "[ogc-rel:map]", "href": "/collections/Ontario/map" }, { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Ontario/tiles" } ] - }, + } + ] + ... +} +``` + +Example response, based on the hierarchical collections listed earlier, for retrieving only the immediate children of the `Quebec` collection `/collections?parent=Quebec&descendants=immediate`: + +```json +{ + "collections": [ { "id": "QuebecCity", "parent": "Quebec", "links": [ @@ -333,32 +346,21 @@ Example response, based on the hierarchical collections listed earlier, for `/co { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Montreal/tiles" } ] }, - { - "id": "Toronto", "parent": "Ontario", - "links": [ - { "rel": "self", "href": "/collections/Toronto" }, - { "rel": "items", "href": "/collections/Toronto/items" }, - { "rel": "[ogc-rel:map]", "href": "/collections/Toronto/map" }, - { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Toronto/tiles" } - ] - }, - { - "id": "Ottawa", "parent": "Ontario", - "links": [ - { "rel": "self", "href": "/collections/Ottawa" }, - { "rel": "items", "href": "/collections/Ottawa/items" }, - { "rel": "[ogc-rel:map]", "href": "/collections/Ottawa/map" }, - { "rel": "[ogc-rel:tilesets-vector]", "href": "/collections/Ottawa/tiles" } - ] - } ] ... } ``` -The following example query demonstrates combining filtering by ancestor with capabilities defined in "Searchable Collections" to look for collections related to precipitations -in a hierarchy within the descendants of a collection with the identifier `canada`: +In order to allow implementations and deployments to present a list of collections in a hierarchical manner by default in a browser, +a permission specific to an HTML representation is introduced. +Since such an HTML representation is not primarily intended for consumption by programmatic clients, this should not impact compatibility with clients not implementing this extension. + +include::recommendations/hierarchy/PER_descendants_default_html.adoc[] + + +The following example query demonstrates combining filtering with a parent hierarchy (with default `descendants=all`) with capabilities defined in "Searchable Collections" to look for collections related to precipitations +in a hierarchy within the descendants of a collection with the identifier `Canada`: ``` -GET /collections?ancestor=Canada&q=precipitations +GET /collections?parent=Canada&q=precipitations ``` diff --git a/collections/recommendations/hierarchy/PER_descendants_default_html.adoc b/collections/recommendations/hierarchy/PER_descendants_default_html.adoc new file mode 100644 index 00000000..bcff890a --- /dev/null +++ b/collections/recommendations/hierarchy/PER_descendants_default_html.adoc @@ -0,0 +1,6 @@ +[[per_hierarchy_descendants-default-html]] +[width="90%",cols="2,6a"] +|=== +^|*Permission {counter:per-id}* |*/per/hierarchy/descendants-default-html* +^|A |For representations not intended primarily for consumption by machines, such as an HTML representation, an implementation MAY assume a default value of `immediate` for the `descendants` query parameter, so as to present the collections in a hierarchical manner and avoid an unnecessarily large response when a large number of collections are available. +|=== diff --git a/collections/recommendations/hierarchy/PER_parent_default_html.adoc b/collections/recommendations/hierarchy/PER_parent_default_html.adoc deleted file mode 100644 index ac1ed798..00000000 --- a/collections/recommendations/hierarchy/PER_parent_default_html.adoc +++ /dev/null @@ -1,6 +0,0 @@ -[[per_hierarchy_parent-default-html]] -[width="90%",cols="2,6a"] -|=== -^|*Permission {counter:per-id}* |*/per/hierarchy/parent-default-html* -^|A |For representations not intended primarily for consumption by machines, such as an HTML representation, an implementation MAY assume a default value of `none` for the `parent` query parameter, so as to present the collections in a hierarchical manner and avoid an unnecessarily large response when a large number of collections are available. -|=== diff --git a/collections/recommendations/hierarchy/REC_parent_convention.adoc b/collections/recommendations/hierarchy/REC_parent_convention.adoc deleted file mode 100644 index 06503c2b..00000000 --- a/collections/recommendations/hierarchy/REC_parent_convention.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[rec_hierarchy_parent-convention]] -[width="90%",cols="2,6a"] -|=== -^|*Recommendation {counter:rec-id}* |*/rec/hierarchy/parent-convention* -^|A |The identifiers for children collections SHOULD follow the pattern `{parentCollectionId}{separator}{distinctivePart}`. For example, the collection with identifier `can:qc:mtl` whose parent collection has the identifier `can:qc` follows this pattern. -^|B |The same single separator character (for example, a colon `:`) SHOULD be used for all collections throughout a Web API deployment. -|=== diff --git a/collections/requirements/hierarchy/REQ_ancestor_parameter.adoc b/collections/requirements/hierarchy/REQ_ancestor_parameter.adoc deleted file mode 100644 index 63653e60..00000000 --- a/collections/requirements/hierarchy/REQ_ancestor_parameter.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[req_hierarchy_ancestor-parameter]] -[width="90%",cols="2,6a"] -|=== -^|*Requirement {counter:req-id}* |*/req/hierarchy/ancestor-parameter* -^|A |The implementation SHALL support an `ancestor` query parameter for listing collections at the resource `/collections` whose string value represents a specified ancestor collection identifier. -^|B |The response for listing collections when this parameter is used SHALL only include collections whose immediate parent, or any ancestor from that parent up to the root of the hierarchy, corresponds to the specified collection identifier. -|=== diff --git a/collections/requirements/hierarchy/REQ_descendants_parameter.adoc b/collections/requirements/hierarchy/REQ_descendants_parameter.adoc new file mode 100644 index 00000000..ce2132f5 --- /dev/null +++ b/collections/requirements/hierarchy/REQ_descendants_parameter.adoc @@ -0,0 +1,8 @@ +[[req_hierarchy_descendants-parameter]] +[width="90%",cols="2,6a"] +|=== +^|*Requirement {counter:req-id}* |*/req/hierarchy/descendants-parameter* +^|A |The implementation SHALL support a `descendants` query parameter for listing collections at the resource `/collections` whose value can be either `immediate` or `all` (the default). +^|B |When the value of the `descendants` parameter is `immediate`, the list of collections returned SHALL only include immediate children of the collection specified in the `parent` query parameter if applicable, or otherwise only the top-level collections with no parent if no `parent` parameter is specified. +^|C |When the value of the `descendants` parameter is `all` or not provided, all collections of the hierarchy SHALL be returned, subject to any other filtering based on any other parameters such as `parent`. +|=== diff --git a/collections/requirements/hierarchy/REQ_parent_parameter.adoc b/collections/requirements/hierarchy/REQ_parent_parameter.adoc index 6735ac8b..ced57b6f 100644 --- a/collections/requirements/hierarchy/REQ_parent_parameter.adoc +++ b/collections/requirements/hierarchy/REQ_parent_parameter.adoc @@ -3,6 +3,8 @@ |=== ^|*Requirement {counter:req-id}* |*/req/hierarchy/parent-parameter* ^|A |The implementation SHALL support a `parent` query parameter for listing collections at the resource `/collections` whose string value represents a specified parent collection identifier. -^|B |The response for listing collections when this parameter is used SHALL only include collections whose immediate parent corresponds to the specified collection identifier. -^|C |When the special value of `none` is used for the `parent` parameter, only top-level collections without a parent SHALL be returned. +^|B |When this parameter is used, the response for listing collections SHALL only include collections under the hierarchy of the specified parent collection, starting with its immediate children (excluding the parent itself). +^|C |When the `parent` parameter is omitted, all collections SHALL be returned. |=== + +NOTE: The list of collections can be further filtered by the `descendants` parameter defined in this requirement class, or separate requirement classes such as Searchable Collection. diff --git a/collections/requirements/hierarchy/REQ_parent_property.adoc b/collections/requirements/hierarchy/REQ_parent_property.adoc index dee17f9d..a93e1191 100644 --- a/collections/requirements/hierarchy/REQ_parent_property.adoc +++ b/collections/requirements/hierarchy/REQ_parent_property.adoc @@ -4,5 +4,4 @@ ^|*Requirement {counter:req-id}* |*/req/hierarchy/parent-property* ^|A |For collections organized into a hierarchy which are not top-level collections, the collection object response for both listing collections (`/collections`) and for individual collection description (`/collections/{collectionId}`) SHALL include a `parent` property set to the collection identifier of the parent collection. ^|B |The `parent` property in collection objects for top-level collections SHALL be omitted or set to a null value. -^|C |Collection identifiers SHALL NOT use the reserved value of `none`. |===