Skip to content

Commit 2267168

Browse files
committed
webanno: implemented maps and using JSON-LD contexts
* Maps allow nested structure to translate from STAM to web annotation * When a STAM dataset ID corresponds to a set that was added as JSON-LD contexts, keys are propagated as-is and not turned into full IRIs. This effectively allows for aliases and it is then up to the JSON-LD context to interpet them.
1 parent 2a43556 commit 2267168

File tree

1 file changed

+74
-7
lines changed

1 file changed

+74
-7
lines changed

src/api/webanno.rs

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,28 @@ fn into_iri<'a>(s: &'a str, mut prefix: &str) -> Cow<'a, str> {
9595
fn value_to_json(value: &DataValue) -> String {
9696
match value {
9797
DataValue::String(s) => format!("\"{}\"", s.replace("\n", "\\n").replace("\"", "\\\"")),
98+
DataValue::List(l) => {
99+
let mut json_out = "[".to_string();
100+
for (i, value) in l.iter().enumerate() {
101+
if i > 0 {
102+
json_out.push(',');
103+
}
104+
json_out.push_str(&value_to_json(value));
105+
}
106+
json_out.push(']');
107+
json_out
108+
}
109+
DataValue::Map(m) => {
110+
let mut json_out = "{".to_string();
111+
for (i, (key, value)) in m.iter().enumerate() {
112+
if i > 0 {
113+
json_out.push(',');
114+
}
115+
json_out.push_str(&format!("\"{}\": {}", key, value_to_json(value)));
116+
}
117+
json_out.push('}');
118+
json_out
119+
}
98120
x => x.to_string(),
99121
}
100122
}
@@ -113,7 +135,9 @@ pub struct WebAnnoConfig {
113135
/// IRI prefix for Text Resources. Will be prepended if the resource public ID is not an IRI yet.
114136
pub default_resource_iri: String,
115137

116-
/// Extra JSON-LD context to export, these must be URLs to JSONLD files.
138+
/// Extra JSON-LD context to export, these must be URLs to JSONLD files. Keys in these sets that are not full IRIs will
139+
/// then be copied as-is to the output (as alias rather than joined with the set ID to form a
140+
/// full IRI ), leaving interpretation it up to the JSON-LD context.
117141
pub extra_context: Vec<String>,
118142

119143
/// Automatically add a 'generated' triple for each annotation, with the timestamp of serialisation
@@ -163,6 +187,22 @@ impl WebAnnoConfig {
163187
Cow::Borrowed(s)
164188
}
165189

190+
/// Automatically add any datasets with IDs ending in `.jsonld` or `.jsonld` to the extra context list.
191+
pub fn auto_extra_context(mut self, store: &AnnotationStore) -> Self {
192+
for dataset in store.datasets() {
193+
if let Some(dataset_id) = dataset.id() {
194+
if (dataset_id.ends_with(".jsonld") || dataset_id.ends_with(".json"))
195+
&& is_iri(dataset_id)
196+
{
197+
if !self.extra_context.iter().any(|x| x == dataset_id) {
198+
self.extra_context.push(dataset_id.to_string());
199+
}
200+
}
201+
}
202+
}
203+
self
204+
}
205+
166206
/// Generates a JSON-LD string to use for @context
167207
pub fn serialize_context(&self) -> String {
168208
let mut out = String::new();
@@ -208,7 +248,7 @@ impl WebAnnoConfig {
208248
}
209249

210250
impl<'store> ResultItem<'store, Annotation> {
211-
/// Outputs the annotation as a W3C Web Annotation, the JSON output will be on a single line without pretty formatting.
251+
/// Outputs the annotation as a W3C Web Annotation, the output will be JSON-LD on a single line without pretty formatting.
212252
pub fn to_webannotation(&self, config: &WebAnnoConfig) -> String {
213253
if let Selector::AnnotationDataSelector(..) | Selector::DataKeySelector(..) =
214254
self.as_ref().target()
@@ -236,6 +276,7 @@ impl<'store> ResultItem<'store, Annotation> {
236276
let mut suppress_body_id = false;
237277
let mut suppress_auto_generated = false;
238278
let mut suppress_auto_generator = false;
279+
let mut target_extra_out = String::new();
239280

240281
let mut outputted_to_main = false;
241282
//gather annotation properties (outside of body)
@@ -267,6 +308,12 @@ impl<'store> ResultItem<'store, Annotation> {
267308
outputted_to_main = true;
268309
ann_out += &output_predicate_datavalue(key_id, data.value(), config);
269310
}
311+
"target" => {
312+
if !target_extra_out.is_empty() {
313+
target_extra_out.push(',');
314+
}
315+
target_extra_out += &value_to_json(data.value());
316+
}
270317
key_id => {
271318
//other predicates -> go into body
272319
if key_id == "type" {
@@ -280,9 +327,15 @@ impl<'store> ResultItem<'store, Annotation> {
280327
body_out += &output_predicate_datavalue(key_id, data.value(), config);
281328
}
282329
},
283-
Some(_set_id) => {
330+
Some(set_id) => {
284331
//different set, go into body
285-
let predicate = key.iri(&config.default_set_iri).expect("set must have ID");
332+
let predicate = if config.extra_context.iter().any(|s| s == set_id) {
333+
//the set doubles as JSON-LD context: return the key as is (either a full IRI already or an alias)
334+
Cow::Borrowed(key.id().expect("key must have ID"))
335+
} else {
336+
//turn it into an IRI per standard identifier rules
337+
key.iri(&config.default_set_iri).expect("set must have ID")
338+
};
286339
if !body_out.is_empty() {
287340
body_out.push(',');
288341
}
@@ -338,15 +391,29 @@ impl<'store> ResultItem<'store, Annotation> {
338391
&mut need_second_pass,
339392
true, //second pass
340393
);
394+
if !target_extra_out.is_empty() {
395+
//with extra target from second pass and extra target(s) from annotation data
396+
ann_out += &format!(
397+
" \"target\": [ {}, {}, {} ]",
398+
output_selector_out, &second_pass_out, &target_extra_out
399+
);
400+
} else {
401+
//with extra target from second pass
402+
ann_out += &format!(
403+
" \"target\": [ {}, {} ]",
404+
output_selector_out, &second_pass_out
405+
);
406+
}
407+
} else if !target_extra_out.is_empty() {
408+
//with extra target(s) from annotation data
341409
ann_out += &format!(
342410
" \"target\": [ {}, {} ]",
343-
output_selector_out, &second_pass_out
411+
&output_selector_out, &target_extra_out
344412
);
345413
} else {
346-
//normal situation
414+
//normal situation, no extra targets
347415
ann_out += &format!(" \"target\": {}", &output_selector_out);
348416
}
349-
350417
ann_out += "}";
351418
ann_out
352419
}

0 commit comments

Comments
 (0)