json-ld 2.1.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/json/ld.rb +1 -1
- data/lib/json/ld/api.rb +49 -44
- data/lib/json/ld/compact.rb +4 -4
- data/lib/json/ld/context.rb +20 -8
- data/lib/json/ld/expand.rb +73 -26
- data/lib/json/ld/flatten.rb +31 -2
- data/lib/json/ld/format.rb +4 -4
- data/lib/json/ld/frame.rb +182 -64
- data/lib/json/ld/streaming_writer.rb +1 -1
- data/lib/json/ld/to_rdf.rb +1 -1
- data/lib/json/ld/utils.rb +10 -1
- data/spec/context_spec.rb +20 -7
- data/spec/expand_spec.rb +19 -0
- data/spec/format_spec.rb +6 -6
- data/spec/frame_spec.rb +1250 -501
- data/spec/suite_helper.rb +1 -1
- metadata +27 -27
- data/spec/test-files/test-1-automatic.json +0 -10
- data/spec/test-files/test-2-automatic.json +0 -27
- data/spec/test-files/test-4-automatic.json +0 -10
- data/spec/test-files/test-5-automatic.json +0 -13
- data/spec/test-files/test-6-automatic.json +0 -10
- data/spec/test-files/test-7-automatic.json +0 -20
- data/spec/test-files/test-8-automatic.json +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb9297e31b76d1e901ae278f349ed412086831f5
|
4
|
+
data.tar.gz: e07e7aeb8bb57349e5f819da903fb55524c46b43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7baea9184fa7cea017a37cb7ec2aa2a4a4b18e153b6a771a8b5297bfe518ca669a66e9a84dc5e37dd04e1b135653ff9195f4b6fb56d48af1a835f1290f8862dd
|
7
|
+
data.tar.gz: fba430dad035dd6465e07ee94c952bf79c33be220baa642a57e07c8d21cd7aa3431e824c5487c3f3b43f4a23f7b30f55c62d059e4b6fb5c2ff1ac8828932b86e
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.1
|
data/lib/json/ld.rb
CHANGED
data/lib/json/ld/api.rb
CHANGED
@@ -70,8 +70,10 @@ module JSON::LD
|
|
70
70
|
# A context that is used to initialize the active context when expanding a document.
|
71
71
|
# @option options [Boolean, String, RDF::URI] :flatten
|
72
72
|
# If set to a value that is not `false`, the JSON-LD processor must modify the output of the Compaction Algorithm or the Expansion Algorithm by coalescing all properties associated with each subject via the Flattening Algorithm. The value of `flatten must` be either an _IRI_ value representing the name of the graph to flatten, or `true`. If the value is `true`, then the first graph encountered in the input document is selected and flattened.
|
73
|
-
# @option options [String] :processingMode ("json-ld-1.
|
74
|
-
#
|
73
|
+
# @option options [String] :processingMode ("json-ld-1.1")
|
74
|
+
# Processing mode, json-ld-1.0 or json-ld-1.1. Also can have other values:
|
75
|
+
#
|
76
|
+
# * json-ld-1.1-expand-frame – special frame expansion mode.
|
75
77
|
# @option options [Boolean] :rename_bnodes (true)
|
76
78
|
# Rename bnodes as part of expansion, or keep them the same.
|
77
79
|
# @option options [Boolean] :unique_bnodes (false)
|
@@ -84,9 +86,14 @@ module JSON::LD
|
|
84
86
|
# @yieldparam [API]
|
85
87
|
# @raise [JsonLdError]
|
86
88
|
def initialize(input, context, options = {}, &block)
|
87
|
-
@options = {
|
88
|
-
|
89
|
-
|
89
|
+
@options = {
|
90
|
+
compactArrays: true,
|
91
|
+
rename_bnodes: true,
|
92
|
+
processingMode: "json-ld-1.1",
|
93
|
+
documentLoader: self.class.method(:documentLoader)
|
94
|
+
}
|
95
|
+
@options[:validate] = %w(json-ld-1.0 json-ld-1.1).include?(@options[:processingMode])
|
96
|
+
@options = @options.merge(options)
|
90
97
|
@namer = options[:unique_bnodes] ? BlankNodeUniqer.new : (@options[:rename_bnodes] ? BlankNodeNamer.new("b") : BlankNodeMapper.new)
|
91
98
|
|
92
99
|
# For context via Link header
|
@@ -127,8 +134,7 @@ module JSON::LD
|
|
127
134
|
|
128
135
|
# If not provided, first use context from document, or from a Link header
|
129
136
|
context ||= (@value['@context'] if @value.is_a?(Hash)) || context_ref
|
130
|
-
@context = Context.
|
131
|
-
@context = @context.parse(context) if context
|
137
|
+
@context = Context.parse(context || {}, @options)
|
132
138
|
|
133
139
|
if block_given?
|
134
140
|
case block.arity
|
@@ -150,9 +156,7 @@ module JSON::LD
|
|
150
156
|
# @param [String, #read, Hash, Array] input
|
151
157
|
# The JSON-LD object to copy and perform the expansion upon.
|
152
158
|
# @param [Hash{Symbol => Object}] options
|
153
|
-
#
|
154
|
-
# @option options [String, #read, Hash, Array, JSON::LD::Context] :expandContext
|
155
|
-
# A context that is used to initialize the active context when expanding a document.
|
159
|
+
# @option options (see #initialize)
|
156
160
|
# @raise [JsonLdError]
|
157
161
|
# @yield jsonld
|
158
162
|
# @yieldparam [Array<Hash>] jsonld
|
@@ -164,10 +168,7 @@ module JSON::LD
|
|
164
168
|
def self.expand(input, options = {})
|
165
169
|
result = nil
|
166
170
|
API.new(input, options[:expandContext], options) do |api|
|
167
|
-
result = api.expand(api.value, nil, api.context,
|
168
|
-
ordered: options.fetch(:ordered, true),
|
169
|
-
framing: options.fetch(:framing, false),
|
170
|
-
keep_free_floating_nodes: options.fetch(:keep_free_floating_nodes, false))
|
171
|
+
result = api.expand(api.value, nil, api.context, ordered: options.fetch(:ordered, true))
|
171
172
|
end
|
172
173
|
|
173
174
|
# If, after the algorithm outlined above is run, the resulting element is an
|
@@ -192,8 +193,7 @@ module JSON::LD
|
|
192
193
|
# @param [String, #read, Hash, Array, JSON::LD::Context] context
|
193
194
|
# The base context to use when compacting the input.
|
194
195
|
# @param [Hash{Symbol => Object}] options
|
195
|
-
#
|
196
|
-
# Other options passed to {JSON::LD::API.expand}
|
196
|
+
# @option options (see #initialize)
|
197
197
|
# @option options [Boolean] :expanded Input is already expanded
|
198
198
|
# @yield jsonld
|
199
199
|
# @yieldparam [Hash] jsonld
|
@@ -212,7 +212,7 @@ module JSON::LD
|
|
212
212
|
|
213
213
|
API.new(expanded_input, context, options) do
|
214
214
|
log_debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE) rescue 'malformed json'}"}
|
215
|
-
result = compact(value
|
215
|
+
result = compact(value)
|
216
216
|
|
217
217
|
# xxx) Add the given context to the output
|
218
218
|
ctx = self.context.serialize
|
@@ -235,8 +235,7 @@ module JSON::LD
|
|
235
235
|
# @param [String, #read, Hash, Array, JSON::LD::EvaluationContext] context
|
236
236
|
# An optional external context to use additionally to the context embedded in input when expanding the input.
|
237
237
|
# @param [Hash{Symbol => Object}] options
|
238
|
-
#
|
239
|
-
# Other options passed to {JSON::LD::API.expand}
|
238
|
+
# @option options (see #initialize)
|
240
239
|
# @option options [Boolean] :expanded Input is already expanded
|
241
240
|
# @yield jsonld
|
242
241
|
# @yieldparam [Hash] jsonld
|
@@ -256,12 +255,12 @@ module JSON::LD
|
|
256
255
|
log_debug(".flatten") {"expanded input: #{value.to_json(JSON_STATE) rescue 'malformed json'}"}
|
257
256
|
|
258
257
|
# Initialize node map to a JSON object consisting of a single member whose key is @default and whose value is an empty JSON object.
|
259
|
-
|
260
|
-
create_node_map(value,
|
258
|
+
graph_maps = {'@default' => {}}
|
259
|
+
create_node_map(value, graph_maps)
|
261
260
|
|
262
|
-
default_graph =
|
263
|
-
|
264
|
-
graph =
|
261
|
+
default_graph = graph_maps['@default']
|
262
|
+
graph_maps.keys.kw_sort.reject {|k| k == '@default'}.each do |graph_name|
|
263
|
+
graph = graph_maps[graph_name]
|
265
264
|
entry = default_graph[graph_name] ||= {'@id' => graph_name}
|
266
265
|
nodes = entry['@graph'] ||= []
|
267
266
|
graph.keys.kw_sort.each do |id|
|
@@ -274,7 +273,7 @@ module JSON::LD
|
|
274
273
|
|
275
274
|
if context && !flattened.empty?
|
276
275
|
# Otherwise, return the result of compacting flattened according the Compaction algorithm passing context ensuring that the compaction result uses the @graph keyword (or its alias) at the top-level, even if the context is empty or if there is only one element to put in the @graph array. This ensures that the returned document has a deterministic structure.
|
277
|
-
compacted = compact(flattened
|
276
|
+
compacted = compact(flattened)
|
278
277
|
compacted = [compacted] unless compacted.is_a?(Array)
|
279
278
|
kwgraph = self.context.compact_iri('@graph', quiet: true)
|
280
279
|
flattened = self.context.serialize.merge(kwgraph => compacted)
|
@@ -295,9 +294,7 @@ module JSON::LD
|
|
295
294
|
# The JSON-LD object to copy and perform the framing on.
|
296
295
|
# @param [String, #read, Hash, Array] frame
|
297
296
|
# The frame to use when re-arranging the data.
|
298
|
-
# @
|
299
|
-
# See options in {JSON::LD::API#initialize}
|
300
|
-
# Other options passed to {JSON::LD::API.expand}
|
297
|
+
# @option options (see #initialize)
|
301
298
|
# @option options ['@last', '@always', '@never', '@link'] :embed ('@last')
|
302
299
|
# a flag specifying that objects should be directly embedded in the output,
|
303
300
|
# instead of being referred to by their IRI.
|
@@ -305,6 +302,9 @@ module JSON::LD
|
|
305
302
|
# a flag specifying that for properties to be included in the output,
|
306
303
|
# they must be explicitly declared in the framing context.
|
307
304
|
# @option options [Boolean] :requireAll (true)
|
305
|
+
# A flag specifying that all properties present in the input frame must
|
306
|
+
# either have a default value or be present in the JSON-LD input for the
|
307
|
+
# frame to match.
|
308
308
|
# @option options [Boolean] :omitDefault (false)
|
309
309
|
# a flag specifying that properties that are missing from the JSON-LD
|
310
310
|
# input should be omitted from the output.
|
@@ -330,7 +330,8 @@ module JSON::LD
|
|
330
330
|
}.merge!(options)
|
331
331
|
|
332
332
|
framing_state = {
|
333
|
-
|
333
|
+
graphMap: {},
|
334
|
+
graphStack: [],
|
334
335
|
subjectStack: [],
|
335
336
|
link: {},
|
336
337
|
}
|
@@ -351,17 +352,27 @@ module JSON::LD
|
|
351
352
|
expanded_input = options[:expanded] ? input : API.expand(input, options)
|
352
353
|
|
353
354
|
# Expand frame to simplify processing
|
354
|
-
expanded_frame = API.expand(frame, options.merge(
|
355
|
+
expanded_frame = API.expand(frame, options.merge(processingMode: "json-ld-1.1-expand-frame"))
|
355
356
|
|
356
357
|
# Initialize input using frame as context
|
357
358
|
API.new(expanded_input, nil, options) do
|
358
359
|
log_debug(".frame") {"expanded frame: #{expanded_frame.to_json(JSON_STATE) rescue 'malformed json'}"}
|
359
360
|
|
360
361
|
# Get framing nodes from expanded input, replacing Blank Node identifiers as necessary
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
362
|
+
create_node_map(value, framing_state[:graphMap], graph: '@default')
|
363
|
+
|
364
|
+
frame_keys = frame.keys.map {|k| context.expand_iri(k, vocab: true, quiet: true)}
|
365
|
+
if frame_keys.include?('@graph')
|
366
|
+
# If frame contains @graph, it matches the default graph.
|
367
|
+
framing_state[:graph] = '@default'
|
368
|
+
else
|
369
|
+
# If frame does not contain @graph used the merged graph.
|
370
|
+
framing_state[:graph] = '@merged'
|
371
|
+
framing_state[:link]['@merged'] = {}
|
372
|
+
framing_state[:graphMap]['@merged'] = merge_node_map_graphs(framing_state[:graphMap])
|
373
|
+
end
|
374
|
+
|
375
|
+
framing_state[:subjects] = framing_state[:graphMap][framing_state[:graph]]
|
365
376
|
|
366
377
|
result = []
|
367
378
|
frame(framing_state, framing_state[:subjects].keys.sort, (expanded_frame.first || {}), options.merge(parent: result))
|
@@ -369,7 +380,7 @@ module JSON::LD
|
|
369
380
|
# Initalize context from frame
|
370
381
|
@context = @context.parse(frame['@context'])
|
371
382
|
# Compact result
|
372
|
-
compacted = compact(result
|
383
|
+
compacted = compact(result)
|
373
384
|
compacted = [compacted] unless compacted.is_a?(Array)
|
374
385
|
|
375
386
|
# Add the given context to the output
|
@@ -387,9 +398,7 @@ module JSON::LD
|
|
387
398
|
#
|
388
399
|
# @param [String, #read, Hash, Array] input
|
389
400
|
# The JSON-LD object to process when outputting statements.
|
390
|
-
# @
|
391
|
-
# See options in {JSON::LD::API#initialize}
|
392
|
-
# Options passed to {JSON::LD::API.expand}
|
401
|
+
# @option options (see #initialize)
|
393
402
|
# @option options [Boolean] :produceGeneralizedRdf (false)
|
394
403
|
# If true, output will include statements having blank node predicates, otherwise they are dropped.
|
395
404
|
# @option options [Boolean] :expanded Input is already expanded
|
@@ -449,7 +458,7 @@ module JSON::LD
|
|
449
458
|
#
|
450
459
|
# @param [Array<RDF::Statement>] input
|
451
460
|
# @param [Hash{Symbol => Object}] options
|
452
|
-
#
|
461
|
+
# @option options (see #initialize)
|
453
462
|
# @option options [Boolean] :useRdfType (false)
|
454
463
|
# If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
|
455
464
|
# @yield jsonld
|
@@ -488,7 +497,7 @@ module JSON::LD
|
|
488
497
|
# If the passed input is a DOMString representing the IRI of a remote document, dereference it. If the retrieved document's content type is neither application/json, nor application/ld+json, nor any other media type using a +json suffix as defined in [RFC6839], reject the promise passing an loading document failed error.
|
489
498
|
if content_type && options[:validate]
|
490
499
|
main, sub = content_type.split("/")
|
491
|
-
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
500
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "url: #{url}, content_type: #{content_type}" if
|
492
501
|
main != 'application' ||
|
493
502
|
sub !~ /^(.*\+)?json$/
|
494
503
|
end
|
@@ -523,10 +532,6 @@ module JSON::LD
|
|
523
532
|
def validate_input(input)
|
524
533
|
return unless defined?(JsonLint)
|
525
534
|
jsonlint = JsonLint::Linter.new
|
526
|
-
unless jsonlint.respond_to?(:check_stream)
|
527
|
-
warn "Skipping jsonlint, use latest version from GiHub until 0.1.1 released"
|
528
|
-
return
|
529
|
-
end
|
530
535
|
input = StringIO.new(input) unless input.respond_to?(:read)
|
531
536
|
unless jsonlint.check_stream(input)
|
532
537
|
raise JsonLdError::LoadingDocumentFailed, jsonlint.errors[''].join("\n")
|
data/lib/json/ld/compact.rb
CHANGED
@@ -10,7 +10,7 @@ module JSON::LD
|
|
10
10
|
# @param [Array, Hash] element
|
11
11
|
# @param [String] property (nil)
|
12
12
|
# @return [Array, Hash]
|
13
|
-
def compact(element, property
|
13
|
+
def compact(element, property: nil)
|
14
14
|
#if property.nil?
|
15
15
|
# log_debug("compact") {"element: #{element.inspect}, ec: #{context.inspect}"}
|
16
16
|
#else
|
@@ -19,7 +19,7 @@ module JSON::LD
|
|
19
19
|
case element
|
20
20
|
when Array
|
21
21
|
#log_debug("") {"Array #{element.inspect}"}
|
22
|
-
result = element.map {|item| compact(item, property)}.compact
|
22
|
+
result = element.map {|item| compact(item, property: property)}.compact
|
23
23
|
|
24
24
|
# If element has a single member and the active property has no
|
25
25
|
# @container mapping to @list or @set, the compacted value is that
|
@@ -65,7 +65,7 @@ module JSON::LD
|
|
65
65
|
end
|
66
66
|
|
67
67
|
if expanded_property == '@reverse'
|
68
|
-
compacted_value = compact(expanded_value, '@reverse')
|
68
|
+
compacted_value = compact(expanded_value, property: '@reverse')
|
69
69
|
#log_debug("@reverse") {"compacted_value: #{compacted_value.inspect}"}
|
70
70
|
compacted_value.each do |prop, value|
|
71
71
|
if context.reverse?(prop)
|
@@ -121,7 +121,7 @@ module JSON::LD
|
|
121
121
|
|
122
122
|
container = context.container(item_active_property)
|
123
123
|
value = list?(expanded_item) ? expanded_item['@list'] : expanded_item
|
124
|
-
compacted_item = compact(value, item_active_property)
|
124
|
+
compacted_item = compact(value, property: item_active_property)
|
125
125
|
#log_debug("") {" => compacted key: #{item_active_property.inspect} for #{compacted_item.inspect}"}
|
126
126
|
|
127
127
|
if list?(expanded_item)
|
data/lib/json/ld/context.rb
CHANGED
@@ -186,6 +186,19 @@ module JSON::LD
|
|
186
186
|
# @return [BlankNodeNamer]
|
187
187
|
attr_accessor :namer
|
188
188
|
|
189
|
+
##
|
190
|
+
# Create a new context by parsing a context.
|
191
|
+
#
|
192
|
+
# @see #initialize
|
193
|
+
# @see #parse
|
194
|
+
# @param [String, #read, Array, Hash, Context] local_context
|
195
|
+
# @raise [JsonLdError]
|
196
|
+
# on a remote context load error, syntax error, or a reference to a term which is not defined.
|
197
|
+
# @return [Context]
|
198
|
+
def self.parse(local_context, **options)
|
199
|
+
self.new(options).parse(local_context)
|
200
|
+
end
|
201
|
+
|
189
202
|
##
|
190
203
|
# Create new evaluation context
|
191
204
|
# @param [Hash] options
|
@@ -204,7 +217,7 @@ module JSON::LD
|
|
204
217
|
# @yield [ec]
|
205
218
|
# @yieldparam [Context]
|
206
219
|
# @return [Context]
|
207
|
-
def initialize(options
|
220
|
+
def initialize(**options)
|
208
221
|
if options[:base]
|
209
222
|
@base = @doc_base = RDF::URI(options[:base]).dup
|
210
223
|
@doc_base.canonicalize! if options[:canonicalize]
|
@@ -298,6 +311,7 @@ module JSON::LD
|
|
298
311
|
# @param [String, #read, Array, Hash, Context] local_context
|
299
312
|
# @raise [JsonLdError]
|
300
313
|
# on a remote context load error, syntax error, or a reference to a term which is not defined.
|
314
|
+
# @return [Context]
|
301
315
|
# @see http://json-ld.org/spec/latest/json-ld-api/index.html#context-processing-algorithm
|
302
316
|
def parse(local_context, remote_contexts = [])
|
303
317
|
result = self.dup
|
@@ -391,9 +405,9 @@ module JSON::LD
|
|
391
405
|
# If context has a @vocab member: if its value is not a valid absolute IRI or null trigger an INVALID_VOCAB_MAPPING error; otherwise set the active context's vocabulary mapping to its value and remove the @vocab member from context.
|
392
406
|
context = context.dup # keep from modifying a hash passed as a param
|
393
407
|
{
|
394
|
-
'@base'
|
408
|
+
'@base' => :base=,
|
395
409
|
'@language' => :default_language=,
|
396
|
-
'@vocab' => :vocab
|
410
|
+
'@vocab' => :vocab=,
|
397
411
|
}.each do |key, setter|
|
398
412
|
v = context.fetch(key, false)
|
399
413
|
unless v == false
|
@@ -797,16 +811,14 @@ module JSON::LD
|
|
797
811
|
#
|
798
812
|
# @param [String] value
|
799
813
|
# A keyword, term, prefix:suffix or possibly relative IRI
|
800
|
-
# @param [Hash{Symbol => Object}] options
|
801
814
|
# @param [Boolean] documentRelative (false)
|
802
815
|
# @param [Boolean] vocab (false)
|
803
|
-
# @param [RDF::URI] base
|
804
816
|
# @param [Hash] local_context
|
805
817
|
# Used during Context Processing.
|
806
818
|
# @param [Hash] defined
|
807
819
|
# Used during Context Processing.
|
808
820
|
# @param [Boolean] quiet (false)
|
809
|
-
# @param
|
821
|
+
# @param [Hash{Symbol => Object}] options
|
810
822
|
# @return [RDF::URI, String]
|
811
823
|
# IRI or String, if it's a keyword
|
812
824
|
# @raise [JSON::LD::JsonLdError::InvalidIRIMapping] if the value cannot be expanded
|
@@ -878,7 +890,7 @@ module JSON::LD
|
|
878
890
|
# @param [RDF::URI] iri
|
879
891
|
# @param [Object] value
|
880
892
|
# Value, used to select among various maps for the same IRI
|
881
|
-
# @param [Boolean]
|
893
|
+
# @param [Boolean] vocab
|
882
894
|
# specifies whether the passed iri should be compacted using the active context's vocabulary mapping
|
883
895
|
# @param [Boolean] reverse
|
884
896
|
# specifies whether a reverse property is being compacted
|
@@ -1193,7 +1205,7 @@ module JSON::LD
|
|
1193
1205
|
defn << "vocab: #{self.vocab.to_s.inspect}" if self.vocab
|
1194
1206
|
term_defs = term_definitions.map do |term, td|
|
1195
1207
|
" " + term.inspect + " => " + td.to_rb
|
1196
|
-
end
|
1208
|
+
end.sort
|
1197
1209
|
defn << "term_definitions: {\n#{term_defs.join(",\n") }\n }" unless term_defs.empty?
|
1198
1210
|
%(# -*- encoding: utf-8 -*-
|
1199
1211
|
# frozen_string_literal: true
|
data/lib/json/ld/expand.rb
CHANGED
@@ -14,10 +14,9 @@ module JSON::LD
|
|
14
14
|
# @param [Context] context
|
15
15
|
# @param [Boolean] ordered (true)
|
16
16
|
# Ensure output objects have keys ordered properly
|
17
|
-
# @
|
18
|
-
|
19
|
-
|
20
|
-
def expand(input, active_property, context, ordered: true, framing: false, keep_free_floating_nodes: false)
|
17
|
+
# @return [Array<Hash{String => Object}>]
|
18
|
+
def expand(input, active_property, context, ordered: true)
|
19
|
+
framing = @options[:processingMode].include?("expand-frame")
|
21
20
|
#log_debug("expand") {"input: #{input.inspect}, active_property: #{active_property.inspect}, context: #{context.inspect}"}
|
22
21
|
result = case input
|
23
22
|
when Array
|
@@ -73,18 +72,37 @@ module JSON::LD
|
|
73
72
|
expanded_value = case expanded_property
|
74
73
|
when '@id'
|
75
74
|
# If expanded property is @id and value is not a string, an invalid @id value error has been detected and processing is aborted
|
76
|
-
case value
|
75
|
+
e_id = case value
|
77
76
|
when String
|
77
|
+
context.expand_iri(value, documentRelative: true, log_depth: @options[:log_depth]).to_s
|
78
|
+
when Array
|
79
|
+
# Framing allows an array of IRIs, and always puts values in an array
|
80
|
+
raise JsonLdError::InvalidIdValue,
|
81
|
+
"value of @id must be a string, array of string or hash if framing: #{value.inspect}" unless framing
|
82
|
+
context.expand_iri(value, documentRelative: true, log_depth: @options[:log_depth]).to_s
|
83
|
+
value.map do |v|
|
84
|
+
raise JsonLdError::InvalidTypeValue,
|
85
|
+
"@id value must be a string or array of strings for framing: #{v.inspect}" unless v.is_a?(String)
|
86
|
+
context.expand_iri(v, documentRelative: true, quiet: true, log_depth: @options[:log_depth]).to_s
|
87
|
+
end
|
78
88
|
when Hash
|
79
89
|
raise JsonLdError::InvalidIdValue,
|
80
90
|
"value of @id must be a string unless framing: #{value.inspect}" unless framing
|
91
|
+
raise JsonLdError::InvalidTypeValue,
|
92
|
+
"value of @id must be a an empty object for framing: #{value.inspect}" unless
|
93
|
+
value.empty? && framing
|
94
|
+
[{}]
|
81
95
|
else
|
82
96
|
raise JsonLdError::InvalidIdValue,
|
83
97
|
"value of @id must be a string or hash if framing: #{value.inspect}"
|
84
98
|
end
|
85
99
|
|
86
|
-
#
|
87
|
-
|
100
|
+
# Use array form if framing
|
101
|
+
if framing && !e_id.is_a?(Array)
|
102
|
+
[e_id]
|
103
|
+
else
|
104
|
+
e_id
|
105
|
+
end
|
88
106
|
when '@type'
|
89
107
|
# 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.
|
90
108
|
#log_debug("@type") {"value: #{value.inspect}"}
|
@@ -101,28 +119,55 @@ module JSON::LD
|
|
101
119
|
# For framing
|
102
120
|
raise JsonLdError::InvalidTypeValue,
|
103
121
|
"@type value must be a an empty object for framing: #{value.inspect}" unless
|
104
|
-
value.empty?
|
122
|
+
value.empty? && framing
|
123
|
+
[{}]
|
105
124
|
else
|
106
125
|
raise JsonLdError::InvalidTypeValue,
|
107
126
|
"@type value must be a string or array of strings: #{value.inspect}"
|
108
127
|
end
|
109
128
|
when '@graph'
|
110
129
|
# 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.
|
111
|
-
expand(value, '@graph', context, ordered: ordered)
|
130
|
+
value = expand(value, '@graph', context, ordered: ordered)
|
131
|
+
value.is_a?(Array) ? value : [value]
|
112
132
|
when '@value'
|
113
133
|
# If expanded property is @value and value is not a scalar or null, an invalid value object value error has been detected and processing is aborted. Otherwise, set expanded value to value. If expanded value is null, set the @value member of result to null and continue with the next key from element. Null values need to be preserved in this case as the meaning of an @type member depends on the existence of an @value member.
|
114
|
-
|
115
|
-
|
116
|
-
|
134
|
+
# If framing, always use array form, unless null
|
135
|
+
case value
|
136
|
+
when String, TrueClass, FalseClass, Numeric then (framing ? [value] : value)
|
137
|
+
when nil
|
117
138
|
output_object['@value'] = nil
|
118
139
|
next;
|
140
|
+
when Array
|
141
|
+
raise JsonLdError::InvalidValueObjectValue,
|
142
|
+
"@value value may not be an array unless framing: #{value.inspect}" unless framing
|
143
|
+
value
|
144
|
+
when Hash
|
145
|
+
raise JsonLdError::InvalidValueObjectValue,
|
146
|
+
"@value value must be a an empty object for framing: #{value.inspect}" unless
|
147
|
+
value.empty? && framing
|
148
|
+
[value]
|
149
|
+
else
|
150
|
+
raise JsonLdError::InvalidValueObjectValue,
|
151
|
+
"Value of #{expanded_property} must be a scalar or null: #{value.inspect}"
|
119
152
|
end
|
120
|
-
value
|
121
153
|
when '@language'
|
122
154
|
# If expanded property is @language and value is not a string, an invalid language-tagged string error has been detected and processing is aborted. Otherwise, set expanded value to lowercased value.
|
123
|
-
|
124
|
-
|
125
|
-
value.downcase
|
155
|
+
# If framing, always use array form, unless null
|
156
|
+
case value
|
157
|
+
when String then (framing ? [value.downcase] : value.downcase)
|
158
|
+
when Array
|
159
|
+
raise JsonLdError::InvalidLanguageTaggedString,
|
160
|
+
"@language value may not be an array unless framing: #{value.inspect}" unless framing
|
161
|
+
value.map(&:downcase)
|
162
|
+
when Hash
|
163
|
+
raise JsonLdError::InvalidLanguageTaggedString,
|
164
|
+
"@language value must be a an empty object for framing: #{value.inspect}" unless
|
165
|
+
value.empty? && framing
|
166
|
+
[value]
|
167
|
+
else
|
168
|
+
raise JsonLdError::InvalidLanguageTaggedString,
|
169
|
+
"Value of #{expanded_property} must be a string: #{value.inspect}"
|
170
|
+
end
|
126
171
|
when '@index'
|
127
172
|
# If expanded property is @index and value is not a string, an invalid @index value error has been detected and processing is aborted. Otherwise, set expanded value to value.
|
128
173
|
raise JsonLdError::InvalidIndexValue,
|
@@ -186,7 +231,8 @@ module JSON::LD
|
|
186
231
|
|
187
232
|
# Continue with the next key from element
|
188
233
|
next
|
189
|
-
when '@
|
234
|
+
when '@default', '@embed', '@explicit', '@omitDefault', '@preserve', '@requireAll'
|
235
|
+
next unless framing
|
190
236
|
# Framing keywords
|
191
237
|
[expand(value, expanded_property, context, ordered: ordered)].flatten
|
192
238
|
else
|
@@ -291,21 +337,22 @@ module JSON::LD
|
|
291
337
|
"value object has unknown keys: #{output_object.inspect}"
|
292
338
|
end
|
293
339
|
|
294
|
-
output_object.delete('@language') if output_object['@language'].to_s.empty?
|
295
|
-
output_object.delete('@type') if output_object['@type'].to_s.empty?
|
340
|
+
output_object.delete('@language') if Array(output_object['@language']).join('').to_s.empty?
|
341
|
+
output_object.delete('@type') if Array(output_object['@type']).join('').to_s.empty?
|
296
342
|
|
297
343
|
# If the value of result's @value key is null, then set result to null.
|
298
|
-
return nil if output_object['@value'].
|
344
|
+
return nil if Array(output_object['@value']).empty?
|
299
345
|
|
300
|
-
if !output_object['@value'].is_a?(String) && output_object.has_key?('@language')
|
346
|
+
if !Array(output_object['@value']).all? {|v| v.is_a?(String) || v.is_a?(Hash) && v.empty?} && output_object.has_key?('@language')
|
301
347
|
# 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.
|
302
348
|
raise JsonLdError::InvalidLanguageTaggedValue,
|
303
|
-
"when @language is used, @value must be a string: #{
|
304
|
-
elsif !output_object.fetch('@type', "").
|
305
|
-
|
349
|
+
"when @language is used, @value must be a string: #{output_object.inspect}"
|
350
|
+
elsif !Array(output_object.fetch('@type', "")).all? {|t|
|
351
|
+
t.is_a?(String) && context.expand_iri(t, vocab: true, log_depth: @options[:log_depth]).is_a?(RDF::URI) ||
|
352
|
+
t.is_a?(Hash) && t.empty?}
|
306
353
|
# 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.
|
307
354
|
raise JsonLdError::InvalidTypedValue,
|
308
|
-
"value of @type must be an IRI: #{output_object
|
355
|
+
"value of @type must be an IRI: #{output_object.inspect}"
|
309
356
|
end
|
310
357
|
elsif !output_object.fetch('@type', []).is_a?(Array)
|
311
358
|
# Otherwise, if result contains the key @type and its associated value is not an array, set it to an array containing only the associated value.
|
@@ -327,7 +374,7 @@ module JSON::LD
|
|
327
374
|
# If active property is null or @graph, drop free-floating values as follows:
|
328
375
|
if (active_property || '@graph') == '@graph' &&
|
329
376
|
(output_object.keys.any? {|k| %w(@value @list).include?(k)} ||
|
330
|
-
(output_object.keys - %w(@id)).empty? && !
|
377
|
+
(output_object.keys - %w(@id)).empty? && !framing)
|
331
378
|
#log_debug(" =>") { "empty top-level: " + output_object.inspect}
|
332
379
|
return nil
|
333
380
|
end
|