@@ -63,6 +63,8 @@ class API
63
63
# The Base IRI to use when expanding the document. This overrides the value of `input` if it is a _IRI_. If not specified and `input` is not an _IRI_, the base IRI defaults to the current document IRI if in a browser context, or the empty string if there is no document context. If not specified, and a base IRI is found from `input`, options[:base] will be modified with this value.
64
64
# @option options [Boolean] :compactArrays (true)
65
65
# If set to `true`, the JSON-LD processor replaces arrays with just one element with that element during compaction. If set to `false`, all arrays will remain arrays even if they have just one element.
66
+ # @option options [Boolean] :compactToRelative (true)
67
+ # Creates document relative IRIs when compacting, if `true`, otherwise leaves expanded.
66
68
# @option options [Proc] :documentLoader
67
69
# The callback of the loader to be used to retrieve remote documents and contexts. If specified, it must be used to retrieve remote documents and contexts; otherwise, if not specified, the processor's built-in loader must be used. See {documentLoader} for the method signature.
68
70
# @option options [String, #read, Hash, Array, JSON::LD::Context] :expandContext
@@ -79,29 +81,26 @@ class API
79
81
# Rename bnodes as part of expansion, or keep them the same.
80
82
# @option options [Boolean] :unique_bnodes (false)
81
83
# Use unique bnode identifiers, defaults to using the identifier which the node was originally initialized with (if any).
82
- # @option options [Boolean] :simple_compact_iris (false)
83
- # When compacting IRIs, do not use terms with expanded term definitions
84
84
# @option options [Symbol] :adapter used with MultiJson
85
85
# @option options [Boolean] :validate Validate input, if a string or readable object.
86
86
# @yield [api]
87
87
# @yieldparam [API]
88
88
# @raise [JsonLdError]
89
89
def initialize ( input , context , options = { } , &block )
90
90
@options = {
91
- compactArrays : true ,
92
- rename_bnodes : true ,
93
- documentLoader : self . class . method ( :documentLoader )
94
- }
95
- @options = @options . merge ( options )
91
+ compactArrays : true ,
92
+ rename_bnodes : true ,
93
+ documentLoader : self . class . method ( :documentLoader )
94
+ } . merge ( options )
96
95
@namer = options [ :unique_bnodes ] ? BlankNodeUniqer . new : ( @options [ :rename_bnodes ] ? BlankNodeNamer . new ( "b" ) : BlankNodeMapper . new )
97
96
98
97
# For context via Link header
99
- context_ref = nil
98
+ remote_base , context_ref = nil , nil
100
99
101
100
@value = case input
102
101
when Array , Hash then input . dup
103
102
when IO , StringIO
104
- @options = { base : input . base_uri } . merge! ( @options ) if input . respond_to? ( :base_uri )
103
+ @options = { base : input . base_uri } . merge ( @options ) if input . respond_to? ( :base_uri )
105
104
106
105
# if input impelements #links, attempt to get a contextUrl from that link
107
106
content_type = input . respond_to? ( :content_type ) ? input . content_type : "application/json"
@@ -116,8 +115,9 @@ def initialize(input, context, options = {}, &block)
116
115
when String
117
116
remote_doc = @options [ :documentLoader ] . call ( input , @options )
118
117
119
- @options = { base : remote_doc . documentUrl } . merge! ( @options )
118
+ remote_base = remote_doc . documentUrl
120
119
context_ref = remote_doc . contextUrl
120
+ @options = { base : remote_doc . documentUrl } . merge ( @options ) unless @options [ :no_default_base ]
121
121
122
122
case remote_doc . document
123
123
when String
@@ -128,9 +128,6 @@ def initialize(input, context, options = {}, &block)
128
128
end
129
129
end
130
130
131
- # Update calling context :base option, if not defined
132
- options [ :base ] ||= @options [ :base ] if @options [ :base ]
133
-
134
131
# If not provided, first use context from document, or from a Link header
135
132
context ||= ( @value [ '@context' ] if @value . is_a? ( Hash ) ) || context_ref
136
133
@context = Context . parse ( context || { } , @options )
@@ -160,25 +157,38 @@ def initialize(input, context, options = {}, &block)
160
157
# @param [Hash{Symbol => Object}] options
161
158
# @option options (see #initialize)
162
159
# @raise [JsonLdError]
163
- # @yield jsonld
160
+ # @yield jsonld, base_iri
164
161
# @yieldparam [Array<Hash>] jsonld
165
162
# The expanded JSON-LD document
163
+ # @yieldparam [RDF::URI] base_iri
164
+ # The document base as determined during expansion
166
165
# @yieldreturn [Object] returned object
167
166
# @return [Object, Array<Hash>]
168
167
# If a block is given, the result of evaluating the block is returned, otherwise, the expanded JSON-LD document
169
168
# @see http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm
170
- def self . expand ( input , options = { } )
171
- result = nil
172
- API . new ( input , options [ :expandContext ] , options ) do |api |
173
- result = api . expand ( api . value , nil , api . context , ordered : options . fetch ( :ordered , true ) )
169
+ def self . expand ( input , options = { } , &block )
170
+ result , doc_base = nil
171
+ API . new ( input , options [ :expandContext ] , options ) do
172
+ result = self . expand ( self . value , nil , self . context , ordered : options . fetch ( :ordered , true ) )
173
+ doc_base = @options [ :base ]
174
174
end
175
175
176
176
# If, after the algorithm outlined above is run, the resulting element is an JSON object with just a @graph property, element is set to the value of @graph's value.
177
177
result = result [ '@graph' ] if result . is_a? ( Hash ) && result . keys == %w( @graph )
178
178
179
179
# Finally, if element is a JSON object, it is wrapped into an array.
180
180
result = [ result ] . compact unless result . is_a? ( Array )
181
- block_given? ? yield ( result ) : result
181
+
182
+ if block_given?
183
+ case block . arity
184
+ when 1 then yield ( result )
185
+ when 2 then yield ( result , doc_base )
186
+ else
187
+ raise "Unexpected number of yield parameters to expand"
188
+ end
189
+ else
190
+ result
191
+ end
182
192
end
183
193
184
194
##
@@ -204,13 +214,17 @@ def self.expand(input, options = {})
204
214
# @raise [JsonLdError]
205
215
# @see http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm
206
216
def self . compact ( input , context , options = { } )
207
- expanded = result = nil
217
+ result = nil
218
+ options = { compactToRelative : true } . merge ( options )
208
219
209
220
# 1) Perform the Expansion Algorithm on the JSON-LD input.
210
221
# This removes any existing context to allow the given context to be cleanly applied.
211
- expanded_input = options [ :expanded ] ? input : API . expand ( input , options )
222
+ expanded_input = options [ :expanded ] ? input : API . expand ( input , options ) do |result , base_iri |
223
+ options [ :base ] ||= base_iri if options [ :compactToRelative ]
224
+ result
225
+ end
212
226
213
- API . new ( expanded_input , context , options ) do
227
+ API . new ( expanded_input , context , options . merge ( no_default_base : true ) ) do
214
228
log_debug ( ".compact" ) { "expanded input: #{ expanded_input . to_json ( JSON_STATE ) rescue 'malformed json' } " }
215
229
result = compact ( value )
216
230
@@ -246,12 +260,16 @@ def self.compact(input, context, options = {})
246
260
# @see http://json-ld.org/spec/latest/json-ld-api/#framing-algorithm
247
261
def self . flatten ( input , context , options = { } )
248
262
flattened = [ ]
263
+ options = { compactToRelative : true } . merge ( options )
249
264
250
265
# Expand input to simplify processing
251
- expanded_input = options [ :expanded ] ? input : API . expand ( input , options )
266
+ expanded_input = options [ :expanded ] ? input : API . expand ( input , options ) do |result , base_iri |
267
+ options [ :base ] ||= base_iri if options [ :compactToRelative ]
268
+ result
269
+ end
252
270
253
271
# Initialize input using
254
- API . new ( expanded_input , context , options ) do
272
+ API . new ( expanded_input , context , options . merge ( no_default_base : true ) ) do
255
273
log_debug ( ".flatten" ) { "expanded input: #{ value . to_json ( JSON_STATE ) rescue 'malformed json' } " }
256
274
257
275
# Initialize node map to a JSON object consisting of a single member whose key is @default and whose value is an empty JSON object.
@@ -316,13 +334,14 @@ def self.frame(input, frame, options = {})
316
334
options = {
317
335
base : ( input if input . is_a? ( String ) ) ,
318
336
compactArrays : true ,
337
+ compactToRelative : true ,
319
338
embed : '@last' ,
320
339
explicit : false ,
321
340
requireAll : true ,
322
341
omitDefault : false ,
323
342
pruneBlankNodeIdentifiers : true ,
324
343
documentLoader : method ( :documentLoader )
325
- } . merge! ( options )
344
+ } . merge ( options )
326
345
327
346
framing_state = {
328
347
graphMap : { } ,
@@ -344,13 +363,16 @@ def self.frame(input, frame, options = {})
344
363
end
345
364
346
365
# Expand input to simplify processing
347
- expanded_input = options [ :expanded ] ? input : API . expand ( input , options )
366
+ expanded_input = options [ :expanded ] ? input : API . expand ( input , options ) do |result , base_iri |
367
+ options [ :base ] ||= base_iri if options [ :compactToRelative ]
368
+ result
369
+ end
348
370
349
371
# Expand frame to simplify processing
350
372
expanded_frame = API . expand ( frame , options . merge ( processingMode : "json-ld-1.1-expand-frame" ) )
351
373
352
374
# Initialize input using frame as context
353
- API . new ( expanded_input , nil , options ) do
375
+ API . new ( expanded_input , nil , options . merge ( no_default_base : true ) ) do
354
376
log_debug ( ".frame" ) { "expanded frame: #{ expanded_frame . to_json ( JSON_STATE ) rescue 'malformed json' } " }
355
377
356
378
# Get framing nodes from expanded input, replacing Blank Node identifiers as necessary
0 commit comments