Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: defining out-of-band order for lists #2323

Open
mielvds opened this issue Nov 22, 2024 · 6 comments
Open

Proposal: defining out-of-band order for lists #2323

mielvds opened this issue Nov 22, 2024 · 6 comments

Comments

@mielvds
Copy link

mielvds commented Nov 22, 2024

This proposal is a follow-up from a discussion in #994. The order in which items are listed, but also presented by viewers, depends on the order of the JSON array. For example, pages of a book as a list of canvases in this manifest:

{
  // Metadata about this manifest file
  "@context": "http://iiif.io/api/presentation/3/context.json",
  "id": "https://example.org/iiif/book1/manifest",
  "type": "Manifest",
  // ...
  // List of Canvases
  "items": [
    {
      "id": "https://example.org/iiif/book1/canvas/p1",
      "type": "Canvas",
      "label": { "none": [ "p. 1" ] }
      // ...
    },
    {
      "id": "https://example.org/iiif/book1/canvas/p2",
      "type": "Canvas",
      "label": { "none": [ "p. 2" ] }
      // ...
    }
  ],
  // ...
}

The items array is typed @list is JSON-LD, which in turn, is an rdf:List data structure in RDF. When interpreting the JSON-LD serialized IIIF manifest in RDF all is fine. Unfortunately, in reverse - going from RDF to a JSON-LD serialized IIIF manifest - this requirement is a bit of a burden.

Creating a IIIF manifest from an RDF stack, which is what we (meemoo) happen to have, with SPARQL Construct + JSON-LD framing is actually quite elegant. But with one big caveat: creating an RDF list with SPARQL is extremely complex and cumbersome. Currently, we post-process our manifests and sort the arrays by code to make sure pages are presented in the right order, which is not ideal.

Granted of course, this is not an issue caused by the IIIF spec, but by the limitations of SPARQL. However, SPARQL is what it is and there might be other use cases unable to create ordered (RDF) lists directly (although I can't immediately think of any). Therefore, I'd like to discuss the possibility to add a complementary way of defining list order in the IIIF Presentation API 4.0 spec.

Proposal:

In short: add a way to define the order of list items outside of, but complementary to the existing array. If present, this definition of order would take preference over the array order. A rough example manifest (based on https://schema.org/ItemList) would look something like:

{
  // Metadata about this manifest file
  "@context": "http://iiif.io/api/presentation/3/context.json",
  "id": "https://example.org/iiif/book1/manifest",
  "type": "Manifest",
  // ...
  // Definition of order
  "ordering": { 
    "id": ...,
    "type": "ItemList",
    "itemListElement": [    //@set
	    { "id" ..., item:  "https://example.org/iiif/book1/content/p1/1", position: 1}
     ]
  },
  // List of Canvases
  "items": [ 
    {
      "id": "https://example.org/iiif/book1/canvas/p1",
      "type": "Canvas",
      "label": { "none": [ "p. 1" ] },
      "nextItem": "https://example.org/iiif/book1/canvas/p2", // optional
      // ...
    },
    {
      "id": "https://example.org/iiif/book1/canvas/p2",
      "type": "Canvas",
      "label": { "none": [ "p. 2" ] },
      "prevItem": "https://example.org/iiif/book1/canvas/p1", // optional
      // ...
    }
  ],
  // ...
}

Similar constructs are also used by ore:Proxy

I understand that this puts an extra burden on viewers, but it might be minimal. Happy to hear your thoughts on this and whether this was already discussed or would be considered for the next version. Thanks!

@DiegoPino
Copy link

@mielvds hi, any reason why the current structure(ranges) does not work for your needs as a way of defining your own order (different to the order of appearance under JSON/JSON-LD? see https://iiif.io/api/presentation/3.0/#54-range

@mielvds
Copy link
Author

mielvds commented Nov 26, 2024

Hi @DiegoPino! My bad, I've should have mentioned range. Our impression from https://iiif.io/api/presentation/3.0/#54-range was that it only dictates the order in the ToC/navigation, rather than fixing the actual order. But more importantly: it relies on the same list-typed items property to define order, no?

Our use case is actually straightforward: have all newspaper pages displayed in the correct order without having the server sort them. The range examples we could find were about highlighting or grouping certain ranges in a book like https://iiif.io/api/cookbook/recipe/0024-book-4-toc/, but nothing about reordering pages.

I probably missed something, and if so, this proposal can be easily dismissed as solved. in that case, though, I would suggest to make this part in the spec clearer and/or expand on the examples. Happy to contribute in that case!

@DiegoPino
Copy link

@mielvds my interpretation of the specs (re: the part I pasted underneath here): if a structure -> range with behavior sequence is present, the viewer should prefer that given order instead of the order of appearance of items. of course, if a viewer respect or not that is a different story. That would match your use case.

Range Behaviors
--
sequence | Valid only on Ranges, where the Range is referenced in the structures property of a Manifest. Ranges that have this behavior represent different orderings of the Canvases listed in the items property of the Manifest, and user interfaces that interact with this order should use the order within the selected Range, rather than the default order of items. Disjoint with thumbnail-nav and no-nav.

See even further in the specs

If there is no Range that has the behavior value sequence, and the Manifest does not have the behavior value unordered, then the client should treat the order of the Canvases in the Manifest’s items array as the default order.

Not sure what you mean with

it relies on the same list-typed items property to define order, no?

It does relay on the item id (it's a reference) but could also use annotations, etc, if one needed to use a totally different way of navigating (that would only make sense in a ToC situation of course)

@mielvds
Copy link
Author

mielvds commented Nov 26, 2024

@mielvds my interpretation of the specs (re: the part I pasted underneath here): if a structure -> range with behavior sequence is present, the viewer should prefer that given order instead of the order of appearance of items. of course, if a viewer respect or not that is a different story. That would match your use case.

Yep, it would!

Range Behaviors

sequence | Valid only on Ranges, where the Range is referenced in the structures property of a Manifest. Ranges that have this behavior represent different orderings of the Canvases listed in the items property of the Manifest, and user interfaces that interact with this order should use the order within the selected Range, rather than the default order of items. Disjoint with thumbnail-nav and no-nav.

See even further in the specs

If there is no Range that has the behavior value sequence, and the Manifest does not have the behavior value unordered, then the client should treat the order of the Canvases in the Manifest’s items array as the default order.

Not sure what you mean with

it relies on the same list-typed items property to define order, no?

It does relay on the item id (it's a reference) but could also use annotations, etc, if one needed to use a totally different way of navigating (that would only make sense in a ToC situation of course)

What I mean it that as long as a Range also relies on the order of a items array, the problem is the same because it's this ordered items array that is hard for us to produce.

Extending Range would be a good way to potentially implement this proposal, though. What you would need is the following:

  • the definition of a sorting attribute that you can add to the relayed item id; let's call thissortKey for now
  • a requirement for viewers to order the Canvases based on the value of sortKey if present.

Example manifest:

{
 // Metadata about this manifest file
 "@context": "http://iiif.io/api/presentation/3/context.json",
 "id": "https://example.org/iiif/book1/manifest",
 "type": "Manifest",
 // ...
 // List of Canvases - this would display page 2 before page 1
 "items": [
   {
     "id": "https://example.org/iiif/book1/canvas/p2",
     "type": "Canvas",
     "label": { "none": [ "p. 2" ] }
     // ...
   },
   {
     "id": "https://example.org/iiif/book1/canvas/p1",
     "type": "Canvas",
     "label": { "none": [ "p. 1" ] }
     // ...
   }
 ],
 // Range  - this makes sure page 1 is displayed before page 2
 "structures": [
     {
        "id": "https://example.org/iiif/book1/range/r1",
         "type": "Range",
         "label": { "en": [ "Order" ] },
         "items": [
           {
             "id": "https://example.org/iiif/book1/canvas/p2",
             "sortKey": 2,
             "type": "Canvas"
           },
           {
             "id": "https://example.org/iiif/book1/canvas/p1",
             "sortKey": 1,
             "type": "Canvas"
           }]
     }
 ]
}

@DiegoPino
Copy link

DiegoPino commented Nov 26, 2024

@mielvds as I said in slack, the computational effort of sorting an array you can produce already in this shape

"structures": [
     {
        "id": "https://example.org/iiif/book1/range/r1",
         "type": "Range",
         "label": { "en": [ "Order" ] },
         "items": [
           {
             "id": "https://example.org/iiif/book1/canvas/p2",
             "sortKey": 2,
             "type": "Canvas"
           },
           {
             "id": "https://example.org/iiif/book1/canvas/p1",
             "sortKey": 1,
             "type": "Canvas"
           }]
     }
 ]

Is truly minimal v/s changing a Community spec and then, if successful, deferring the sorting (someone needs to sort it anyways) back to the viewer instead (with the adoption/developer roadmap/times that it would entail). Not sure what programing language you are using for the final output, but it is really simple

Something (roughly )like this ?

TheCompareFunction( a, b ) {
  if ( a.sortKey < b.sortKey ){
    return -1;
  }
  if ( a.sortKey > b.sortKey ){
    return 1;
  }
  return 0;
}

and then structures[0].items.yourlangueSortingFunction( TheCompareFunction ); ?

If not I think you could maybe join one of the IIIF API editors calls and share your use case there, see how that goes. @glenrobson, what do you think?

@mielvds
Copy link
Author

mielvds commented Dec 2, 2024

@DiegoPino thanks for following up on my question/proposal. Sure, you can order the array, but that's not what I'm after here. Adding sort operation is an extra (hackish) step in our architecture, which is exactly what I'm trying to avoid.

What I'm proposing or asking is this: could we add (to the specification) a way for servers to push sorting items (e.g., Canvas) to the client in addition to the current server-only ordering.

The motivation is enabling backend architectures that are for any reason not able to easily sort lists, such as a SPARQL-based stack. Yes, this is not IIIF's problem and mostly a major limitation in SPARQL. But if IIIF can be more inclusive with minor changes, it's worth discussing it. That said, if there is little support base within the community, we can drop it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants