@@ -71,6 +71,8 @@ class API
71
71
# A context that is used to initialize the active context when expanding a document.
72
72
# @option options [Boolean, String, RDF::URI] :flatten
73
73
# 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.
74
+ # @option options [String] :language
75
+ # When set, this has the effect of inserting a context definition with `@language` set to the associated value, creating a default language for interpreting string values.
74
76
# @option options [String] :processingMode
75
77
# Processing mode, json-ld-1.0 or json-ld-1.1.
76
78
# If `processingMode` is not specified, a mode of `json-ld-1.0` or `json-ld-1.1` is set, the context used for `expansion` or `compaction`.
@@ -80,12 +82,15 @@ class API
80
82
# Use unique bnode identifiers, defaults to using the identifier which the node was originally initialized with (if any).
81
83
# @option options [Symbol] :adapter used with MultiJson
82
84
# @option options [Boolean] :validate Validate input, if a string or readable object.
85
+ # @option options [Boolean] :ordered (true)
86
+ # Order traversal of dictionary members by key when performing algorithms.
83
87
# @yield [api]
84
88
# @yieldparam [API]
85
89
# @raise [JsonLdError]
86
90
def initialize ( input , context , rename_bnodes : true , unique_bnodes : false , **options , &block )
87
91
@options = {
88
92
compactArrays : true ,
93
+ ordered : false ,
89
94
documentLoader : self . class . method ( :documentLoader )
90
95
} . merge ( options )
91
96
@namer = unique_bnodes ? BlankNodeUniqer . new : ( rename_bnodes ? BlankNodeNamer . new ( "b" ) : BlankNodeMapper . new )
@@ -161,11 +166,11 @@ def initialize(input, context, rename_bnodes: true, unique_bnodes: false, **opti
161
166
# @return [Object, Array<Hash>]
162
167
# If a block is given, the result of evaluating the block is returned, otherwise, the expanded JSON-LD document
163
168
# @see http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm
164
- def self . expand ( input , ordered : true , framing : false , **options , &block )
169
+ def self . expand ( input , framing : false , **options , &block )
165
170
result , doc_base = nil
166
171
API . new ( input , options [ :expandContext ] , options ) do
167
172
result = self . expand ( self . value , nil , self . context ,
168
- ordered : ordered ,
173
+ ordered : @options [ : ordered] ,
169
174
framing : framing )
170
175
doc_base = @options [ :base ]
171
176
end
@@ -216,14 +221,14 @@ def self.compact(input, context, expanded: false, **options)
216
221
217
222
# 1) Perform the Expansion Algorithm on the JSON-LD input.
218
223
# This removes any existing context to allow the given context to be cleanly applied.
219
- expanded_input = expanded ? input : API . expand ( input , options ) do |res , base_iri |
224
+ expanded_input = expanded ? input : API . expand ( input , options . merge ( ordered : false ) ) do |res , base_iri |
220
225
options [ :base ] ||= base_iri if options [ :compactToRelative ]
221
226
res
222
227
end
223
228
224
229
API . new ( expanded_input , context , no_default_base : true , **options ) do
225
230
log_debug ( ".compact" ) { "expanded input: #{ expanded_input . to_json ( JSON_STATE ) rescue 'malformed json' } " }
226
- result = compact ( value )
231
+ result = compact ( value , ordered : @options [ :ordered ] )
227
232
228
233
# xxx) Add the given context to the output
229
234
ctx = self . context . serialize
@@ -274,23 +279,23 @@ def self.flatten(input, context, expanded: false, **options)
274
279
create_node_map ( value , graph_maps )
275
280
276
281
default_graph = graph_maps [ '@default' ]
277
- graph_maps . keys . sort . each do |graph_name |
282
+ graph_maps . keys . opt_sort ( ordered : @options [ :ordered ] ) . each do |graph_name |
278
283
next if graph_name == '@default'
279
284
280
285
graph = graph_maps [ graph_name ]
281
286
entry = default_graph [ graph_name ] ||= { '@id' => graph_name }
282
287
nodes = entry [ '@graph' ] ||= [ ]
283
- graph . keys . sort . each do |id |
288
+ graph . keys . opt_sort ( ordered : @options [ :ordered ] ) . each do |id |
284
289
nodes << graph [ id ] unless node_reference? ( graph [ id ] )
285
290
end
286
291
end
287
- default_graph . keys . sort . each do |id |
292
+ default_graph . keys . opt_sort ( ordered : @options [ :ordered ] ) . each do |id |
288
293
flattened << default_graph [ id ] unless node_reference? ( default_graph [ id ] )
289
294
end
290
295
291
296
if context && !flattened . empty?
292
297
# 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.
293
- compacted = as_array ( compact ( flattened ) )
298
+ compacted = as_array ( compact ( flattened , ordered : @options [ :ordered ] ) )
294
299
kwgraph = self . context . compact_iri ( '@graph' , quiet : true )
295
300
flattened = self . context . serialize . merge ( kwgraph => compacted )
296
301
end
@@ -337,7 +342,6 @@ def self.frame(input, frame, expanded: false, **options)
337
342
explicit : false ,
338
343
requireAll : true ,
339
344
omitDefault : false ,
340
- omitGraph : false ,
341
345
documentLoader : method ( :documentLoader )
342
346
} . merge ( options )
343
347
@@ -361,19 +365,24 @@ def self.frame(input, frame, expanded: false, **options)
361
365
end
362
366
363
367
# Expand input to simplify processing
364
- expanded_input = expanded ? input : API . expand ( input , options ) do |res , base_iri |
368
+ expanded_input = expanded ? input : API . expand ( input , options . merge ( ordered : false ) ) do |res , base_iri |
365
369
options [ :base ] ||= base_iri if options [ :compactToRelative ]
366
370
res
367
371
end
368
372
369
373
# Expand frame to simplify processing
370
- expanded_frame = API . expand ( frame , framing : true , ** options )
374
+ expanded_frame = API . expand ( frame , options . merge ( framing : true , ordered : false ) )
371
375
372
376
# Initialize input using frame as context
373
377
API . new ( expanded_input , frame [ '@context' ] , no_default_base : true , **options ) do
374
378
log_debug ( ".frame" ) { "expanded input: #{ expanded_input . to_json ( JSON_STATE ) rescue 'malformed json' } " }
375
379
log_debug ( ".frame" ) { "expanded frame: #{ expanded_frame . to_json ( JSON_STATE ) rescue 'malformed json' } " }
376
380
381
+ # Set omitGraph option, if not present, based on processingMode
382
+ unless options . has_key? ( :omitGraph )
383
+ options [ :omitGraph ] = @options [ :processingMode ] != 'json-ld-1.0'
384
+ end
385
+
377
386
# Get framing nodes from expanded input, replacing Blank Node identifiers as necessary
378
387
create_node_map ( value , framing_state [ :graphMap ] , active_graph : '@default' )
379
388
@@ -391,7 +400,7 @@ def self.frame(input, frame, expanded: false, **options)
391
400
framing_state [ :subjects ] = framing_state [ :graphMap ] [ framing_state [ :graph ] ]
392
401
393
402
result = [ ]
394
- frame ( framing_state , framing_state [ :subjects ] . keys . sort , ( expanded_frame . first || { } ) , parent : result , **options )
403
+ frame ( framing_state , framing_state [ :subjects ] . keys . opt_sort ( ordered : @options [ :ordered ] ) , ( expanded_frame . first || { } ) , parent : result , **options )
395
404
396
405
# Count blank node identifiers used in the document, if pruning
397
406
unless @options [ :processingMode ] == 'json-ld-1.0'
@@ -402,7 +411,7 @@ def self.frame(input, frame, expanded: false, **options)
402
411
# Initalize context from frame
403
412
@context = @context . parse ( frame [ '@context' ] )
404
413
# Compact result
405
- compacted = compact ( result )
414
+ compacted = compact ( result , ordered : @options [ :ordered ] )
406
415
compacted = [ compacted ] unless options [ :omitGraph ] || compacted . is_a? ( Array )
407
416
408
417
# Add the given context to the output
@@ -443,7 +452,7 @@ def self.toRdf(input, expanded: false, **options, &block)
443
452
end
444
453
445
454
# Expand input to simplify processing
446
- expanded_input = expanded ? input : API . expand ( input , ordered : false , ** options )
455
+ expanded_input = expanded ? input : API . expand ( input , options . merge ( ordered : false ) )
447
456
448
457
API . new ( expanded_input , nil , options ) do
449
458
# 1) Perform the Expansion Algorithm on the JSON-LD input.
@@ -487,8 +496,11 @@ def self.toRdf(input, expanded: false, **options, &block)
487
496
def self . fromRdf ( input , useRdfType : false , useNativeTypes : false , **options , &block )
488
497
result = nil
489
498
490
- API . new ( nil , nil , options ) do |api |
491
- result = api . from_statements ( input , useRdfType : useRdfType , useNativeTypes : useNativeTypes )
499
+ API . new ( nil , nil , options ) do
500
+ result = from_statements ( input ,
501
+ useRdfType : useRdfType ,
502
+ useNativeTypes : useNativeTypes ,
503
+ ordered : @options [ :ordered ] )
492
504
end
493
505
494
506
block_given? ? yield ( result ) : result
0 commit comments