aiiinotate 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +61 -0
- package/cli/import.js +142 -0
- package/cli/index.js +26 -0
- package/cli/io.js +105 -0
- package/cli/migrate.js +123 -0
- package/cli/mongoClient.js +11 -0
- package/docs/architecture.md +88 -0
- package/docs/db.md +38 -0
- package/docs/dev_iiif_compatibility.md +43 -0
- package/docs/endpoints.md +48 -0
- package/docs/progress.md +159 -0
- package/docs/specifications/0_w3c_open_annotations.md +332 -0
- package/docs/specifications/1_w3c_web_annotations.md +577 -0
- package/docs/specifications/2_iiif_apis.md +396 -0
- package/docs/specifications/3_iiif_annotations.md +103 -0
- package/docs/specifications/4_search_api.md +135 -0
- package/docs/specifications/5_sas.md +119 -0
- package/docs/specifications/6_mirador.md +119 -0
- package/docs/specifications/7_aikon.md +137 -0
- package/docs/specifications/include/presentation_2.0.webp +0 -0
- package/docs/specifications/include/presentation_2.0_white.png +0 -0
- package/docs/specifications/include/presentation_3.0.png +0 -0
- package/docs/specifications/include/presentation_3.0_resize.png +0 -0
- package/eslint.config.js +27 -0
- package/migrations/baseConfig.js +56 -0
- package/migrations/manageIndex.js +55 -0
- package/migrations/migrate-mongo-config-main.js +8 -0
- package/migrations/migrate-mongo-config-test.js +8 -0
- package/migrations/migrationScripts/20250825185706-collections.js +41 -0
- package/migrations/migrationScripts/20250826194832-annotations2-canvas-index.js +31 -0
- package/migrations/migrationScripts/20250904080710-annotations2-schema.js +42 -0
- package/migrations/migrationScripts/20251002141951-manifest2-schema.js +43 -0
- package/migrations/migrationScripts/20251006212110-manifest-unique-index.js +29 -0
- package/migrations/migrationScripts/20251028115614-annotations2-id-index.js +27 -0
- package/migrations/migrationTemplate.js +25 -0
- package/package.json +78 -0
- package/run.sh +70 -0
- package/scripts/_migrations.sh +79 -0
- package/scripts/_setup.js +31 -0
- package/scripts/setup_mongodb.sh +61 -0
- package/scripts/setup_mongodb_migrate.sh +17 -0
- package/scripts/setup_node.sh +15 -0
- package/scripts/utils.sh +192 -0
- package/setup.sh +20 -0
- package/src/app.js +113 -0
- package/src/config/.env.template +22 -0
- package/src/data/annotations/annotations2.js +419 -0
- package/src/data/annotations/annotations3.js +32 -0
- package/src/data/annotations/routes.js +271 -0
- package/src/data/annotations/routes.test.js +180 -0
- package/src/data/collectionAbstract.js +270 -0
- package/src/data/index.js +29 -0
- package/src/data/manifests/manifests2.js +305 -0
- package/src/data/manifests/manifests2.test.js +53 -0
- package/src/data/manifests/manifests3.js +23 -0
- package/src/data/manifests/routes.js +95 -0
- package/src/data/manifests/routes.test.js +69 -0
- package/src/data/routes.js +141 -0
- package/src/data/routes.test.js +117 -0
- package/src/data/utils/iiif2Utils.js +196 -0
- package/src/data/utils/iiif2Utils.test.js +98 -0
- package/src/data/utils/iiif3Utils.js +0 -0
- package/src/data/utils/iiifUtils.js +18 -0
- package/src/data/utils/routeUtils.js +109 -0
- package/src/data/utils/testUtils.js +253 -0
- package/src/data/utils/utils.js +231 -0
- package/src/db/index.js +48 -0
- package/src/fileServer/annotations.js +39 -0
- package/src/fileServer/data/annotationList_aikon_wit9_man11_anno165_all.jsonld +827 -0
- package/src/fileServer/data/annotationList_vhs_wit250_man250_anno250_all.jsonld +37514 -0
- package/src/fileServer/data/annotationList_vhs_wit253_man253_anno253_all.jsonld +20111 -0
- package/src/fileServer/data/annotations2Invalid.jsonld +39 -0
- package/src/fileServer/data/annotations2Valid.jsonld +39 -0
- package/src/fileServer/data/bnf_invalid_manifest.json +2806 -0
- package/src/fileServer/data/bnf_valid_manifest.json +2817 -0
- package/src/fileServer/data/vhs_wit253_man253_anno253_anno-24.json +1 -0
- package/src/fileServer/index.js +64 -0
- package/src/fileServer/manifests.js +14 -0
- package/src/fileServer/utils.js +35 -0
- package/src/schemas/index.js +20 -0
- package/src/schemas/schemasBase.js +47 -0
- package/src/schemas/schemasPresentation2.js +417 -0
- package/src/schemas/schemasPresentation3.js +57 -0
- package/src/schemas/schemasResolver.js +71 -0
- package/src/schemas/schemasRoutes.js +277 -0
- package/src/server.js +22 -0
- package/src/types.js +93 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
# Web annotation data model
|
|
2
|
+
|
|
3
|
+
[https://www.w3.org/TR/annotation-model/](https://www.w3.org/TR/annotation-model/)
|
|
4
|
+
|
|
5
|
+
The IIIF format is an implementation of the W3C's Web Annotation Data Model
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## In general
|
|
10
|
+
|
|
11
|
+
- an annotation is composed of 2 connected resourrces:
|
|
12
|
+
- a body: the annotation content
|
|
13
|
+
- a target: the Web resource being annotated
|
|
14
|
+
- the Web annotation format is a single data model that satisfies most annotation use cases.
|
|
15
|
+
- it is implemenation-independant
|
|
16
|
+
- its design is based on linked data, but can be used outside of that context
|
|
17
|
+
- annotations are expressed in JSON-LD
|
|
18
|
+
|
|
19
|
+
A basic annotation can look like:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
{
|
|
23
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
24
|
+
"id": "http://example.org/anno1",
|
|
25
|
+
"type": "Annotation",
|
|
26
|
+
"body": "http://example.org/post1",
|
|
27
|
+
"target": "http://example.com/page1"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Vocabulary
|
|
33
|
+
|
|
34
|
+
- **IRI**: like URIs except that IRIs allow for unicode characters, whereas URIs are limited to ASCII
|
|
35
|
+
- **Resource**: an item of interest that MAY be identified by an URI
|
|
36
|
+
- **Web resource**: a Resource that MUST be identified by an IRI
|
|
37
|
+
- **External Web Resource (EWR)**: a Web resource that is outside of the current Resource, to which an IRI points. for example, the Target of an Annotation is an EWR.
|
|
38
|
+
- **Property**: a feature of a Resource, often with a specific data type, that is not a Relationship
|
|
39
|
+
- **Relationship**: a specific Property that is a reference to another resource (using its IRI, or describing it)
|
|
40
|
+
- **Class**: a group of resources. a class is a Web resource itself (identified by an IRI)
|
|
41
|
+
- **Instance**: a resource that belongs to a specific class
|
|
42
|
+
- **Type**: a Relationship that associates a class Instance to the class itself
|
|
43
|
+
- **SpecificResource**: a Target or Body that is more specific than the Resource identified by an IRI:
|
|
44
|
+
- the SpecificResource refers to the source resource and the constraints that make it more specific.
|
|
45
|
+
- examples: a specific segment or state, a T or B that plays a specific role in the annotation...
|
|
46
|
+
- **AnnotationCollection**: an ordered list of annotations
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Annotations
|
|
51
|
+
|
|
52
|
+
### Description
|
|
53
|
+
|
|
54
|
+
- an Annotation is directed graph describing a relationship between 2 types of resources:
|
|
55
|
+
- Bodies
|
|
56
|
+
- Targets
|
|
57
|
+
- an Annotation has 0..n Bodies and 1..n Targets. it typically has 1 Body and 1 Target.
|
|
58
|
+
- Annotations, Bodies and Targets MAY have their own properties and relationships
|
|
59
|
+
|
|
60
|
+
### Annotations data model
|
|
61
|
+
|
|
62
|
+
- `@context`: `IRI | IRI[]`
|
|
63
|
+
- `"http://www.w3.org/ns/anno.jsonld"` MUST be in the context, or the entire context. if there's only this value, it MUST be provided as a string
|
|
64
|
+
- `id`: `string`
|
|
65
|
+
- the IRI identifying the resource
|
|
66
|
+
- `type`: `string | string[]`
|
|
67
|
+
- Relationship describing the type of the annotation.
|
|
68
|
+
- accepts 1+ values. if it has only 1 value, it MUST be `"Annotation"`
|
|
69
|
+
- `body`: `IRI | Object`
|
|
70
|
+
- accepts 0..n values, but there SHOULD be at least 1 body
|
|
71
|
+
- the Body MAY be embedded in the annotation, or it is an IRI pointing to an EWR
|
|
72
|
+
- `target`: `Object | IRI`
|
|
73
|
+
- accepts 0..n values, but there SHOULD be at least 1 body
|
|
74
|
+
- the Target MUST be an IRI pointing to an EWR, or a SpecificResource
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// a complete annotation
|
|
78
|
+
{
|
|
79
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
80
|
+
"id": "http://example.org/anno1",
|
|
81
|
+
"type": "Annotation",
|
|
82
|
+
"body": "http://example.org/post1",
|
|
83
|
+
"target": "http://example.com/page1"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Bodies and targets
|
|
90
|
+
|
|
91
|
+
### External Web Resources
|
|
92
|
+
|
|
93
|
+
An EWR is identified by an IRI and has properties. It is a pattern used to reference content external to the annotation JSON.
|
|
94
|
+
|
|
95
|
+
Targets MUST be EWRs and Bodies MAY be EWRs.
|
|
96
|
+
- they MUST be identified by an IRI
|
|
97
|
+
- the Resource described by a Target or Body MAY be more specific than its IRI: a T or B can be:
|
|
98
|
+
- a segment of a resource,
|
|
99
|
+
- a specific state of it,
|
|
100
|
+
- a T or B can have a specific role in an annotation
|
|
101
|
+
- for specific ways to target part of a Resource, see [Specific Resources](https://www.w3.org/TR/annotation-model/#specific-resources), which allows to specify CSS selectors, XPATH...
|
|
102
|
+
|
|
103
|
+
All properties of an EWR MAY be contained within the annotation itself. In the example below, the IRIs point to the EWR to access, while all other properties are described in the annotation's body.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
// Beatrice records a long analysis of a patent, and publishes the audio on her website as an mp3. She then creates an Annotation with the mp3 as the body, and the PDF of the patent as the target.
|
|
107
|
+
// here, the properties of the Body and Target are recorded within the Annotation itself
|
|
108
|
+
{
|
|
109
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
110
|
+
"id": "http://example.org/anno2",
|
|
111
|
+
"type": "Annotation",
|
|
112
|
+
"body": {
|
|
113
|
+
"id": "http://example.org/analysis1.mp3",
|
|
114
|
+
"format": "audio/mpeg",
|
|
115
|
+
"language": "fr"
|
|
116
|
+
},
|
|
117
|
+
"target": {
|
|
118
|
+
"id": "http://example.gov/patent1.pdf",
|
|
119
|
+
"format": "application/pdf",
|
|
120
|
+
"language": ["en", "ar"],
|
|
121
|
+
"textDirection": "ltr",
|
|
122
|
+
"processingLanguage": "en"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### General attributes of a Body or Target
|
|
128
|
+
|
|
129
|
+
- `id`: `IRI`
|
|
130
|
+
- the IRI identifying the body or target.
|
|
131
|
+
- if the `id` identifies a segment of an EWR (i.e., part of an image), the IRI's `fragment` should identify the specific part of the resource that is being targeted. Example: `{"id": "http://example.com/image1#xywh=100,100,300,300"}`
|
|
132
|
+
- for more fine-grained ways to retrieve part of a Resource, see [Specific Resources](https://www.w3.org/TR/annotation-model/#specific-resources), which allows to specify CSS selectors, XPATH...
|
|
133
|
+
- `type`: `string`
|
|
134
|
+
- the type attribute of a target or body describes the class it belongs to.
|
|
135
|
+
- allowed values are: `Dataset | Image | Video | Sound | Text`
|
|
136
|
+
- `format`: `mimetype`
|
|
137
|
+
- the mimetype of the resource. not to be confused with `type`, that describes the general class of the EWR
|
|
138
|
+
|
|
139
|
+
### String body (`bodyValue`)
|
|
140
|
+
|
|
141
|
+
In a lot of cases, the annotation's body is just an HTML string. In those cases, the Body may not be an EWR and can be included directly in the annotation, to avoid fetching content from external sources.
|
|
142
|
+
|
|
143
|
+
The simplest body is a plain string. It is expressed using `bodyValue` attribute.
|
|
144
|
+
- it MUST NOT have any metadata associated with it. For metadata (`format`, `language`...), use `TextualBody`
|
|
145
|
+
- it MUST be interpretable as `text/plain` (not HTML)
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// complete annotation with a string body
|
|
149
|
+
{
|
|
150
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
151
|
+
"id": "http://example.org/anno6",
|
|
152
|
+
"type": "Annotation",
|
|
153
|
+
"bodyValue": "Comment text",
|
|
154
|
+
"target": "http://example.org/target1"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Embedded textual body (`TextualBody`)
|
|
159
|
+
|
|
160
|
+
To include metafdata with an embedded body, use the Embedded textual body construct. Embedded textual body attributes are:
|
|
161
|
+
|
|
162
|
+
- `id`: `IRI`
|
|
163
|
+
- the IRI of the body. this attribute MAY be used to identify the textual body
|
|
164
|
+
- `type`: `string | string[]`
|
|
165
|
+
- it SHOULD have the value `"TextualBody"` and may have other classes
|
|
166
|
+
- the class `TextualBody` indicates that the body is embedded within the annotation
|
|
167
|
+
- `value`: `string`
|
|
168
|
+
- the value MUST be used. it contains the content of the body.
|
|
169
|
+
|
|
170
|
+
`TextualBody` should be preffered over `bodyValue`.
|
|
171
|
+
|
|
172
|
+
```js
|
|
173
|
+
{
|
|
174
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
175
|
+
"id": "http://example.org/anno5",
|
|
176
|
+
"type": "Annotation",
|
|
177
|
+
"body": {
|
|
178
|
+
"type" : "TextualBody",
|
|
179
|
+
"value" : "<p>j'adore !</p>",
|
|
180
|
+
"format" : "text/html",
|
|
181
|
+
"language" : "fr"
|
|
182
|
+
},
|
|
183
|
+
"target": "http://example.org/photo1"
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
And the equivalent in `bodyValue` (note that HTML markup is removed)
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
{
|
|
191
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
192
|
+
"id": "http://example.org/anno5",
|
|
193
|
+
"type": "Annotation",
|
|
194
|
+
"bodyValue": "j'adore !,
|
|
195
|
+
"target": "http://example.org/photo1"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Cardinality (number of bodies and targets)
|
|
200
|
+
|
|
201
|
+
An annotation can have 0+ bodies and 1+ targets.
|
|
202
|
+
- when there is 0 body, the attribute `body | bodyValue` is omitted. an annotation with no body is semantically similar to highlighting part of a resource.
|
|
203
|
+
- when there are 2+ bodies or targets, the `body` and `target` attributes are mapped to an array.
|
|
204
|
+
- when there are several bodies/targets, each body is related to each target individually
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
// annotation without a body.
|
|
209
|
+
{
|
|
210
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
211
|
+
"id": "http://example.org/anno8",
|
|
212
|
+
"type": "Annotation",
|
|
213
|
+
"target": "http://example.org/img.jpg#xywh=100,100,300,300"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
// annotation with several bodies and targets
|
|
219
|
+
{
|
|
220
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
221
|
+
"id": "http://example.org/anno9",
|
|
222
|
+
"type": "Annotation",
|
|
223
|
+
"body": [
|
|
224
|
+
"http://example.org/description1",
|
|
225
|
+
{
|
|
226
|
+
"type": "TextualBody",
|
|
227
|
+
"value": "tag1"
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"target": [
|
|
231
|
+
"http://example.org/image1",
|
|
232
|
+
"http://example.org/image2"
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Choice
|
|
238
|
+
|
|
239
|
+
The class `Choice` allows to select only one resourrce from an array. The client MAY use any algorithm to decide which resource to use. Otherwise, it MAY require the uer to make the decision.
|
|
240
|
+
|
|
241
|
+
Attribures are:
|
|
242
|
+
- `id`: `string`
|
|
243
|
+
- the IRI of the Choice
|
|
244
|
+
- `type`: `Choice`.
|
|
245
|
+
- A Choice resourrce MUST have only 1 value and the only allowed value is `Choice`
|
|
246
|
+
- `items`: `[]`
|
|
247
|
+
- the list of resources to choose from. The 1st option is the default.
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
{
|
|
251
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
252
|
+
"id": "http://example.org/anno10",
|
|
253
|
+
"type": "Annotation",
|
|
254
|
+
"body": {
|
|
255
|
+
"type": "Choice",
|
|
256
|
+
"items": [
|
|
257
|
+
{
|
|
258
|
+
"id": "http://example.org/note1",
|
|
259
|
+
"language": "en"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"id": "http://example.org/note2",
|
|
263
|
+
"language": "fr"
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
"target": "http://example.org/website1"
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Specific Resources
|
|
274
|
+
|
|
275
|
+
A `SpecificResource` allows to target a section with more precision than just an IRI and its fragment: CSS selectors, XPATH, text range...
|
|
276
|
+
- it is used in between the Body and Target
|
|
277
|
+
- they MAY be EWRs with their IRIs, but it is better to include them inside the annotation to avoid extra queries
|
|
278
|
+
- possible types of specificities (categories of Specific Resources) are: `Purpose | Selector | State | Style | Rendering | Scope`
|
|
279
|
+
|
|
280
|
+
### Specific resources data model
|
|
281
|
+
|
|
282
|
+
- `id`: `IRI`
|
|
283
|
+
- the SpecificResource's IRI (optional)
|
|
284
|
+
- `type`: `SpecificResource`
|
|
285
|
+
- it SHOULD have `SpecificResource` value and MAY have other values too
|
|
286
|
+
- `source`: `IRI | Object`
|
|
287
|
+
- the relationship between SecificResource and the Resource it represents.
|
|
288
|
+
- there MUST be exactly 1 source, described in detail or identified by its IRI.
|
|
289
|
+
- `purpose`: optional
|
|
290
|
+
- describe the motivation for the annotation
|
|
291
|
+
- `selector`: `string | string[] | object | object[]`
|
|
292
|
+
- may be a string, an object or an array of strings or objects
|
|
293
|
+
- custom selectors for the annotation
|
|
294
|
+
- there MAY be 0+ selectors
|
|
295
|
+
- multiple selectors SHOULD select the same content
|
|
296
|
+
|
|
297
|
+
```js
|
|
298
|
+
// a SpecificResource with "tagging" purposes
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
{
|
|
302
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
303
|
+
"id": "http://example.org/anno18",
|
|
304
|
+
"type": "Annotation",
|
|
305
|
+
"body": {
|
|
306
|
+
"type": "SpecificResource",
|
|
307
|
+
"purpose": "tagging",
|
|
308
|
+
"source": "http://example.org/city1"
|
|
309
|
+
},
|
|
310
|
+
"target": {
|
|
311
|
+
"id": "http://example.org/photo1",
|
|
312
|
+
"type": "Image"
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Selectors data model
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
Other attributes specific to a certain type of selector are possible.
|
|
321
|
+
- `type`: `string`
|
|
322
|
+
- the type of selector we are using
|
|
323
|
+
- a selector MUST have only 1 value
|
|
324
|
+
- possible values are: `FragmentSelector | CssSelector | XPathSelector | TextQuoteSelector | TextPositionSelector | DataPositionSelector | SvgSelector | RangeSelector`
|
|
325
|
+
- `value`: `string`
|
|
326
|
+
- the content of the selector
|
|
327
|
+
- a selector MUST have only 1 value
|
|
328
|
+
- `refinedBy`: `IRI | Object`
|
|
329
|
+
a selector within a selector to augment specificity of a selector.
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
// the Target is a SpecificResource with a CSS selector
|
|
333
|
+
{
|
|
334
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
335
|
+
"id": "http://example.org/anno21",
|
|
336
|
+
"type": "Annotation",
|
|
337
|
+
"body": "http://example.org/note1",
|
|
338
|
+
"target": {
|
|
339
|
+
"source": "http://example.org/page1.html",
|
|
340
|
+
"selector": {
|
|
341
|
+
"type": "CssSelector",
|
|
342
|
+
"value": "#elemid > .elemclass + p"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
```js
|
|
349
|
+
// the Target is a SpecificResource that points to "annotation" preceded by "this is an " and suffixed by " that has some"
|
|
350
|
+
{
|
|
351
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
352
|
+
"id": "http://example.org/anno23",
|
|
353
|
+
"type": "Annotation",
|
|
354
|
+
"body": "http://example.org/comment1",
|
|
355
|
+
"target": {
|
|
356
|
+
"source": "http://example.org/page1",
|
|
357
|
+
"selector": {
|
|
358
|
+
"type": "TextQuoteSelector",
|
|
359
|
+
"exact": "anotation",
|
|
360
|
+
"prefix": "this is an ",
|
|
361
|
+
"suffix": " that has some"
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
// refinedBy in action: 1st selector targets a fragment, second selector targets a quote
|
|
369
|
+
{
|
|
370
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
371
|
+
"id": "http://example.org/anno29",
|
|
372
|
+
"type": "Annotation",
|
|
373
|
+
"body": "http://example.org/comment1",
|
|
374
|
+
"target": {
|
|
375
|
+
"source": "http://example.org/page1",
|
|
376
|
+
"selector": {
|
|
377
|
+
"type": "FragmentSelector",
|
|
378
|
+
"value": "para5",
|
|
379
|
+
"refinedBy": {
|
|
380
|
+
"type": "TextQuoteSelector",
|
|
381
|
+
"exact": "Selected Text",
|
|
382
|
+
"prefix": "text before the ",
|
|
383
|
+
"suffix": " and text after it"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Annotation collections
|
|
393
|
+
|
|
394
|
+
An annotation Collection
|
|
395
|
+
- is an ordered list grouping annotations
|
|
396
|
+
- is divided in 2 sections:
|
|
397
|
+
- Annotation Collection manages the identify and description of the list (metadata that contextualises the collection and helps in its understanding)
|
|
398
|
+
- Annotation Pages list all annotations that are members of the Collection. Each Page is an ordered list of Annotations.
|
|
399
|
+
- contains 0+ annotations
|
|
400
|
+
- MAY have multiple pages that are traversed through `first/last` (at collection level) and `prev/next` (at page level)
|
|
401
|
+
|
|
402
|
+
### Annotation Collection data model
|
|
403
|
+
|
|
404
|
+
- `@context`: `http://www.w3.org/ns/anno.jsonld`
|
|
405
|
+
- MUST have one or more value and MUST contain the value `http://www.w3.org/ns/anno.jsonld`
|
|
406
|
+
- `id`: IRI
|
|
407
|
+
- MUST have exactly 1 IRI that identifies the collection
|
|
408
|
+
- `type`: `AnnotationCollection`
|
|
409
|
+
- MUST have 1+ types and MUST have the type `AnnotationCollection`
|
|
410
|
+
- `label`: `string | string[]`
|
|
411
|
+
- a human readable label for the collection
|
|
412
|
+
- SHOULD have 1+ labels
|
|
413
|
+
- `total`: `int`
|
|
414
|
+
- the number of Annotations in the collection
|
|
415
|
+
- SHOULD be used
|
|
416
|
+
- `first`: the first Annotation Page
|
|
417
|
+
- a Collection with >1 annotations MUST have a `first`
|
|
418
|
+
- the first Annotation Page MAY be embedded within the Collection, or it MAY be an IRI
|
|
419
|
+
- `last`: the last Annotation Page
|
|
420
|
+
- a Collection with >1 annotations SHOULD have a `last`
|
|
421
|
+
- `last` is an IRI pointing to the last Annotation Page
|
|
422
|
+
|
|
423
|
+
```js
|
|
424
|
+
{
|
|
425
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
426
|
+
"id": "http://example.org/collection1",
|
|
427
|
+
"type": "AnnotationCollection",
|
|
428
|
+
"label": "Steampunk Annotations",
|
|
429
|
+
"creator": "http://example.com/publisher",
|
|
430
|
+
"total": 42023,
|
|
431
|
+
"first": "http://example.org/page1",
|
|
432
|
+
"last": "http://example.org/page42"
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Annotation Page data model
|
|
437
|
+
|
|
438
|
+
- `@context`: `IRI?`
|
|
439
|
+
- if Page is not embedded in a collection, it MUST have 1+ values including `http://www.w3.org/ns/anno.jsonld`.
|
|
440
|
+
- if Page is embedded, it SHOULD NOT have an `@context`
|
|
441
|
+
- `id`: IRI
|
|
442
|
+
- an Annotation Page MUST have 1 IRI to identify it
|
|
443
|
+
- `type`: `AnnotationPage`
|
|
444
|
+
- MUST have 1+ types, including `AnnotationPage`
|
|
445
|
+
- `partOf`: `IRI | Object`
|
|
446
|
+
- the relation to the Collection
|
|
447
|
+
- the Collection MAY be identified by its IRI or by an Object containing properties of the Collection and at least the Collection's `id`
|
|
448
|
+
- `items`: `[]`
|
|
449
|
+
- the list of annotations on the Page.
|
|
450
|
+
- MUST be used
|
|
451
|
+
- `next`: `IRI`
|
|
452
|
+
- next Page related to the current Page in the Collection
|
|
453
|
+
- MUST be used unless the current Page is the last one
|
|
454
|
+
- `prev`: `IRI`
|
|
455
|
+
- previous page in the Collection
|
|
456
|
+
- SHOULD be used unless the current Page is the first one
|
|
457
|
+
- `startIndex`: `int`
|
|
458
|
+
- SHOULD be used, MUST be a single positive or null integer
|
|
459
|
+
- represents the index of the 1st annotation on the page relative to all the annotations in the Collection
|
|
460
|
+
|
|
461
|
+
```js
|
|
462
|
+
{
|
|
463
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
464
|
+
"id": "http://example.org/page1",
|
|
465
|
+
"type": "AnnotationPage",
|
|
466
|
+
"partOf": {
|
|
467
|
+
"id": "http://example.org/collection1",
|
|
468
|
+
"label": "Steampunk Annotations",
|
|
469
|
+
"total": 42023
|
|
470
|
+
},
|
|
471
|
+
"next": "http://example.org/page2",
|
|
472
|
+
"startIndex": 0,
|
|
473
|
+
"items": [
|
|
474
|
+
{
|
|
475
|
+
"id": "http://example.org/anno1",
|
|
476
|
+
"type": "Annotation",
|
|
477
|
+
"body": "http://example.net/comment1",
|
|
478
|
+
"target": "http://example.com/book/chapter1"
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"id": "http://example.org/anno2",
|
|
482
|
+
"type": "Annotation",
|
|
483
|
+
"body": "http://example.net/comment2",
|
|
484
|
+
"target": "http://example.com/book/chapter2"
|
|
485
|
+
}
|
|
486
|
+
]
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## Complete Example
|
|
493
|
+
|
|
494
|
+
```js
|
|
495
|
+
{
|
|
496
|
+
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
497
|
+
"id": "http://example.org/anno38",
|
|
498
|
+
"type": "Annotation",
|
|
499
|
+
"motivation": "commenting",
|
|
500
|
+
"creator": {
|
|
501
|
+
"id": "http://example.org/user1",
|
|
502
|
+
"type": "Person",
|
|
503
|
+
"name": "A. Person",
|
|
504
|
+
"nickname": "user1"
|
|
505
|
+
},
|
|
506
|
+
"created": "2015-10-13T13:00:00Z",
|
|
507
|
+
"generator": {
|
|
508
|
+
"id": "http://example.org/client1",
|
|
509
|
+
"type": "Software",
|
|
510
|
+
"name": "Code v2.1",
|
|
511
|
+
"homepage": "http://example.org/homepage1"
|
|
512
|
+
},
|
|
513
|
+
"generated": "2015-10-14T15:13:28Z",
|
|
514
|
+
"stylesheet": {
|
|
515
|
+
"id": "http://example.org/stylesheet1",
|
|
516
|
+
"type": "CssStylesheet"
|
|
517
|
+
},
|
|
518
|
+
"body": [
|
|
519
|
+
{
|
|
520
|
+
"type": "TextualBody",
|
|
521
|
+
"purpose": "tagging",
|
|
522
|
+
"value": "love"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"type": "Choice",
|
|
526
|
+
"items": [
|
|
527
|
+
{
|
|
528
|
+
"type": "TextualBody",
|
|
529
|
+
"purpose": "describing",
|
|
530
|
+
"value": "I really love this particular bit of text in this XML. No really.",
|
|
531
|
+
"format": "text/plain",
|
|
532
|
+
"language": "en",
|
|
533
|
+
"creator": "http://example.org/user1"
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"type": "SpecificResource",
|
|
537
|
+
"purpose": "describing",
|
|
538
|
+
"source": {
|
|
539
|
+
"id": "http://example.org/comment1",
|
|
540
|
+
"type": "Audio",
|
|
541
|
+
"format": "audio/mpeg",
|
|
542
|
+
"language": "de",
|
|
543
|
+
"creator": {
|
|
544
|
+
"id": "http://example.org/user2",
|
|
545
|
+
"type": "Person"
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
],
|
|
552
|
+
"target": {
|
|
553
|
+
"type": "SpecificResource",
|
|
554
|
+
"styleClass": "mystyle",
|
|
555
|
+
"source": "http://example.com/document1",
|
|
556
|
+
"state": [
|
|
557
|
+
{
|
|
558
|
+
"type": "HttpRequestState",
|
|
559
|
+
"value": "Accept: application/xml",
|
|
560
|
+
"refinedBy": {
|
|
561
|
+
"type": "TimeState",
|
|
562
|
+
"sourceDate": "2015-09-25T12:00:00Z"
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
],
|
|
566
|
+
"selector": {
|
|
567
|
+
"type": "FragmentSelector",
|
|
568
|
+
"value": "xpointer(/doc/body/section[2]/para[1])",
|
|
569
|
+
"refinedBy": {
|
|
570
|
+
"type": "TextPositionSelector",
|
|
571
|
+
"start": 6,
|
|
572
|
+
"end": 27
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
```
|