json-ld 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +9 -8
- data/VERSION +1 -1
- data/bin/jsonld +2 -1
- data/lib/json/ld.rb +43 -42
- data/lib/json/ld/api.rb +184 -39
- data/lib/json/ld/compact.rb +1 -1
- data/lib/json/ld/context.rb +88 -58
- data/lib/json/ld/expand.rb +27 -25
- data/lib/json/ld/extensions.rb +0 -23
- data/lib/json/ld/flatten.rb +1 -1
- data/lib/json/ld/reader.rb +2 -2
- data/lib/json/ld/resource.rb +1 -1
- data/spec/api_spec.rb +3 -1
- data/spec/compact_spec.rb +6 -4
- data/spec/context_spec.rb +20 -35
- data/spec/expand_spec.rb +42 -22
- data/spec/frame_spec.rb +1 -1
- data/spec/from_rdf_spec.rb +4 -22
- data/spec/suite_compact_spec.rb +2 -19
- data/spec/suite_error_spec.rb +17 -0
- data/spec/suite_expand_spec.rb +2 -16
- data/spec/suite_flatten_spec.rb +2 -16
- data/spec/suite_frame_spec.rb +2 -16
- data/spec/suite_from_rdf_spec.rb +2 -18
- data/spec/suite_helper.rb +218 -60
- data/spec/suite_remote_doc_spec.rb +17 -0
- data/spec/suite_to_rdf_spec.rb +2 -19
- data/spec/to_rdf_spec.rb +5 -5
- data/spec/writer_spec.rb +3 -3
- metadata +8 -6
- data/spec/suite_error_expand_spec.rb +0 -23
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTJhN2RiZDA5MjA5ZTUxZGJhZTZhMTI5NGNkOTM3YjA0ZjkxYzlkYQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZTRlZDUwNDA0Nzc5MWIyMDg5YmQ2MTQzY2JlYzU2YWYxMzAyNDBjMQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YmY4M2Q3NjEyYmNkOTBlYjdiYzAzOWI1ZThhMDQ2ZjA3MWQ0ZTFiZDFkOGMx
|
10
|
+
NzAyYzRhYjgwNGMyMjMxNTNjZjQ2N2I2NzQyZTRlMGQzMThjZmY1Mjc3ZTk4
|
11
|
+
OTYyNDYzMmY1Yzc5ODFlNGY3MDY1OGQxOTY5NGRhZTdmY2FiOGQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjBlNTM5YTJkY2YxY2UyOGMxMmRlMjRiODk5Yjk0M2EyM2NiNzlkODBjNWY2
|
14
|
+
ODg1MzAwOTUxODc0OTI3NDI3NzA0ZDk0ZGEzNTE3YjVmZWNhMzk2ZWY1MDAw
|
15
|
+
M2M5NmFjM2M0OGUzMjA1Zjk2Zjg4ZDhiOTY0YWM2OTJlNWNiZjg=
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# JSON-LD reader/writer
|
2
2
|
|
3
|
-
[JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD][] processor.
|
3
|
+
[JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD API][] processor. Additionally this gem implements [JSON-LD Framing][].
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/json-ld.png)](http://badge.fury.io/rb/json-ld)
|
6
6
|
[![Build Status](https://secure.travis-ci.org/ruby-rdf/json-ld.png?branch=master)](http://travis-ci.org/ruby-rdf/json-ld)
|
@@ -220,13 +220,12 @@ Install with `gem install json-ld`
|
|
220
220
|
Full documentation available on [RubyDoc](http://rubydoc.info/gems/json-ld/file/README.md)
|
221
221
|
|
222
222
|
## Differences from [JSON-LD API][]
|
223
|
-
The specified JSON-LD API is based on a WebIDL definition intended for use within
|
223
|
+
The specified JSON-LD API is based on a WebIDL definition implementing [Promises][] intended for use within a browser.
|
224
224
|
This version implements a more Ruby-like variation of this API without the use
|
225
|
-
of
|
226
|
-
execute synchronously, so that the return from a method can be used as well as a block.
|
225
|
+
of promises or callback arguments, preferring Ruby blocks. All API methods
|
226
|
+
execute synchronously, so that the return from a method can typically be used as well as a block.
|
227
227
|
|
228
|
-
Note, the API method signatures differed in versions before 1.0, in that they also had
|
229
|
-
a callback parameter.
|
228
|
+
Note, the API method signatures differed in versions before 1.0, in that they also had a callback parameter. And 1.0.6 has some other minor method signature differences than previous versions. This should be the only exception to the use of semantic versioning.
|
230
229
|
|
231
230
|
### Principal Classes
|
232
231
|
* {JSON::LD}
|
@@ -288,5 +287,7 @@ see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
288
287
|
[PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
|
289
288
|
[RDF.rb]: http://rubygems.org/gems/rdf
|
290
289
|
[Backports]: http://rubygems.org/gems/backports
|
291
|
-
[JSON-LD]: http://
|
292
|
-
[JSON-LD API]: http://
|
290
|
+
[JSON-LD]: http://www.w3.org/TR/json-ld/ "JSON-LD 1.0"
|
291
|
+
[JSON-LD API]: http://www.w3.org/TR/json-ld-api/ "JSON-LD 1.0 Processing Algorithms and API"
|
292
|
+
[JSON-LD Framing]: http://json-ld.org/spec/latest/json-ld-framing/ "JSON-LD Framing 1.0"
|
293
|
+
[Promises]: http://dom.spec.whatwg.org/#promises
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.6
|
data/bin/jsonld
CHANGED
@@ -26,7 +26,8 @@ def run(input, options)
|
|
26
26
|
prefixes = {}
|
27
27
|
start = Time.new
|
28
28
|
if options[:expand]
|
29
|
-
|
29
|
+
options = options.merge(:expandContext => options.delete(:context)) if options.has_key?(:context)
|
30
|
+
output = JSON::LD::API.expand(input, options)
|
30
31
|
secs = Time.new - start
|
31
32
|
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
|
32
33
|
STDERR.puts "Expanded in #{secs} seconds." unless options[:quiet]
|
data/lib/json/ld.rb
CHANGED
@@ -88,48 +88,49 @@ module JSON
|
|
88
88
|
def self.debug?; @debug; end
|
89
89
|
def self.debug=(value); @debug = value; end
|
90
90
|
|
91
|
-
class
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
class
|
100
|
-
class
|
101
|
-
class
|
102
|
-
class
|
103
|
-
class
|
104
|
-
class
|
105
|
-
class
|
106
|
-
class
|
107
|
-
class
|
108
|
-
class
|
109
|
-
class
|
110
|
-
class
|
111
|
-
class
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
class
|
116
|
-
class CyclicIRIMapping <
|
117
|
-
class
|
118
|
-
class
|
119
|
-
class
|
120
|
-
class
|
121
|
-
class
|
122
|
-
class
|
123
|
-
class
|
124
|
-
class
|
125
|
-
class
|
126
|
-
class
|
127
|
-
class
|
128
|
-
class
|
129
|
-
class
|
130
|
-
class
|
131
|
-
class
|
132
|
-
class
|
91
|
+
class JsonLdError < Exception
|
92
|
+
def to_s
|
93
|
+
"#{self.class.instance_variable_get :@code}: #{super}"
|
94
|
+
end
|
95
|
+
def code
|
96
|
+
self.class.instance_variable_get :@code
|
97
|
+
end
|
98
|
+
|
99
|
+
class LoadingDocumentFailed < JsonLdError; @code = "loading document failed"; end
|
100
|
+
class ListOfLists < JsonLdError; @code = "list of lists"; end
|
101
|
+
class InvalidIndexValue < JsonLdError; @code = "invalid @index value"; end
|
102
|
+
class ConflictingIndexes < JsonLdError; @code = "conflicting indexes"; end
|
103
|
+
class InvalidIdValue < JsonLdError; @code = "invalid @id value"; end
|
104
|
+
class InvalidLocalContext < JsonLdError; @code = "invalid local context"; end
|
105
|
+
class MultipleContextLinkHeaders < JsonLdError; @code = "multiple context link headers"; end
|
106
|
+
class LoadingRemoteContextFailed < JsonLdError; @code = "loading remote context failed"; end
|
107
|
+
class InvalidRemoteContext < JsonLdError; @code = "invalid remote context"; end
|
108
|
+
class RecursiveContextInclusion < JsonLdError; @code = "recursive context inclusion"; end
|
109
|
+
class InvalidBaseIRI < JsonLdError; @code = "invalid base IRI"; end
|
110
|
+
class InvalidVocabMapping < JsonLdError; @code = "invalid vocab mapping"; end
|
111
|
+
class InvalidDefaultLanguage < JsonLdError; @code = "invalid default language"; end
|
112
|
+
class KeywordRedefinition < JsonLdError; @code = "keyword redefinition"; end
|
113
|
+
class InvalidTermDefinition < JsonLdError; @code = "invalid term definition"; end
|
114
|
+
class InvalidReverseProperty < JsonLdError; @code = "invalid reverse property"; end
|
115
|
+
class InvalidIRIMapping < JsonLdError; @code = "invalid IRI mapping"; end
|
116
|
+
class CyclicIRIMapping < JsonLdError; @code = "cyclic IRI mapping"; end
|
117
|
+
class InvalidKeywordAlias < JsonLdError; @code = "invalid keyword alias"; end
|
118
|
+
class InvalidTypeMapping < JsonLdError; @code = "invalid type mapping"; end
|
119
|
+
class InvalidLanguageMapping < JsonLdError; @code = "invalid language mapping"; end
|
120
|
+
class CollidingKeywords < JsonLdError; @code = "colliding keywords"; end
|
121
|
+
class InvalidContainerMapping < JsonLdError; @code = "invalid container mapping"; end
|
122
|
+
class InvalidTypeValue < JsonLdError; @code = "invalid type value"; end
|
123
|
+
class InvalidValueObject < JsonLdError; @code = "invalid value object"; end
|
124
|
+
class InvalidValueObjectValue < JsonLdError; @code = "invalid value object value"; end
|
125
|
+
class InvalidLanguageTaggedString < JsonLdError; @code = "invalid language-tagged string"; end
|
126
|
+
class InvalidLanguageTaggedValue < JsonLdError; @code = "invalid language-tagged value"; end
|
127
|
+
class InvalidTypedValue < JsonLdError; @code = "invalid typed value"; end
|
128
|
+
class InvalidSetOrListObject < JsonLdError; @code = "invalid set or list object"; end
|
129
|
+
class InvalidLanguageMapValue < JsonLdError; @code = "invalid language map value"; end
|
130
|
+
class CompactionToListOfLists < JsonLdError; @code = "compaction to list of lists"; end
|
131
|
+
class InvalidReversePropertyMap < JsonLdError; @code = "invalid reverse property map"; end
|
132
|
+
class InvalidReverseValue < JsonLdError; @code = "invalid @reverse value"; end
|
133
|
+
class InvalidReversePropertyValue < JsonLdError; @code = "invalid reverse property value"; end
|
133
134
|
end
|
134
135
|
|
135
136
|
class InvalidFrame < Exception
|
data/lib/json/ld/api.rb
CHANGED
@@ -48,39 +48,56 @@ module JSON::LD
|
|
48
48
|
# Initialize the API, reading in any document and setting global options
|
49
49
|
#
|
50
50
|
# @param [String, #read, Hash, Array] input
|
51
|
-
# @param [String, #read
|
51
|
+
# @param [String, #read, Hash, Array, JSON::LD::Context] context
|
52
52
|
# An external context to use additionally to the context embedded in input when expanding the input.
|
53
53
|
# @param [Hash{Symbol => Object}] options
|
54
|
-
# @option options [
|
54
|
+
# @option options [String, #to_s] :base
|
55
55
|
# 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.
|
56
|
+
# If not specified, and a base IRI is found from `input`, options[:base] will be modified with this value.
|
56
57
|
# @option options [Boolean] :compactArrays (true)
|
57
58
|
# 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.
|
59
|
+
# @option options [Proc] :documentLoader
|
60
|
+
# 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.
|
61
|
+
# @option options [String, #read, Hash, Array, JSON::LD::Context] :expandContext
|
62
|
+
# A context that is used to initialize the active context when expanding a document.
|
58
63
|
# @option options [Boolean, String, RDF::URI] :flatten
|
59
64
|
# 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.
|
60
|
-
# @option options [
|
61
|
-
# If set to
|
62
|
-
#
|
65
|
+
# @option options [String] :processingMode ("json-ld-1.0")
|
66
|
+
# If set to "json-ld-1.0", the JSON-LD processor must produce exactly the same results as the algorithms defined in this specification. If set to another value, the JSON-LD processor is allowed to extend or modify the algorithms defined in this specification to enable application-specific optimizations. The definition of such optimizations is beyond the scope of this specification and thus not defined. Consequently, different implementations may implement different optimizations. Developers must not define modes beginning with json-ld as they are reserved for future versions of this specification.
|
67
|
+
# @option options [String] :produceGeneralizedRdf (false)
|
68
|
+
# Unless the produce generalized RDF flag is set to true, RDF triples containing a blank node predicate are excluded from output.
|
63
69
|
# @option options [Boolean] :useNativeTypes (true)
|
64
70
|
# If set to `true`, the JSON-LD processor will use native datatypes for expression xsd:integer, xsd:boolean, and xsd:double values, otherwise, it will use the expanded form.
|
65
|
-
# @option options [Boolean] :useRdfType (false)
|
66
|
-
# If set to `true`, the JSON-LD processor will try to convert datatyped literals to JSON native types instead of using the expanded object form when converting from RDF. `xsd:boolean` values will be converted to `true` or `false`. `xsd:integer` and `xsd:double` values will be converted to JSON numbers.
|
67
71
|
# @option options [Boolean] :rename_bnodes (true)
|
68
72
|
# Rename bnodes as part of expansion, or keep them the same.
|
69
73
|
# @yield [api]
|
70
74
|
# @yieldparam [API]
|
71
75
|
def initialize(input, context, options = {}, &block)
|
72
76
|
@options = {:compactArrays => true}.merge(options)
|
73
|
-
options =
|
77
|
+
@options[:validate] = true if @options[:processingMode] == "json-ld-1.0"
|
78
|
+
@options[:documentLoader] ||= self.class.method(:documentLoader)
|
79
|
+
options[:rename_bnodes] ||= true
|
74
80
|
@namer = options[:rename_bnodes] ? BlankNodeNamer.new("b") : BlankNodeMapper.new
|
81
|
+
content_type = nil
|
75
82
|
@value = case input
|
76
83
|
when Array, Hash then input.dup
|
77
|
-
when IO, StringIO
|
84
|
+
when IO, StringIO
|
85
|
+
@options = {:base => input.base_uri}.merge(@options) if input.respond_to?(:base_uri)
|
86
|
+
JSON.parse(input.read)
|
78
87
|
when String
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
88
|
+
remote_doc = @options[:documentLoader].call(input, @options)
|
89
|
+
|
90
|
+
@options = {:base => remote_doc.documentUrl}.merge(@options)
|
91
|
+
context = context ? [context, remote_doc.contextUrl].compact : remote_doc.contextUrl
|
92
|
+
|
93
|
+
case remote_doc.document
|
94
|
+
when String then JSON.parse(remote_doc.document)
|
95
|
+
else remote_doc.document
|
96
|
+
end
|
83
97
|
end
|
98
|
+
|
99
|
+
# Update calling context :base option, if not defined
|
100
|
+
options[:base] ||= @options[:base] if @options[:base]
|
84
101
|
@context = Context.new(@options)
|
85
102
|
@context = @context.parse(context) if context
|
86
103
|
|
@@ -100,20 +117,18 @@ module JSON::LD
|
|
100
117
|
#
|
101
118
|
# @param [String, #read, Hash, Array] input
|
102
119
|
# The JSON-LD object to copy and perform the expansion upon.
|
103
|
-
# @param [String, #read, Hash, Array, JSON::LD::Context] context
|
104
|
-
# An external context to use additionally to the context embedded in input when expanding the input.
|
105
120
|
# @param [Hash{Symbol => Object}] options
|
106
121
|
# See options in {JSON::LD::API#initialize}
|
107
|
-
# @raise [
|
122
|
+
# @raise [JsonLdError]
|
108
123
|
# @yield jsonld
|
109
124
|
# @yieldparam [Array<Hash>] jsonld
|
110
125
|
# The expanded JSON-LD document
|
111
126
|
# @return [Array<Hash>]
|
112
127
|
# The expanded JSON-LD document
|
113
128
|
# @see http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm
|
114
|
-
def self.expand(input,
|
129
|
+
def self.expand(input, options = {})
|
115
130
|
result = nil
|
116
|
-
API.new(input,
|
131
|
+
API.new(input, options[:expandContext], options) do |api|
|
117
132
|
result = api.expand(api.value, nil, api.context)
|
118
133
|
end
|
119
134
|
|
@@ -147,14 +162,14 @@ module JSON::LD
|
|
147
162
|
# The compacted JSON-LD document
|
148
163
|
# @return [Hash]
|
149
164
|
# The compacted JSON-LD document
|
150
|
-
# @raise [
|
165
|
+
# @raise [JsonLdError]
|
151
166
|
# @see http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm
|
152
167
|
def self.compact(input, context, options = {})
|
153
168
|
expanded = result = nil
|
154
169
|
|
155
170
|
# 1) Perform the Expansion Algorithm on the JSON-LD input.
|
156
171
|
# This removes any existing context to allow the given context to be cleanly applied.
|
157
|
-
expanded = API.expand(input,
|
172
|
+
expanded = API.expand(input, options)
|
158
173
|
|
159
174
|
API.new(expanded, context, options) do
|
160
175
|
debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE)}"}
|
@@ -195,10 +210,10 @@ module JSON::LD
|
|
195
210
|
flattened = []
|
196
211
|
|
197
212
|
# Expand input to simplify processing
|
198
|
-
expanded_input = API.expand(input,
|
213
|
+
expanded_input = API.expand(input, options)
|
199
214
|
|
200
215
|
# Initialize input using frame as context
|
201
|
-
API.new(expanded_input,
|
216
|
+
API.new(expanded_input, context, options) do
|
202
217
|
debug(".flatten") {"expanded input: #{value.to_json(JSON_STATE)}"}
|
203
218
|
|
204
219
|
# Initialize node map to a JSON object consisting of a single member whose key is @default and whose value is an empty JSON object.
|
@@ -221,7 +236,7 @@ module JSON::LD
|
|
221
236
|
|
222
237
|
if context && !flattened.empty?
|
223
238
|
# 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.
|
224
|
-
compacted = compact(flattened, nil)
|
239
|
+
compacted = depth {compact(flattened, nil)}
|
225
240
|
compacted = [compacted] unless compacted.is_a?(Array)
|
226
241
|
kwgraph = self.context.compact_iri('@graph', :quiet => true)
|
227
242
|
flattened = self.context.serialize.merge(kwgraph => compacted)
|
@@ -274,22 +289,25 @@ module JSON::LD
|
|
274
289
|
framing_state[:embed] = options[:embed] if options.has_key?(:embed)
|
275
290
|
framing_state[:explicit] = options[:explicit] if options.has_key?(:explicit)
|
276
291
|
framing_state[:omitDefault] = options[:omitDefault] if options.has_key?(:omitDefault)
|
292
|
+
options[:documentLoader] ||= method(:documentLoader)
|
277
293
|
|
278
294
|
# de-reference frame to create the framing object
|
279
295
|
frame = case frame
|
280
296
|
when Hash then frame.dup
|
281
297
|
when IO, StringIO then JSON.parse(frame.read)
|
282
298
|
when String
|
283
|
-
|
284
|
-
|
285
|
-
|
299
|
+
remote_doc = options[:documentLoader].call(frame)
|
300
|
+
case remote_doc.document
|
301
|
+
when String then JSON.parse(remote_doc.document)
|
302
|
+
else remote_doc.document
|
303
|
+
end
|
286
304
|
end
|
287
305
|
|
288
|
-
# Expand frame to simplify processing
|
289
|
-
expanded_frame = API.expand(frame)
|
290
|
-
|
291
306
|
# Expand input to simplify processing
|
292
|
-
expanded_input = API.expand(input)
|
307
|
+
expanded_input = API.expand(input, options)
|
308
|
+
|
309
|
+
# Expand frame to simplify processing
|
310
|
+
expanded_frame = API.expand(frame, options)
|
293
311
|
|
294
312
|
# Initialize input using frame as context
|
295
313
|
API.new(expanded_input, nil, options) do
|
@@ -334,25 +352,23 @@ module JSON::LD
|
|
334
352
|
#
|
335
353
|
# @param [String, #read, Hash, Array] input
|
336
354
|
# The JSON-LD object to process when outputting statements.
|
337
|
-
# @param [String, #read, Hash, Array, JSON::LD::Context] context
|
338
|
-
# An external context to use additionally to the context embedded in input when expanding the input.
|
339
355
|
# @param [{Symbol,String => Object}] options
|
340
356
|
# See options in {JSON::LD::API#initialize}
|
341
357
|
# Options passed to {JSON::LD::API.expand}
|
342
|
-
# @option options [Boolean] :
|
358
|
+
# @option options [Boolean] :produceGeneralizedRdf (false)
|
343
359
|
# If true, output will include statements having blank node predicates, otherwise they are dropped.
|
344
|
-
# @raise [
|
360
|
+
# @raise [JsonLdError]
|
345
361
|
# @return [Array<RDF::Statement>] if no block given
|
346
362
|
# @yield statement
|
347
363
|
# @yieldparam [RDF::Statement] statement
|
348
|
-
def self.toRDF(input,
|
364
|
+
def self.toRDF(input, options = {}, &block)
|
349
365
|
results = []
|
350
366
|
results.extend(RDF::Enumerable)
|
351
367
|
|
352
368
|
# Expand input to simplify processing
|
353
|
-
expanded_input = API.expand(input,
|
369
|
+
expanded_input = API.expand(input, options)
|
354
370
|
|
355
|
-
API.new(expanded_input,
|
371
|
+
API.new(expanded_input, nil, options) do
|
356
372
|
# 1) Perform the Expansion Algorithm on the JSON-LD input.
|
357
373
|
# This removes any existing context to allow the given context to be cleanly applied.
|
358
374
|
debug(".toRDF") {"expanded input: #{expanded_input.to_json(JSON_STATE)}"}
|
@@ -367,8 +383,29 @@ module JSON::LD
|
|
367
383
|
node_map.each do |graph_name, graph|
|
368
384
|
context = as_resource(graph_name) unless graph_name == '@default'
|
369
385
|
debug(".toRDF") {"context: #{context ? context.to_ntriples : 'null'}"}
|
386
|
+
# Drop results for graphs which are named with relative IRIs
|
387
|
+
if graph_name.is_a?(RDF::URI) && !graph_name.absolute
|
388
|
+
debug(".toRDF") {"drop relative graph_name: #{statement.to_ntriples}"}
|
389
|
+
next
|
390
|
+
end
|
370
391
|
graph_to_rdf(graph).each do |statement|
|
371
|
-
next if statement.predicate.node? && !options[:
|
392
|
+
next if statement.predicate.node? && !options[:produceGeneralizedRdf]
|
393
|
+
# Drop results with relative IRIs
|
394
|
+
relative = statement.to_a.any? do |r|
|
395
|
+
case r
|
396
|
+
when RDF::URI
|
397
|
+
r.relative?
|
398
|
+
when RDF::Literal
|
399
|
+
r.has_datatype? && r.datatype.relative?
|
400
|
+
else
|
401
|
+
false
|
402
|
+
end
|
403
|
+
end
|
404
|
+
if relative
|
405
|
+
debug(".toRDF") {"drop statement with relative IRIs: #{statement.to_ntriples}"}
|
406
|
+
next
|
407
|
+
end
|
408
|
+
|
372
409
|
statement.context = context if context
|
373
410
|
if block_given?
|
374
411
|
yield statement
|
@@ -395,7 +432,7 @@ module JSON::LD
|
|
395
432
|
# @return [Array<Hash>]
|
396
433
|
# The JSON-LD document in expanded form
|
397
434
|
def self.fromRDF(input, options = {}, &block)
|
398
|
-
options = {:useNativeTypes =>
|
435
|
+
options = {:useNativeTypes => false}.merge(options)
|
399
436
|
result = nil
|
400
437
|
|
401
438
|
API.new(nil, nil, options) do |api|
|
@@ -405,6 +442,114 @@ module JSON::LD
|
|
405
442
|
yield result if block_given?
|
406
443
|
result
|
407
444
|
end
|
445
|
+
|
446
|
+
##
|
447
|
+
# Default document loader.
|
448
|
+
# @param [RDF::URI, String] url
|
449
|
+
# @param [Hash<Symbol => Object>] options
|
450
|
+
# @option options [Boolean] :validate
|
451
|
+
# Allow only appropriate content types
|
452
|
+
# @return [RemoteDocument] retrieved remote document and context information unless block given
|
453
|
+
# @yield remote_document
|
454
|
+
# @yieldparam [RemoteDocument] remote_document
|
455
|
+
# @raise [JsonLdError]
|
456
|
+
def self.documentLoader(url, options = {})
|
457
|
+
require 'net/http' unless defined?(Net::HTTP)
|
458
|
+
remote_document = nil
|
459
|
+
options[:headers] ||= OPEN_OPTS[:headers]
|
460
|
+
|
461
|
+
url = url.to_s[5..-1] if url.to_s.start_with?("file:")
|
462
|
+
case url.to_s
|
463
|
+
when /^http/
|
464
|
+
parsed_url = ::URI.parse(url.to_s)
|
465
|
+
until remote_document do
|
466
|
+
Net::HTTP::start(parsed_url.host, parsed_url.port) do |http|
|
467
|
+
request = Net::HTTP::Get.new(parsed_url.request_uri, options[:headers])
|
468
|
+
http.request(request) do |response|
|
469
|
+
case response
|
470
|
+
when Net::HTTPSuccess
|
471
|
+
# found object
|
472
|
+
content_type, ct_param = response.content_type.to_s.downcase.split(";")
|
473
|
+
|
474
|
+
# 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.
|
475
|
+
if content_type && options[:validate]
|
476
|
+
main, sub = content_type.split("/")
|
477
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
478
|
+
main != 'application' ||
|
479
|
+
sub !~ /^(.*\+)?json$/
|
480
|
+
end
|
481
|
+
|
482
|
+
remote_document = RemoteDocument.new(parsed_url.to_s, response.body)
|
483
|
+
|
484
|
+
# If the input has been retrieved, the response has an HTTP Link Header [RFC5988] using the http://www.w3.org/ns/json-ld#context link relation and a content type of application/json or any media type with a +json suffix as defined in [RFC6839] except application/ld+json, update the active context using the Context Processing algorithm, passing the context referenced in the HTTP Link Header as local context. The HTTP Link Header is ignored for documents served as application/ld+json If multiple HTTP Link Headers using the http://www.w3.org/ns/json-ld#context link relation are found, the promise is rejected with a JsonLdError whose code is set to multiple context link headers and processing is terminated.
|
485
|
+
unless content_type.start_with?("application/ld+json")
|
486
|
+
links = response["link"].to_s.
|
487
|
+
split(",").
|
488
|
+
map(&:strip).
|
489
|
+
select {|h| h =~ %r{rel=\"http://www.w3.org/ns/json-ld#context\"}}
|
490
|
+
case links.length
|
491
|
+
when 0 then #nothing to do
|
492
|
+
when 1
|
493
|
+
remote_document.contextUrl = links.first.match(/<([^>]*)>/) && $1
|
494
|
+
else
|
495
|
+
raise JSON::LD::JsonLdError::MultipleContextLinkHeaders,
|
496
|
+
"expected at most 1 Link header with rel=jsonld:context, got #{links.length}"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
yield remote_document if block_given?
|
501
|
+
when Net::HTTPRedirection
|
502
|
+
# Follow redirection
|
503
|
+
parsed_url = ::URI.parse(response["Location"])
|
504
|
+
else
|
505
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "<#{parsed_url}>: #{response.msg}(#{response.code})"
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
else
|
511
|
+
# Use regular open
|
512
|
+
RDF::Util::File.open_file(url, options) do |f|
|
513
|
+
remote_document = RemoteDocument.new(url, f.read)
|
514
|
+
content_type, ct_param = f.content_type.to_s.downcase.split(";") if f.respond_to?(:content_type)
|
515
|
+
if content_type && options[:validate]
|
516
|
+
main, sub = content_type.split("/")
|
517
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
518
|
+
main != 'application' ||
|
519
|
+
sub !~ /^(.*\+)?json$/
|
520
|
+
end
|
521
|
+
|
522
|
+
yield remote_document if block_given?
|
523
|
+
end
|
524
|
+
end
|
525
|
+
remote_document
|
526
|
+
end
|
527
|
+
|
528
|
+
##
|
529
|
+
# A {RemoteDocument} is returned from a {documentLoader}.
|
530
|
+
class RemoteDocument
|
531
|
+
# @return [String] URL of the loaded document, after redirects
|
532
|
+
attr_reader :documentUrl
|
533
|
+
|
534
|
+
# @return [String, Array<Hash>, Hash]
|
535
|
+
# The retrieved document, either as raw text or parsed JSON
|
536
|
+
attr_reader :document
|
537
|
+
|
538
|
+
# @return [String]
|
539
|
+
# The URL of a remote context as specified by an HTTP Link header with rel=`http://www.w3.org/ns/json-ld#context`
|
540
|
+
attr_accessor :contextUrl
|
541
|
+
|
542
|
+
# @param [String] url URL of the loaded document, after redirects
|
543
|
+
# @param [String, Array<Hash>, Hash] document
|
544
|
+
# The retrieved document, either as raw text or parsed JSON
|
545
|
+
# @param [String] context_url (nil)
|
546
|
+
# The URL of a remote context as specified by an HTTP Link header with rel=`http://www.w3.org/ns/json-ld#context`
|
547
|
+
def initialize(url, document, context_url = nil)
|
548
|
+
@documentUrl = url
|
549
|
+
@document = document
|
550
|
+
@contextUrl = context_url
|
551
|
+
end
|
552
|
+
end
|
408
553
|
end
|
409
554
|
end
|
410
555
|
|