json-ld 3.1.1 → 3.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +124 -48
- data/VERSION +1 -1
- data/bin/jsonld +27 -30
- data/lib/json/ld.rb +12 -7
- data/lib/json/ld/api.rb +41 -31
- data/lib/json/ld/compact.rb +58 -37
- data/lib/json/ld/conneg.rb +1 -1
- data/lib/json/ld/context.rb +641 -540
- data/lib/json/ld/expand.rb +160 -77
- data/lib/json/ld/flatten.rb +1 -1
- data/lib/json/ld/format.rb +20 -7
- data/lib/json/ld/frame.rb +0 -1
- data/lib/json/ld/from_rdf.rb +40 -17
- data/lib/json/ld/html/nokogiri.rb +2 -1
- data/lib/json/ld/html/rexml.rb +2 -1
- data/lib/json/ld/reader.rb +20 -11
- data/lib/json/ld/streaming_reader.rb +578 -0
- data/lib/json/ld/to_rdf.rb +9 -5
- data/lib/json/ld/writer.rb +10 -3
- data/spec/compact_spec.rb +1 -0
- data/spec/context_spec.rb +20 -73
- data/spec/expand_spec.rb +277 -9
- data/spec/frame_spec.rb +44 -0
- data/spec/from_rdf_spec.rb +181 -0
- data/spec/matchers.rb +1 -1
- data/spec/reader_spec.rb +33 -34
- data/spec/streaming_reader_spec.rb +237 -0
- data/spec/suite_expand_spec.rb +2 -2
- data/spec/suite_frame_spec.rb +0 -1
- data/spec/suite_helper.rb +18 -8
- data/spec/suite_to_rdf_spec.rb +2 -1
- data/spec/to_rdf_spec.rb +206 -0
- metadata +65 -62
data/lib/json/ld/expand.rb
CHANGED
@@ -21,20 +21,21 @@ module JSON::LD
|
|
21
21
|
# @param [Array, Hash] input
|
22
22
|
# @param [String] active_property
|
23
23
|
# @param [Context] context
|
24
|
-
# @param [Boolean] ordered (true)
|
25
|
-
# Ensure output objects have keys ordered properly
|
26
24
|
# @param [Boolean] framing (false)
|
27
25
|
# Special rules for expanding a frame
|
28
26
|
# @param [Boolean] from_map
|
29
27
|
# Expanding from a map, which could be an `@type` map, so don't clear out context term definitions
|
28
|
+
#
|
30
29
|
# @return [Array<Hash{String => Object}>]
|
31
|
-
def expand(input, active_property, context,
|
32
|
-
|
30
|
+
def expand(input, active_property, context,
|
31
|
+
framing: false, from_map: false, log_depth: nil)
|
32
|
+
log_debug("expand", depth: log_depth.to_i) {"input: #{input.inspect}, active_property: #{active_property.inspect}, context: #{context.inspect}"}
|
33
33
|
framing = false if active_property == '@default'
|
34
|
-
expanded_active_property = context.expand_iri(active_property, vocab: true, as_string: true) if active_property
|
34
|
+
expanded_active_property = context.expand_iri(active_property, vocab: true, as_string: true, base: @options[:base]) if active_property
|
35
35
|
|
36
36
|
# Use a term-specific context, if defined, based on the non-type-scoped context.
|
37
37
|
property_scoped_context = context.term_definitions[active_property].context if active_property && context.term_definitions[active_property]
|
38
|
+
log_debug("expand", depth: log_depth.to_i) {"property_scoped_context: #{property_scoped_context.inspect}"} unless property_scoped_context.nil?
|
38
39
|
|
39
40
|
result = case input
|
40
41
|
when Array
|
@@ -42,7 +43,10 @@ module JSON::LD
|
|
42
43
|
is_list = context.container(active_property).include?('@list')
|
43
44
|
value = input.each_with_object([]) do |v, memo|
|
44
45
|
# Initialize expanded item to the result of using this algorithm recursively, passing active context, active property, and item as element.
|
45
|
-
v = expand(v, active_property, context,
|
46
|
+
v = expand(v, active_property, context,
|
47
|
+
framing: framing,
|
48
|
+
from_map: from_map,
|
49
|
+
log_depth: log_depth.to_i + 1)
|
46
50
|
|
47
51
|
# If the active property is @list or its container mapping is set to @list and v is an array, change it to a list object
|
48
52
|
v = {"@list" => v} if is_list && v.is_a?(Array)
|
@@ -57,23 +61,29 @@ module JSON::LD
|
|
57
61
|
value
|
58
62
|
when Hash
|
59
63
|
if context.previous_context
|
60
|
-
expanded_key_map = input.keys.inject({})
|
64
|
+
expanded_key_map = input.keys.inject({}) do |memo, key|
|
65
|
+
memo.merge(key => context.expand_iri(key, vocab: true, as_string: true, base: @options[:base]))
|
66
|
+
end
|
61
67
|
# Revert any previously type-scoped term definitions, unless this is from a map, a value object or a subject reference
|
62
68
|
revert_context = !from_map &&
|
63
69
|
!expanded_key_map.values.include?('@value') &&
|
64
70
|
!(expanded_key_map.values == ['@id'])
|
65
71
|
|
66
72
|
# If there's a previous context, the context was type-scoped
|
73
|
+
log_debug("expand", depth: log_depth.to_i) {"previous_context: #{context.previous_context.inspect}"} if revert_context
|
67
74
|
context = context.previous_context if revert_context
|
68
75
|
end
|
69
76
|
|
70
77
|
# Apply property-scoped context after reverting term-scoped context
|
71
|
-
|
78
|
+
unless property_scoped_context.nil?
|
79
|
+
context = context.parse(property_scoped_context, base: @options[:base], override_protected: true)
|
80
|
+
end
|
81
|
+
log_debug("expand", depth: log_depth.to_i) {"after property_scoped_context: #{context.inspect}"} unless property_scoped_context.nil?
|
72
82
|
|
73
83
|
# If element contains the key @context, set active context to the result of the Context Processing algorithm, passing active context and the value of the @context key as local context.
|
74
84
|
if input.has_key?('@context')
|
75
|
-
context = context.parse(input.delete('@context'))
|
76
|
-
|
85
|
+
context = context.parse(input.delete('@context'), base: @options[:base])
|
86
|
+
log_debug("expand", depth: log_depth.to_i) {"context: #{context.inspect}"}
|
77
87
|
end
|
78
88
|
|
79
89
|
# Set the type-scoped context to the context on input, for use later
|
@@ -84,25 +94,28 @@ module JSON::LD
|
|
84
94
|
# See if keys mapping to @type have terms with a local context
|
85
95
|
type_key = nil
|
86
96
|
input.keys.sort.
|
87
|
-
select {|k| context.expand_iri(k, vocab: true,
|
97
|
+
select {|k| context.expand_iri(k, vocab: true, base: @options[:base]) == '@type'}.
|
88
98
|
each do |tk|
|
89
99
|
|
90
100
|
type_key ||= tk # Side effect saves the first found key mapping to @type
|
91
101
|
Array(input[tk]).sort.each do |term|
|
92
102
|
term_context = type_scoped_context.term_definitions[term].context if type_scoped_context.term_definitions[term]
|
93
|
-
|
103
|
+
unless term_context.nil?
|
104
|
+
log_debug("expand", depth: log_depth.to_i) {"term_context: #{term_context.inspect}"}
|
105
|
+
context = context.parse(term_context, base: @options[:base], propagate: false)
|
106
|
+
end
|
94
107
|
end
|
95
108
|
end
|
96
109
|
|
97
110
|
# Process each key and value in element. Ignores @nesting content
|
98
111
|
expand_object(input, active_property, context, output_object,
|
99
112
|
expanded_active_property: expanded_active_property,
|
100
|
-
|
113
|
+
framing: framing,
|
101
114
|
type_key: type_key,
|
102
|
-
|
103
|
-
|
115
|
+
type_scoped_context: type_scoped_context,
|
116
|
+
log_depth: log_depth.to_i + 1)
|
104
117
|
|
105
|
-
|
118
|
+
log_debug("output object", depth: log_depth.to_i) {output_object.inspect}
|
106
119
|
|
107
120
|
# If result contains the key @value:
|
108
121
|
if value?(output_object)
|
@@ -110,13 +123,13 @@ module JSON::LD
|
|
110
123
|
unless (keys - KEYS_VALUE_LANGUAGE_TYPE_INDEX_DIRECTION).empty?
|
111
124
|
# The result must not contain any keys other than @direction, @value, @language, @type, and @index. It must not contain both the @language key and the @type key. Otherwise, an invalid value object error has been detected and processing is aborted.
|
112
125
|
raise JsonLdError::InvalidValueObject,
|
113
|
-
|
126
|
+
"value object has unknown keys: #{output_object.inspect}"
|
114
127
|
end
|
115
128
|
|
116
129
|
if keys.include?('@type') && !(keys & %w(@language @direction)).empty?
|
117
130
|
# @type is inconsistent with either @language or @direction
|
118
131
|
raise JsonLdError::InvalidValueObject,
|
119
|
-
|
132
|
+
"value object must not include @type with either @language or @direction: #{output_object.inspect}"
|
120
133
|
end
|
121
134
|
|
122
135
|
output_object.delete('@language') if output_object.key?('@language') && Array(output_object['@language']).empty?
|
@@ -133,9 +146,16 @@ module JSON::LD
|
|
133
146
|
# Otherwise, if the value of result's @value member is not a string and result contains the key @language, an invalid language-tagged value error has been detected (only strings can be language-tagged) and processing is aborted.
|
134
147
|
raise JsonLdError::InvalidLanguageTaggedValue,
|
135
148
|
"when @language is used, @value must be a string: #{output_object.inspect}"
|
136
|
-
elsif
|
137
|
-
|
138
|
-
|
149
|
+
elsif output_object['@type'] &&
|
150
|
+
(!Array(output_object['@type']).all? {|t|
|
151
|
+
t.is_a?(String) && RDF::URI(t).valid? && !t.start_with?('_:') ||
|
152
|
+
t.is_a?(Hash) && t.empty?} ||
|
153
|
+
!framing && !output_object['@type'].is_a?(String))
|
154
|
+
# Otherwise, if the result has a @type member and its value is not an IRI, an invalid typed value error has been detected and processing is aborted.
|
155
|
+
raise JsonLdError::InvalidTypedValue,
|
156
|
+
"value of @type must be an IRI or '@json': #{output_object.inspect}"
|
157
|
+
elsif !framing && !output_object.fetch('@type', '').is_a?(String) &&
|
158
|
+
RDF::URI(t).valid? && !t.start_with?('_:')
|
139
159
|
# Otherwise, if the result has a @type member and its value is not an IRI, an invalid typed value error has been detected and processing is aborted.
|
140
160
|
raise JsonLdError::InvalidTypedValue,
|
141
161
|
"value of @type must be an IRI or '@json': #{output_object.inspect}"
|
@@ -161,12 +181,12 @@ module JSON::LD
|
|
161
181
|
if (expanded_active_property || '@graph') == '@graph' &&
|
162
182
|
(output_object.key?('@value') || output_object.key?('@list') ||
|
163
183
|
(output_object.keys - KEY_ID).empty? && !framing)
|
164
|
-
|
184
|
+
log_debug(" =>", depth: log_depth.to_i) { "empty top-level: " + output_object.inspect}
|
165
185
|
return nil
|
166
186
|
end
|
167
187
|
|
168
188
|
# Re-order result keys if ordering
|
169
|
-
if ordered
|
189
|
+
if @options[:ordered]
|
170
190
|
output_object.keys.sort.each_with_object({}) {|kk, memo| memo[kk] = output_object[kk]}
|
171
191
|
else
|
172
192
|
output_object
|
@@ -176,12 +196,17 @@ module JSON::LD
|
|
176
196
|
return nil if input.nil? || active_property.nil? || expanded_active_property == '@graph'
|
177
197
|
|
178
198
|
# Apply property-scoped context
|
179
|
-
|
199
|
+
unless property_scoped_context.nil?
|
200
|
+
context = context.parse(property_scoped_context,
|
201
|
+
base: @options[:base],
|
202
|
+
override_protected: true)
|
203
|
+
end
|
204
|
+
log_debug("expand", depth: log_depth.to_i) {"property_scoped_context: #{context.inspect}"} unless property_scoped_context.nil?
|
180
205
|
|
181
|
-
context.expand_value(active_property, input,
|
206
|
+
context.expand_value(active_property, input, base: @options[:base])
|
182
207
|
end
|
183
208
|
|
184
|
-
|
209
|
+
log_debug(depth: log_depth.to_i) {" => #{result.inspect}"}
|
185
210
|
result
|
186
211
|
end
|
187
212
|
|
@@ -190,21 +215,21 @@ module JSON::LD
|
|
190
215
|
# Expand each key and value of element adding them to result
|
191
216
|
def expand_object(input, active_property, context, output_object,
|
192
217
|
expanded_active_property:,
|
193
|
-
|
218
|
+
framing:,
|
194
219
|
type_key:,
|
195
|
-
|
196
|
-
|
220
|
+
type_scoped_context:,
|
221
|
+
log_depth: nil)
|
197
222
|
nests = []
|
198
223
|
|
199
224
|
input_type = Array(input[type_key]).last
|
200
|
-
input_type = context.expand_iri(input_type, vocab: true, as_string: true) if input_type
|
225
|
+
input_type = context.expand_iri(input_type, vocab: true, as_string: true, base: @options[:base]) if input_type
|
201
226
|
|
202
227
|
# Then, proceed and process each property and value in element as follows:
|
203
|
-
keys = ordered ? input.keys.sort : input.keys
|
228
|
+
keys = @options[:ordered] ? input.keys.sort : input.keys
|
204
229
|
keys.each do |key|
|
205
230
|
# For each key and value in element, ordered lexicographically by key:
|
206
231
|
value = input[key]
|
207
|
-
expanded_property = context.expand_iri(key, vocab: true)
|
232
|
+
expanded_property = context.expand_iri(key, vocab: true, base: @options[:base])
|
208
233
|
|
209
234
|
# If expanded property is null or it neither contains a colon (:) nor it is a keyword, drop key by continuing to the next key.
|
210
235
|
next if expanded_property.is_a?(RDF::URI) && expanded_property.relative?
|
@@ -215,10 +240,10 @@ module JSON::LD
|
|
215
240
|
expanded_property.to_s.start_with?("_:") &&
|
216
241
|
context.processingMode('json-ld-1.1')
|
217
242
|
|
218
|
-
#log_debug("expand property") {"ap: #{active_property.inspect}, expanded: #{expanded_property.inspect}, value: #{value.inspect}"}
|
243
|
+
#log_debug("expand property", depth: log_depth.to_i) {"ap: #{active_property.inspect}, expanded: #{expanded_property.inspect}, value: #{value.inspect}"}
|
219
244
|
|
220
245
|
if expanded_property.nil?
|
221
|
-
#log_debug(" => ") {"skip nil property"}
|
246
|
+
#log_debug(" => ", depth: log_depth.to_i) {"skip nil property"}
|
222
247
|
next
|
223
248
|
end
|
224
249
|
|
@@ -236,24 +261,35 @@ module JSON::LD
|
|
236
261
|
# If expanded property is @id and value is not a string, an invalid @id value error has been detected and processing is aborted
|
237
262
|
e_id = case value
|
238
263
|
when String
|
239
|
-
context.expand_iri(value,
|
264
|
+
context.expand_iri(value, as_string: true, base: @options[:base], documentRelative: true)
|
240
265
|
when Array
|
241
266
|
# Framing allows an array of IRIs, and always puts values in an array
|
242
267
|
raise JsonLdError::InvalidIdValue,
|
243
268
|
"value of @id must be a string unless framing: #{value.inspect}" unless framing
|
244
|
-
context.expand_iri(value,
|
269
|
+
context.expand_iri(value, as_string: true, base: @options[:base], documentRelative: true)
|
245
270
|
value.map do |v|
|
246
271
|
raise JsonLdError::InvalidTypeValue,
|
247
272
|
"@id value must be a string or array of strings for framing: #{v.inspect}" unless v.is_a?(String)
|
248
|
-
context.expand_iri(v,
|
273
|
+
context.expand_iri(v, as_string: true, base: @options[:base], documentRelative: true)
|
249
274
|
end
|
250
275
|
when Hash
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
[
|
276
|
+
if framing
|
277
|
+
raise JsonLdError::InvalidTypeValue,
|
278
|
+
"value of @id must be a an empty object for framing: #{value.inspect}" unless
|
279
|
+
value.empty?
|
280
|
+
[{}]
|
281
|
+
elsif @options[:rdfstar]
|
282
|
+
# Result must have just a single statement
|
283
|
+
rei_node = expand(value, active_property, context, log_depth: log_depth.to_i + 1)
|
284
|
+
statements = to_enum(:item_to_rdf, rei_node)
|
285
|
+
raise JsonLdError::InvalidEmbeddedNode,
|
286
|
+
"Embedded node with #{statements.size} statements" unless
|
287
|
+
statements.count == 1
|
288
|
+
rei_node
|
289
|
+
else
|
290
|
+
raise JsonLdError::InvalidIdValue,
|
291
|
+
"value of @id must be a string unless framing: #{value.inspect}" unless framing
|
292
|
+
end
|
257
293
|
else
|
258
294
|
raise JsonLdError::InvalidIdValue,
|
259
295
|
"value of @id must be a string or hash if framing: #{value.inspect}"
|
@@ -268,7 +304,9 @@ module JSON::LD
|
|
268
304
|
when '@included'
|
269
305
|
# Included blocks are treated as an array of separate object nodes sharing the same referencing active_property. For 1.0, it is skipped as are other unknown keywords
|
270
306
|
next if context.processingMode('json-ld-1.0')
|
271
|
-
included_result = as_array(expand(value, active_property, context,
|
307
|
+
included_result = as_array(expand(value, active_property, context,
|
308
|
+
framing: framing,
|
309
|
+
log_depth: log_depth.to_i + 1))
|
272
310
|
|
273
311
|
# Expanded values must be node objects
|
274
312
|
raise JsonLdError::InvalidIncludedValue, "values of @included must expand to node objects" unless included_result.all? {|e| node?(e)}
|
@@ -276,27 +314,39 @@ module JSON::LD
|
|
276
314
|
Array(output_object['@included']) + included_result
|
277
315
|
when '@type'
|
278
316
|
# If expanded property is @type and value is neither a string nor an array of strings, an invalid type value error has been detected and processing is aborted. Otherwise, set expanded value to the result of using the IRI Expansion algorithm, passing active context, true for vocab, and true for document relative to expand the value or each of its items.
|
279
|
-
#log_debug("@type") {"value: #{value.inspect}"}
|
317
|
+
#log_debug("@type", depth: log_depth.to_i) {"value: #{value.inspect}"}
|
280
318
|
e_type = case value
|
281
319
|
when Array
|
282
320
|
value.map do |v|
|
283
321
|
raise JsonLdError::InvalidTypeValue,
|
284
322
|
"@type value must be a string or array of strings: #{v.inspect}" unless v.is_a?(String)
|
285
|
-
type_scoped_context.expand_iri(v,
|
323
|
+
type_scoped_context.expand_iri(v,
|
324
|
+
as_string: true,
|
325
|
+
base: @options[:base],
|
326
|
+
documentRelative: true,
|
327
|
+
vocab: true)
|
286
328
|
end
|
287
329
|
when String
|
288
|
-
type_scoped_context.expand_iri(value,
|
330
|
+
type_scoped_context.expand_iri(value,
|
331
|
+
as_string: true,
|
332
|
+
base: @options[:base],
|
333
|
+
documentRelative: true,
|
334
|
+
vocab: true)
|
289
335
|
when Hash
|
290
336
|
if !framing
|
291
337
|
raise JsonLdError::InvalidTypeValue,
|
292
338
|
"@type value must be a string or array of strings: #{value.inspect}"
|
293
339
|
elsif value.keys.length == 1 &&
|
294
|
-
type_scoped_context.expand_iri(value.keys.first, vocab: true) == '@default'
|
340
|
+
type_scoped_context.expand_iri(value.keys.first, vocab: true, base: @options[:base]) == '@default'
|
295
341
|
# Expand values of @default, which must be a string, or array of strings expanding to IRIs
|
296
342
|
[{'@default' => Array(value['@default']).map do |v|
|
297
343
|
raise JsonLdError::InvalidTypeValue,
|
298
344
|
"@type default value must be a string or array of strings: #{v.inspect}" unless v.is_a?(String)
|
299
|
-
type_scoped_context.expand_iri(v,
|
345
|
+
type_scoped_context.expand_iri(v,
|
346
|
+
as_string: true,
|
347
|
+
base: @options[:base],
|
348
|
+
documentRelative: true,
|
349
|
+
vocab: true)
|
300
350
|
end}]
|
301
351
|
elsif !value.empty?
|
302
352
|
raise JsonLdError::InvalidTypeValue,
|
@@ -314,7 +364,9 @@ module JSON::LD
|
|
314
364
|
framing || e_type.length > 1 ? e_type : e_type.first
|
315
365
|
when '@graph'
|
316
366
|
# If expanded property is @graph, set expanded value to the result of using this algorithm recursively passing active context, @graph for active property, and value for element.
|
317
|
-
value = expand(value, '@graph', context,
|
367
|
+
value = expand(value, '@graph', context,
|
368
|
+
framing: framing,
|
369
|
+
log_depth: log_depth.to_i + 1)
|
318
370
|
as_array(value)
|
319
371
|
when '@value'
|
320
372
|
# If expanded property is @value and input contains @type: json, accept any value.
|
@@ -406,7 +458,9 @@ module JSON::LD
|
|
406
458
|
next if (expanded_active_property || '@graph') == '@graph'
|
407
459
|
|
408
460
|
# Otherwise, initialize expanded value to the result of using this algorithm recursively passing active context, active property, and value for element.
|
409
|
-
value = expand(value, active_property, context,
|
461
|
+
value = expand(value, active_property, context,
|
462
|
+
framing: framing,
|
463
|
+
log_depth: log_depth.to_i + 1)
|
410
464
|
|
411
465
|
# Spec FIXME: need to be sure that result is an array
|
412
466
|
value = as_array(value)
|
@@ -414,7 +468,9 @@ module JSON::LD
|
|
414
468
|
value
|
415
469
|
when '@set'
|
416
470
|
# If expanded property is @set, set expanded value to the result of using this algorithm recursively, passing active context, active property, and value for element.
|
417
|
-
expand(value, active_property, context,
|
471
|
+
expand(value, active_property, context,
|
472
|
+
framing: framing,
|
473
|
+
log_depth: log_depth.to_i + 1)
|
418
474
|
when '@reverse'
|
419
475
|
# If expanded property is @reverse and value is not a JSON object, an invalid @reverse value error has been detected and processing is aborted.
|
420
476
|
raise JsonLdError::InvalidReverseValue,
|
@@ -422,11 +478,13 @@ module JSON::LD
|
|
422
478
|
|
423
479
|
# Otherwise
|
424
480
|
# Initialize expanded value to the result of using this algorithm recursively, passing active context, @reverse as active property, and value as element.
|
425
|
-
value = expand(value, '@reverse', context,
|
481
|
+
value = expand(value, '@reverse', context,
|
482
|
+
framing: framing,
|
483
|
+
log_depth: log_depth.to_i + 1)
|
426
484
|
|
427
485
|
# If expanded value contains an @reverse member, i.e., properties that are reversed twice, execute for each of its property and item the following steps:
|
428
486
|
if value.has_key?('@reverse')
|
429
|
-
#log_debug("@reverse") {"double reverse: #{value.inspect}"}
|
487
|
+
#log_debug("@reverse", depth: log_depth.to_i) {"double reverse: #{value.inspect}"}
|
430
488
|
value['@reverse'].each do |property, item|
|
431
489
|
# If result does not have a property member, create one and set its value to an empty array.
|
432
490
|
# Append item to the value of the property member of result.
|
@@ -455,7 +513,10 @@ module JSON::LD
|
|
455
513
|
when '@default', '@embed', '@explicit', '@omitDefault', '@preserve', '@requireAll'
|
456
514
|
next unless framing
|
457
515
|
# Framing keywords
|
458
|
-
[expand(value, expanded_property, context,
|
516
|
+
[expand(value, expanded_property, context,
|
517
|
+
framing: framing,
|
518
|
+
log_depth: log_depth.to_i + 1)
|
519
|
+
].flatten
|
459
520
|
when '@nest'
|
460
521
|
# Add key to nests
|
461
522
|
nests << key
|
@@ -467,7 +528,7 @@ module JSON::LD
|
|
467
528
|
end
|
468
529
|
|
469
530
|
# Unless expanded value is null, set the expanded property member of result to expanded value.
|
470
|
-
#log_debug("expand #{expanded_property}") { expanded_value.inspect}
|
531
|
+
#log_debug("expand #{expanded_property}", depth: log_depth.to_i) { expanded_value.inspect}
|
471
532
|
output_object[expanded_property] = expanded_value unless expanded_value.nil? && expanded_property == '@value' && input_type != '@json'
|
472
533
|
next
|
473
534
|
end
|
@@ -483,9 +544,9 @@ module JSON::LD
|
|
483
544
|
ary = []
|
484
545
|
|
485
546
|
# For each key-value pair language-language value in value, ordered lexicographically by language
|
486
|
-
keys = ordered ? value.keys.sort : value.keys
|
547
|
+
keys = @options[:ordered] ? value.keys.sort : value.keys
|
487
548
|
keys.each do |k|
|
488
|
-
expanded_k = context.expand_iri(k, vocab: true, as_string: true)
|
549
|
+
expanded_k = context.expand_iri(k, vocab: true, as_string: true, base: @options[:base])
|
489
550
|
|
490
551
|
if k !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/ && expanded_k != '@none'
|
491
552
|
warn "@language must be valid BCP47: #{k.inspect}"
|
@@ -517,23 +578,35 @@ module JSON::LD
|
|
517
578
|
context.previous_context
|
518
579
|
elsif container.include?('@id') && context.term_definitions[key]
|
519
580
|
id_context = context.term_definitions[key].context if context.term_definitions[key]
|
520
|
-
id_context
|
581
|
+
if id_context.nil?
|
582
|
+
context
|
583
|
+
else
|
584
|
+
log_debug("expand", depth: log_depth.to_i) {"id_context: #{id_context.inspect}"}
|
585
|
+
context.parse(id_context, base: @options[:base], propagate: false)
|
586
|
+
end
|
521
587
|
else
|
522
588
|
context
|
523
589
|
end
|
524
590
|
|
525
591
|
# For each key-value in the object:
|
526
|
-
keys = ordered ? value.keys.sort : value.keys
|
592
|
+
keys = @options[:ordered] ? value.keys.sort : value.keys
|
527
593
|
keys.each do |k|
|
528
594
|
# If container mapping in the active context includes @type, and k is a term in the active context having a local context, use that context when expanding values
|
529
595
|
map_context = container_context.term_definitions[k].context if container.include?('@type') && container_context.term_definitions[k]
|
530
|
-
map_context
|
596
|
+
unless map_context.nil?
|
597
|
+
log_debug("expand", depth: log_depth.to_i) {"map_context: #{map_context.inspect}"}
|
598
|
+
map_context = container_context.parse(map_context, base: @options[:base],
|
599
|
+
propagate: false)
|
600
|
+
end
|
531
601
|
map_context ||= container_context
|
532
602
|
|
533
|
-
expanded_k = container_context.expand_iri(k, vocab: true, as_string: true)
|
603
|
+
expanded_k = container_context.expand_iri(k, vocab: true, as_string: true, base: @options[:base])
|
534
604
|
|
535
605
|
# Initialize index value to the result of using this algorithm recursively, passing active context, key as active property, and index value as element.
|
536
|
-
index_value = expand([value[k]].flatten, key, map_context,
|
606
|
+
index_value = expand([value[k]].flatten, key, map_context,
|
607
|
+
framing: framing,
|
608
|
+
from_map: true,
|
609
|
+
log_depth: log_depth.to_i + 1)
|
537
610
|
index_value.each do |item|
|
538
611
|
case
|
539
612
|
when container.include?('@index')
|
@@ -547,8 +620,8 @@ module JSON::LD
|
|
547
620
|
raise JsonLdError::InvalidValueObject, "Attempt to add illegal key to value object: #{index_key}"
|
548
621
|
else
|
549
622
|
# Expand key based on term
|
550
|
-
expanded_k = k == '@none' ? '@none' : container_context.expand_value(index_key, k)
|
551
|
-
index_property = container_context.expand_iri(index_key, vocab: true, as_string: true)
|
623
|
+
expanded_k = k == '@none' ? '@none' : container_context.expand_value(index_key, k, base: @options[:base])
|
624
|
+
index_property = container_context.expand_iri(index_key, vocab: true, as_string: true, base: @options[:base])
|
552
625
|
item[index_property] = [expanded_k].concat(Array(item[index_property])) unless expanded_k == '@none'
|
553
626
|
end
|
554
627
|
when container.include?('@id')
|
@@ -557,7 +630,7 @@ module JSON::LD
|
|
557
630
|
item = {'@graph' => as_array(item)}
|
558
631
|
end
|
559
632
|
# Expand k document relative
|
560
|
-
expanded_k = container_context.expand_iri(k,
|
633
|
+
expanded_k = container_context.expand_iri(k, as_string: true, base: @options[:base], documentRelative: true) unless expanded_k == '@none'
|
561
634
|
item['@id'] ||= expanded_k unless expanded_k == '@none'
|
562
635
|
when container.include?('@type')
|
563
636
|
item['@type'] = [expanded_k].concat(Array(item['@type'])) unless expanded_k == '@none'
|
@@ -570,26 +643,28 @@ module JSON::LD
|
|
570
643
|
ary
|
571
644
|
else
|
572
645
|
# Otherwise, initialize expanded value to the result of using this algorithm recursively, passing active context, key for active property, and value for element.
|
573
|
-
expand(value, key, context,
|
646
|
+
expand(value, key, context,
|
647
|
+
framing: framing,
|
648
|
+
log_depth: log_depth.to_i + 1)
|
574
649
|
end
|
575
650
|
|
576
651
|
# If expanded value is null, ignore key by continuing to the next key from element.
|
577
652
|
if expanded_value.nil?
|
578
|
-
#log_debug(" => skip nil value")
|
653
|
+
#log_debug(" => skip nil value", depth: log_depth.to_i)
|
579
654
|
next
|
580
655
|
end
|
581
|
-
#log_debug {" => #{expanded_value.inspect}"}
|
656
|
+
#log_debug(depth: log_depth.to_i) {" => #{expanded_value.inspect}"}
|
582
657
|
|
583
658
|
# If the container mapping associated to key in active context is @list and expanded value is not already a list object, convert expanded value to a list object by first setting it to an array containing only expanded value if it is not already an array, and then by setting it to a JSON object containing the key-value pair @list-expanded value.
|
584
659
|
if container.first == '@list' && container.length == 1 && !list?(expanded_value)
|
585
|
-
#log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
|
660
|
+
#log_debug(" => ", depth: log_depth.to_i) { "convert #{expanded_value.inspect} to list"}
|
586
661
|
expanded_value = {'@list' => as_array(expanded_value)}
|
587
662
|
end
|
588
|
-
#log_debug {" => #{expanded_value.inspect}"}
|
663
|
+
#log_debug(depth: log_depth.to_i) {" => #{expanded_value.inspect}"}
|
589
664
|
|
590
665
|
# convert expanded value to @graph if container specifies it
|
591
666
|
if container.first == '@graph' && container.length == 1
|
592
|
-
#log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
|
667
|
+
#log_debug(" => ", depth: log_depth.to_i) { "convert #{expanded_value.inspect} to list"}
|
593
668
|
expanded_value = as_array(expanded_value).map do |v|
|
594
669
|
{'@graph' => as_array(v)}
|
595
670
|
end
|
@@ -625,16 +700,24 @@ module JSON::LD
|
|
625
700
|
|
626
701
|
# For each key in nests, recusively expand content
|
627
702
|
nests.each do |key|
|
703
|
+
nest_context = context.term_definitions[key].context if context.term_definitions[key]
|
704
|
+
nest_context = if nest_context.nil?
|
705
|
+
context
|
706
|
+
else
|
707
|
+
log_debug("expand", depth: log_depth.to_i) {"nest_context: #{nest_context.inspect}"}
|
708
|
+
context.parse(nest_context, base: @options[:base],
|
709
|
+
override_protected: true)
|
710
|
+
end
|
628
711
|
nested_values = as_array(input[key])
|
629
712
|
nested_values.each do |nv|
|
630
713
|
raise JsonLdError::InvalidNestValue, nv.inspect unless
|
631
|
-
nv.is_a?(Hash) && nv.keys.none? {|k|
|
632
|
-
expand_object(nv, active_property,
|
714
|
+
nv.is_a?(Hash) && nv.keys.none? {|k| nest_context.expand_iri(k, vocab: true, base: @options[:base]) == '@value'}
|
715
|
+
expand_object(nv, active_property, nest_context, output_object,
|
716
|
+
framing: framing,
|
633
717
|
expanded_active_property: expanded_active_property,
|
634
|
-
type_scoped_context: type_scoped_context,
|
635
718
|
type_key: type_key,
|
636
|
-
|
637
|
-
|
719
|
+
type_scoped_context: type_scoped_context,
|
720
|
+
log_depth: log_depth.to_i + 1)
|
638
721
|
end
|
639
722
|
end
|
640
723
|
end
|