lib/json/ld/api.rb in json-ld-3.1.3 vs lib/json/ld/api.rb in json-ld-3.1.4
- old
+ new
@@ -64,11 +64,11 @@
#
# @param [String, #read, Hash, Array] input
# @param [String, #read, Hash, Array, JSON::LD::Context] context
# An external context to use additionally to the context embedded in input when expanding the input.
# @param [Hash{Symbol => Object}] options
- # @option options [String, #to_s] :base
+ # @option options [RDF::URI, String, #to_s] :base
# 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.
# @option options [Boolean] :compactArrays (true)
# 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.
# @option options [Boolean] :compactToRelative (true)
# Creates document relative IRIs when compacting, if `true`, otherwise leaves expanded.
@@ -106,20 +106,21 @@
ordered: false,
extractAllScripts: false,
}.merge(options)
@namer = unique_bnodes ? BlankNodeUniqer.new : (rename_bnodes ? BlankNodeNamer.new("b") : BlankNodeMapper.new)
+ @options[:base] = RDF::URI(@options[:base]) if @options[:base] && !@options[:base].is_a?(RDF::URI)
# For context via Link header
_, context_ref = nil, nil
@value = case input
when Array, Hash then input.dup
when IO, StringIO, String
remote_doc = self.class.loadRemoteDocument(input, **@options)
context_ref = remote_doc.contextUrl
- @options[:base] = remote_doc.documentUrl if remote_doc.documentUrl && !@options[:no_default_base]
+ @options[:base] = RDF::URI(remote_doc.documentUrl) if remote_doc.documentUrl && !@options[:no_default_base]
case remote_doc.document
when String
MultiJson.load(remote_doc.document, **options)
else
@@ -128,11 +129,11 @@
end
end
# If not provided, first use context from document, or from a Link header
context ||= context_ref || {}
- @context = Context.parse(context || {}, **@options)
+ @context = Context.parse(context, **@options)
if block_given?
case block.arity
when 0, -1 then instance_eval(&block)
else block.call(self)
@@ -161,14 +162,13 @@
# @yieldreturn [Object] returned object
# @return [Object, Array<Hash>]
# If a block is given, the result of evaluating the block is returned, otherwise, the expanded JSON-LD document
# @see https://www.w3.org/TR/json-ld11-api/#expansion-algorithm
def self.expand(input, framing: false, **options, &block)
- result, doc_base = nil
+ result = doc_base = nil
API.new(input, options[:expandContext], **options) do
result = self.expand(self.value, nil, self.context,
- ordered: @options[:ordered],
framing: framing)
doc_base = @options[:base]
end
# 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.
@@ -216,25 +216,25 @@
options = {compactToRelative: true}.merge(options)
# 1) Perform the Expansion Algorithm on the JSON-LD input.
# This removes any existing context to allow the given context to be cleanly applied.
expanded_input = expanded ? input : API.expand(input, ordered: false, **options) do |res, base_iri|
- options[:base] ||= base_iri if options[:compactToRelative]
+ options[:base] ||= RDF::URI(base_iri) if base_iri && options[:compactToRelative]
res
end
API.new(expanded_input, context, no_default_base: true, **options) do
log_debug(".compact") {"expanded input: #{expanded_input.to_json(JSON_STATE) rescue 'malformed json'}"}
- result = compact(value, ordered: @options[:ordered])
+ result = compact(value)
# xxx) Add the given context to the output
- ctx = self.context.serialize
+ ctx = self.context.serialize(provided_context: context)
if result.is_a?(Array)
kwgraph = self.context.compact_iri('@graph', vocab: true)
result = result.empty? ? {} : {kwgraph => result}
end
- result = ctx.merge(result) unless ctx.empty?
+ result = ctx.merge(result) unless ctx.fetch('@context', {}).empty?
end
block_given? ? yield(result) : result
end
##
@@ -263,11 +263,11 @@
extractAllScripts: true,
}.merge(options)
# Expand input to simplify processing
expanded_input = expanded ? input : API.expand(input, **options) do |result, base_iri|
- options[:base] ||= base_iri if options[:compactToRelative]
+ options[:base] ||= RDF::URI(base_iri) if base_iri && options[:compactToRelative]
result
end
# Initialize input using
API.new(expanded_input, context, no_default_base: true, **options) do
@@ -292,13 +292,15 @@
flattened << default_graph[id] unless node_reference?(default_graph[id])
end
if context && !flattened.empty?
# 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.
- compacted = as_array(compact(flattened, ordered: @options[:ordered]))
+ compacted = as_array(compact(flattened))
kwgraph = self.context.compact_iri('@graph')
- flattened = self.context.serialize.merge(kwgraph => compacted)
+ flattened = self.context.
+ serialize(provided_context: context).
+ merge(kwgraph => compacted)
end
end
block_given? ? yield(flattened) : flattened
end
@@ -333,11 +335,11 @@
# @raise [InvalidFrame]
# @see https://www.w3.org/TR/json-ld11-api/#framing-algorithm
def self.frame(input, frame, expanded: false, **options)
result = nil
options = {
- base: (input if input.is_a?(String)),
+ base: (RDF::URI(input) if input.is_a?(String)),
compactArrays: true,
compactToRelative: true,
embed: '@once',
explicit: false,
requireAll: false,
@@ -367,11 +369,11 @@
end
end
# Expand input to simplify processing
expanded_input = expanded ? input : API.expand(input, ordered: false, **options) do |res, base_iri|
- options[:base] ||= base_iri if options[:compactToRelative]
+ options[:base] ||= RDF::URI(base_iri) if base_iri && options[:compactToRelative]
res
end
# Expand frame to simplify processing
expanded_frame = API.expand(frame, framing: true, ordered: false, **options)
@@ -424,23 +426,26 @@
# Replace values with `@preserve` with the content of its entry.
result = cleanup_preserve(result)
log_debug(".frame") {"expanded result: #{result.to_json(JSON_STATE) rescue 'malformed json'}"}
# Compact result
- compacted = compact(result, ordered: @options[:ordered])
+ compacted = compact(result)
# @replace `@null` with nil, compacting arrays
compacted = cleanup_null(compacted)
compacted = [compacted] unless options[:omitGraph] || compacted.is_a?(Array)
# Add the given context to the output
result = if !compacted.is_a?(Array)
- context.serialize.merge(compacted)
+ compacted
else
kwgraph = context.compact_iri('@graph')
- context.serialize.merge({kwgraph => compacted})
+ {kwgraph => compacted}
end
+ # Only add context if one was provided
+ result = context.serialize(provided_context: frame).merge(result) if frame['@context']
+
log_debug(".frame") {"after compact: #{result.to_json(JSON_STATE) rescue 'malformed json'}"}
result
end
block_given? ? yield(result) : result
@@ -519,45 +524,47 @@
result = nil
API.new(nil, nil, **options) do
result = from_statements(input,
useRdfType: useRdfType,
- useNativeTypes: useNativeTypes,
- ordered: @options[:ordered])
+ useNativeTypes: useNativeTypes)
end
block_given? ? yield(result) : result
end
##
# Uses built-in or provided documentLoader to retrieve a parsed document.
#
# @param [RDF::URI, String] url
+ # @param [String, RDF::URI] base
+ # Location to use as documentUrl instead of `url`.
+ # @option options [Proc] :documentLoader
+ # The callback of the loader to be used to retrieve remote documents and contexts.
# @param [Boolean] extractAllScripts
# If set to `true`, when extracting JSON-LD script elements from HTML, unless a specific fragment identifier is targeted, extracts all encountered JSON-LD script elements using an array form, if necessary.
# @param [String] profile
# When the resulting `contentType` is `text/html` or `application/xhtml+xml`, this option determines the profile to use for selecting a JSON-LD script elements.
# @param [String] requestProfile
# One or more IRIs to use in the request as a profile parameter.
- # @param [Boolean] validate
+ # @param [Boolean] validate (false)
# Allow only appropriate content types
- # @param [String, RDF::URI] base
- # Location to use as documentUrl instead of `url`.
# @param [Hash<Symbol => Object>] options
# @yield remote_document
# @yieldparam [RemoteDocumentRemoteDocument, RDF::Util::File::RemoteDocument] remote_document
# @yieldreturn [Object] returned object
# @return [Object, RemoteDocument]
# If a block is given, the result of evaluating the block is returned, otherwise, the retrieved remote document and context information unless block given
# @raise [JsonLdError]
def self.loadRemoteDocument(url,
+ base: nil,
+ documentLoader: nil,
extractAllScripts: false,
profile: nil,
requestProfile: nil,
validate: false,
- base: nil,
**options)
- documentLoader = options.fetch(:documentLoader, self.method(:documentLoader))
+ documentLoader ||= self.method(:documentLoader)
options = OPEN_OPTS.merge(options)
if requestProfile
# Add any request profile
options[:headers]['Accept'] = options[:headers]['Accept'].sub('application/ld+json,', "application/ld+json;profile=#{requestProfile}, application/ld+json;q=0.9,")
end