IIIF Presentation APIのバリデーション方法とその実例の紹介ほか

概要

先日、以下の記事に書いた通り、IIIFのマニフェストファイルの配信と、IIIF Content Search APIを提供するアプリを開発しました。

nakamura196.hatenablog.com

ただそれぞれ、APIに準拠しない記述をしていた部分がありました。

本記事では、その修正内容を共有するとともに、バリデーションを行うPresentation API Validatorの使用方法について、実例とともに紹介します。

https://presentation-validator.iiif.io/

マニフェストファイルの修正

上記のPresentation API Validatorのサイトにアクセスし、URL of Manifest to ValidateマニフェストファイルのURLを入力し、対応したAPIのバージョン(今回は3.0)を選択します。

その結果、以下のように、エラーがある場合には、その内容が表示されます。

冒頭で紹介した私が開発したアプリが配信するマニフェストファイルは、そのサイズが大きいため、そのまま本バリデータにURLを入力すると、検証結果が表示されるまで時間がかかります。

そのため、マニフェストファイルの1canvas目のデータのみを残したマニフェストファイルを別途作成しました。それをバリデータにかけた結果、59件のエラーメッセージが表示されました。

以下、それぞれのエラー内容への対応方法を記述します。

Error 1 of 59. Message: ['https://ocr.aws.ldas.jp/v1/manifest/3437686.json'] is not of type 'string'

before

{
    "id": [
        "https://ocr.aws.ldas.jp/v1/manifest/3437686.json"
    ]
}

誤って、マニフェストファイルのidを配列の形で与えていました。以下のように修正しました。

after

{
    "id": "https://ocr.aws.ldas.jp/v1/manifest/3437686.json"
}

Error 2 of 59. Message: 'Persistent ID' is not of type 'object'

before

{
    "metadata": [
        {
            "label": "Persistent ID",
            "value": "info:ndljp/pid/3437686"
        }
    ]
}

この類のエラーは、2-23、26-59まで共通でした。(主に、metadataの記述箇所)

以下のような形で、言語(ここではnone)を指定し、値は配列として与える必要がありました。必要に応じて、jaenといった言語を与えることができます。

after

{
    "metadata": [
        {
            "label": {
                "none": [
                    "Persistent ID"
                ]
            },
            "value": {
                "none": [
                    "info:ndljp/pid/3437686"
                ]
            }
        }
    ]
}

Error 24 of 59. Message: {'@context': 'http://iiif.io/api/search/1/context.json', '@id': 'https://search.aws.ldas.jp/search/3437686', 'profile': 'http://iiif.io/api/search/1/search'} is not of type 'array'

before

{
    "service": {
        "@context": "http://iiif.io/api/search/1/context.json",
        "@id": "https://search.aws.ldas.jp/search/3437686",
        "profile": "http://iiif.io/api/search/1/search"
    }
}

IIIF Search APIを指定している部分です。serviceの値を配列にし、@ididに修正し、必須項目typeSearchService1を与えました。

after

{
    "service": [
        {
            "@context": "http://iiif.io/api/search/1/context.json",
            "id": "https://search.aws.ldas.jp/search/3437686",
            "profile": "http://iiif.io/api/search/1/search",
            "type": "SearchService1"
        }
    ]
}

Error 25 of 59. Message: 'https://dl.ndl.go.jp/ja/iiif_license.html' does not match 'http://creativecommons.org/licenses/.*'

before

{
    "rights": "https://dl.ndl.go.jp/ja/iiif_license.html"
}

rightsに与えることができる値は、https://creativecommons.orghttps://rightsstatements.orgのURLのみのようです。

https://iiif.io/api/presentation/3.0/#rights

そのため、rightsを削除して、metadataに値を移動しました。

(この方法だと、ビューア上で利用条件が見つけにくくなってしまうため、他により良い方法がないか引き続き検討します。)

after

{
    "metadata": [
        {
            "label": {
                "none": [
                    "rights"
                ]
            },
            "value": {
                "none": [
                    "https://dl.ndl.go.jp/ja/iiif_license.html"
                ]
            }
        }
    ]
}

Error 29 of 59. Message: 'id' is a required property

before

{
    "@id": "https://www.dl.ndl.go.jp/api/iiif/3437686/range/1",
    "@type": "sc:Range",
    "label": {
        "none": [
            "目次"
        ]
    },
    "items": [...]
}

目次を与えるstructuresの記述において、v2の記述が残っていました。@ididに、@typetypeに修正し、値からsc:を除きました。

after

{
    "id": "https://www.dl.ndl.go.jp/api/iiif/3437686/range/1",
    "type": "Range",
    "label": {
        "none": [
            "目次"
        ]
    },
    "items": [...]
}

結果

上記の対応の結果、以下のValidated successfullyが表示されました。

IIIF Content Search API

次に、IIIF Content Search APIについて修正します。本APIについては、バリデータがない(はず)なので、ドキュメントを参考に不具合を修正しました。修正漏れや誤りが残っている可能性があります。

https://iiif.io/api/search/1.0/

@contextの修正

before

{
  "@context": "http://iiif.io/ns/search/canvas.json"
}

存在しないURIを指定していました。正しいURIに修正します。

after

{
  "@context": "https://iiif.io/api/search/1/context.json"
}

@typeとcanvasのxywhの修正

before

{
      "@id": "https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/3#xywh=2074,3786,711,222/searchResults",
      "@type": "oa:Annotation",
      "motivation": "sc:panting",
      "resource": {
        "@type": "cnt:ContextAstext",
        "chars": "公央中"
      },
      "on": "https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/3#xywh=2074,3786,711,222/searchResults"
    }

onに不要な文字列/searchResultsが末尾に含まれている点を修正しました。また、@typeの値をcnt:ContextAstextからcnt:ContentAsTextに修正しました。 さらに、これは修正が必須なものでありませんが、@idの指定方法を以下のWellcome Collectionにならって改めました。

https://iiif.wellcomecollection.org/search/v0/b18035723?q=ab

after

{
      "@id": "https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/3/h1r2074,3786,711,222",
      "@type": "oa:Annotation",
      "motivation": "sc:panting",
      "resource": {
        "@type": "cnt:ContentAsText",
        "chars": "公央中"
      },
      "on": "https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/3#xywh=2074,3786,711,222"
    }

hits要素の追加

これまで、本APIの返戻結果に、以下のhits要素を含めていませんでした。

https://iiif.io/api/search/1.0/#search-api-specific-responses

今回の修正に合わせて、このhits要素を追加することにより、Image Annotatorでも検索結果が正しく表示されるようになりました。

まとめ

まだ不完全な可能性がありますが、上記のように、各APIの不具合方針を定めました。この後、それぞれのサービスを実際に修正します。

本記事が、IIIFのバリデータの使い方や、IIIF Presentation API v3の記述方法の参考になりましたら幸いです。(私の凡ミスがほとんどでしたが...)

本不具合についてお知らせくださった @_masaka 先生、ありがとうございました!

(そして、私の不具合に合わせてアプリを修正していただき、お手数をおかけして申し訳ありませんでした。)