NationalMuseumAustralia / Collection-API

The public web API of the National Museum of Australia
10 stars 0 forks source link

Finding relevant image versions #11

Open f27wood opened 6 years ago

f27wood commented 6 years ago

Finding the relevant image version can be complex. Notes from a developer wanting to find the preview image for certain objects follow.

I need to loop through each image and compare on the version string to find a match on “preview image”. Perhaps additional structure would be useful here in a future version, so each format associated with a version is a key in the array, eg: ■ hasVersion[][‘preview’] ■ hasVersion[][thumbnail’] ■ hasVersion[][large’]

For the example script (simple JSON) I am simply looking in the first item in the hasVersion array (which happens to be the Emu asset) and looking for a version that matches string “preview image”.

The linked-art version is more complex, I need to loop through an additional layer to compare the classified_as label against string “preview image”.

Conal-Tuohy commented 6 years ago

what is the 'example script' mentioned?

f27wood commented 6 years ago

I think they are:

Simple json: http://nma.conaltuohy.com/object/60250?format=simple Linked art: http://nma.conaltuohy.com/object/60250?format=json-ld

f27wood commented 6 years ago

BTW this was when testing scenario 1 in the testing scenarios.

TASK 1: Embed information about an object on a webpage

E.g: On the Flinders circumnavigates Australia Defining moments page at: http://www.nma.gov.au/online_features/defining_moments/featured/flinders-circumnavigates-aus tralia

Embed the object information relating to the object with irn of 60250. Include the: ● Title ● Preview image ● Description ● Statement of Significance ● A link to the object in Collection Explorer

stooit commented 6 years ago

Hi @Conal-Tuohy, basic sample script attached. You can see when looking for a preview image associated with an object it requires looping through each version of an image and matching on the classification label "preview image".

Not a big deal, just a little extra work when wanting to retrieve the associated preview image.

<?php

/**
 * @file
 * This sample file performs a lookup of an individual object by urn (id).
 * We retrieve this object in both simple and linked art formats and output:
 *   Title
 *   Preview image
 *   Description
 *   Statement of Significance
 *   A link to the object in Collection Explorer
 */

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7;

// Set the client base URI.
$client = new GuzzleHttp\Client(['base_uri' => 'http://nma.conaltuohy.com/']);

// Retrieve object using simple json schema.
try {
  $response = $client->request('GET', 'object/60250', [
    'query' => ['format' => 'simple']
  ]);
} catch (RequestException $e) {
  echo Psr7\str($e->getRequest());
  if ($e->hasResponse()) {
    echo Psr7\str($e->getResponse());
  }
}

// Get all of the response headers.
echo "<pre>";
echo "==== Simple JSON ====\n";
foreach ($response->getHeaders() as $name => $values) {
    echo $name . ': ' . implode(', ', $values) . "\r\n";
}

$data = json_decode($response->getBody());

// Check for valid json.
if ($data == null) {
  echo "Response could not be parsed as json. Exiting.";
  exit();
}

// Retrieve values for title, preview image, description, statement of significance and link to collection explorer.
echo "\nTitle: {$data->title}\n";

foreach ($data->hasVersion[0]->hasVersion as $image) {
  if ($image->version === "preview image") {
    echo "Preview image: {$image->identifier}\n";
  }
}

echo "Description:\n{$data->physicalDescription}\n\n";
echo "Statement of significance:\n{$data->significanceStatement}\n\n";

$collectionUrl = "http://collectionsearch.nma.gov.au/object/{$data->id}";
echo "Link to item in API explorer: {$collectionUrl}\n\n";
echo "</pre>";

echo "<h2>Simple web example</h2>";
echo "<h4>{$data->title}</h4>";

foreach ($data->hasVersion[0]->hasVersion as $image) {
  if ($image->version === "preview image") {
    echo "<img style='float:left' src='{$image->identifier}'>";
  }
}

echo "<p>{$data->physicalDescription}</p>";
echo "<p>{$data->significanceStatement}</p>";

$collectionUrl = "http://collectionsearch.nma.gov.au/object/{$data->id}";
echo "<a href='{$collectionurl}'>Link to object</a>";

/**
 * Linked-art schema.
 */
try {
  $response = $client->request('GET', 'object/60250', [
    'query' => ['format' => 'json-ld']
  ]);
} catch (RequestException $e) {
  echo Psr7\str($e->getRequest());
  if ($e->hasResponse()) {
    echo Psr7\str($e->getResponse());
  }
}
echo "<pre style='clear:both'>";
echo "==== Linked-art JSON ====\n";
foreach ($response->getHeaders() as $name => $values) {
    echo $name . ': ' . implode(', ', $values) . "\r\n";
}

$data = json_decode($response->getBody());

// Check for valid json.
if ($data == null) {
  echo "Response could not be parsed as json. Exiting.";
  exit();
}

echo "\nTitle: {$data->label}\n";

// Loop through until the first preview image is found.
foreach ($data->representation as $representation) {
  $found = false;
  foreach ($representation as $image) {
    if ($image->classified_as->label === "preview image") {
      echo "Preview image: {$image->id}\n";
      $found = true;
      break;
    }
  }
  if ($found) {
    break;
  }
}

// Loop through subject data for descriptions.
foreach ($data->subject_of as $subject) {
  // See if this classification is a physical description or significance statement.
  foreach ($subject->classified_as as $classification) {
    if ($classification->label === "physical description") {
      echo "Description:\n{$subject->value}\n\n";
    }
    else if ($classification->label === "significance") {
      echo "Statement of significance:\n{$subject->value}\n\n";
    }
  }
}

// Loop through identifiers to find the repository number.
foreach ($data->identified_by as $identified) {
  if ($identified->classified_as->label === "repository number") {
    $collectionUrl = "http://collectionsearch.nma.gov.au/object/{$identified->value}";
    echo "Link to item in API explorer: {$collectionUrl}\n\n";
  }
}

echo "</pre>";
Conal-Tuohy commented 6 years ago

Cheers @srowlands for the sample code.

I totally take your point, but I think this kind of nesting is inevitable in JSON-LD, and that this is going to be an issue generally. Do you think there might an alternative, more concise PHP idiom that might make this kind of thing easier? My PHP knowledge is pretty scanty I'm afraid. In Javascript I think I would use the filter() function of arrays to find the image which has the type I'm after. Something like:

var previewImageUrl = object
   .representation
      .representation
         .filter(image => image.classified_as.label == 'preview image')
         [0]
            .id;

... which is functionally the same but more concise, though only slightly.

If you could suggest something it would be great to include some sample code in the API documentation.

Conal-Tuohy commented 6 years ago

Maybe something like this? http://php.net/manual/en/ds-map.filter.php

Conal-Tuohy commented 6 years ago

... maybe even better, an implementation of JsonPath? e.g. one of

In particular with the JSON-LD format, which does involve a lot of nesting and where I suspect you would often want to filter objects based on properties of child objects, I think having an "expression language" like JsonPath could be very useful. I have not used JsonPath myself, but I'm very familiar with XPath (for querying XML objects), which it seems was the inspiration for JsonPath.

Have you ever used it, @srowlands ? Thoughts? Given the cross-platform support for JsonPath it might be worth using it in our documentation for examples.

Conal-Tuohy commented 6 years ago

Apart from JsonPath there is also jq which is also available for PHP. e.g. a jq query to extract preview images from an object: .representation[].representation[] | select(.classified_as.label == "preview image") | .id I would certainly want to be using something like this if I were doing a large client-side job based on the Museum's API, but it could be overkill for a small use.

f27wood commented 6 years ago

To discuss.