json-ld 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -3
- data/VERSION +1 -1
- data/bin/jsonld +42 -23
- data/lib/json/ld.rb +6 -6
- data/lib/json/ld/api.rb +68 -93
- data/lib/json/ld/compact.rb +15 -15
- data/lib/json/ld/context.rb +47 -22
- data/lib/json/ld/expand.rb +7 -7
- data/lib/json/ld/extensions.rb +2 -2
- data/lib/json/ld/flatten.rb +1 -1
- data/lib/json/ld/format.rb +5 -5
- data/lib/json/ld/frame.rb +5 -5
- data/lib/json/ld/from_rdf.rb +2 -2
- data/lib/json/ld/reader.rb +0 -2
- data/lib/json/ld/resource.rb +4 -4
- data/lib/json/ld/streaming_writer.rb +123 -0
- data/lib/json/ld/to_rdf.rb +6 -6
- data/lib/json/ld/writer.rb +29 -6
- data/spec/api_spec.rb +57 -4
- data/spec/compact_spec.rb +92 -92
- data/spec/context_spec.rb +43 -23
- data/spec/expand_spec.rb +142 -142
- data/spec/flatten_spec.rb +17 -17
- data/spec/format_spec.rb +17 -17
- data/spec/frame_spec.rb +47 -47
- data/spec/from_rdf_spec.rb +25 -25
- data/spec/matchers.rb +9 -9
- data/spec/reader_spec.rb +4 -4
- data/spec/resource_spec.rb +1 -1
- data/spec/spec_helper.rb +14 -9
- data/spec/streaming_writer_spec.rb +142 -0
- data/spec/suite_helper.rb +29 -88
- data/spec/to_rdf_spec.rb +17 -17
- data/spec/writer_spec.rb +43 -20
- metadata +40 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f6790b14a0a5f9c477e63ad9b8788b03be1eabe
|
4
|
+
data.tar.gz: 8fc23868782eb98f4c375607ff6bf01813a5aa78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7134666ce6f5e0c47148c6a032e1fb13be5c272abd5db50b1a84b7925857b7a86e3f3444718cb2b0d7717eed49a4d24f70bb6a3beaa3da6b394ad68aab1c6140
|
7
|
+
data.tar.gz: 88f96434d3c7b342e7be136c3b9b20ded52c93f4d8234af446e164336decc7a6b9dbd99f59d362619a8fe6f95a7855adbc8feacb929c99601e41a415a7739ded
|
data/README.md
CHANGED
@@ -13,6 +13,12 @@ JSON::LD can now be used to create a _context_ from an RDFS/OWL definition, and
|
|
13
13
|
|
14
14
|
Install with `gem install json-ld`
|
15
15
|
|
16
|
+
### JSON-LD Streaming Profile
|
17
|
+
This gem implements an optimized streaming writer used for generating JSON-LD from large repositories. Such documents result in the JSON-LD Streaming Profile:
|
18
|
+
|
19
|
+
* Each statement written as a separate node in expanded/flattened form.
|
20
|
+
* RDF Lists are written as separate nodes using `rdf:first` and `rdf:rest` properties.
|
21
|
+
|
16
22
|
## Examples
|
17
23
|
|
18
24
|
require 'rubygems'
|
@@ -165,7 +171,7 @@ Install with `gem install json-ld`
|
|
165
171
|
graph = RDF::Graph.new << JSON::LD::API.toRdf(input)
|
166
172
|
|
167
173
|
require 'rdf/turtle'
|
168
|
-
graph.dump(:ttl, :
|
174
|
+
graph.dump(:ttl, prefixes: {foaf: "http://xmlns.com/foaf/0.1/"})
|
169
175
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
170
176
|
|
171
177
|
<http://example.org/people#joebob> a foaf:Person;
|
@@ -213,8 +219,8 @@ Install with `gem install json-ld`
|
|
213
219
|
## RDF Reader and Writer
|
214
220
|
{JSON::LD} also acts as a normal RDF reader and writer, using the standard RDF.rb reader/writer interfaces:
|
215
221
|
|
216
|
-
graph = RDF::Graph.load("etc/doap.jsonld", :
|
217
|
-
graph.dump(:jsonld, :
|
222
|
+
graph = RDF::Graph.load("etc/doap.jsonld", format: :jsonld)
|
223
|
+
graph.dump(:jsonld, standard_prefixes: true)
|
218
224
|
|
219
225
|
`RDF::GRAPH#dump` can also take a `:context` option to use a separately defined context
|
220
226
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.8
|
data/bin/jsonld
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
|
-
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
3
|
begin
|
5
4
|
require 'linkeddata'
|
6
5
|
rescue LoadError
|
7
6
|
end
|
7
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
8
8
|
require 'json/ld'
|
9
9
|
require 'getoptlong'
|
10
10
|
require 'open-uri'
|
@@ -17,42 +17,49 @@ def run(input, options)
|
|
17
17
|
options[:format] = :jsonld if options[:compact] || options[:frame]
|
18
18
|
|
19
19
|
# If input format is not JSON-LD, transform input to JSON-LD first
|
20
|
-
|
21
|
-
|
22
|
-
g = RDF::Repository.new << r
|
23
|
-
input = JSON::LD::API.fromRdf(g)
|
20
|
+
reader = if options[:input_format] != :jsonld
|
21
|
+
reader_class.new(input, options[:parser_options])
|
24
22
|
end
|
25
23
|
|
26
24
|
prefixes = {}
|
27
25
|
start = Time.new
|
28
26
|
if options[:expand]
|
29
|
-
options = options.merge(:
|
27
|
+
options = options.merge(expandContext: options.delete(:context)) if options.has_key?(:context)
|
28
|
+
input = JSON::LD::API.fromRdf(reader) if reader
|
30
29
|
output = JSON::LD::API.expand(input, options)
|
31
30
|
secs = Time.new - start
|
32
31
|
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
|
33
32
|
STDERR.puts "Expanded in #{secs} seconds." unless options[:quiet]
|
34
33
|
elsif options[:compact]
|
34
|
+
input = JSON::LD::API.fromRdf(reader) if reader
|
35
35
|
output = JSON::LD::API.compact(input, options[:context], options)
|
36
36
|
secs = Time.new - start
|
37
37
|
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
|
38
38
|
STDERR.puts "Compacted in #{secs} seconds." unless options[:quiet]
|
39
39
|
elsif options[:flatten]
|
40
|
+
input = JSON::LD::API.fromRdf(reader) if reader
|
40
41
|
output = JSON::LD::API.flatten(input, options[:context], options)
|
41
42
|
secs = Time.new - start
|
42
43
|
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
|
43
44
|
STDERR.puts "Flattened in #{secs} seconds." unless options[:quiet]
|
44
45
|
elsif options[:frame]
|
46
|
+
input = JSON::LD::API.fromRdf(reader) if reader
|
45
47
|
output = JSON::LD::API.frame(input, options[:frame], options)
|
46
48
|
secs = Time.new - start
|
47
49
|
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
|
48
50
|
STDERR.puts "Framed in #{secs} seconds." unless options[:quiet]
|
49
51
|
else
|
50
|
-
options = options.merge(:
|
51
|
-
|
52
|
+
options = options.merge(expandContext: options.delete(:context)) if options.has_key?(:context)
|
53
|
+
parser_options = options[:parser_options].merge(standard_prefixes: true)
|
54
|
+
reader ||= JSON::LD::Reader.new(input, parser_options)
|
55
|
+
num = 0
|
56
|
+
RDF::Writer.for(options[:output_format]).new(options[:output], parser_options) do |w|
|
57
|
+
reader.each do |statement|
|
58
|
+
num += 1
|
59
|
+
w << statement
|
60
|
+
end
|
61
|
+
end
|
52
62
|
secs = Time.new - start
|
53
|
-
num = g.count
|
54
|
-
parser_options = options[:parser_options].merge(:standard_prefixes => true)
|
55
|
-
options[:output].puts g.dump(options[:output_format], parser_options)
|
56
63
|
STDERR.puts "\nParsed #{num} statements in #{secs} seconds @ #{num/secs} statements/second." unless options[:quiet]
|
57
64
|
end
|
58
65
|
rescue
|
@@ -62,17 +69,18 @@ rescue
|
|
62
69
|
end
|
63
70
|
|
64
71
|
parser_options = {
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:
|
68
|
-
:
|
72
|
+
base: nil,
|
73
|
+
progress: false,
|
74
|
+
validate: false,
|
75
|
+
stream: false,
|
76
|
+
strict: false,
|
69
77
|
}
|
70
78
|
|
71
79
|
options = {
|
72
|
-
:
|
73
|
-
:
|
74
|
-
|
75
|
-
|
80
|
+
parser_options: parser_options,
|
81
|
+
output: STDOUT,
|
82
|
+
output_format: :jsonld,
|
83
|
+
input_format: :jsonld,
|
76
84
|
}
|
77
85
|
input = nil
|
78
86
|
|
@@ -89,8 +97,9 @@ OPT_ARGS = [
|
|
89
97
|
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output to the specified file path"],
|
90
98
|
["--parse-only", GetoptLong::NO_ARGUMENT, "Parse the document for well-formedness only"],
|
91
99
|
["--quiet", GetoptLong::NO_ARGUMENT, "Supress most output other than progress indicators"],
|
100
|
+
["--stream", GetoptLong::NO_ARGUMENT, "Use Streaming reader/writer"],
|
92
101
|
["--uri", GetoptLong::REQUIRED_ARGUMENT,"URI to be used as the document base"],
|
93
|
-
["--
|
102
|
+
["--validate", GetoptLong::NO_ARGUMENT, "Validate while processing"],
|
94
103
|
["--help", "-?", GetoptLong::NO_ARGUMENT, "This message"]
|
95
104
|
]
|
96
105
|
def usage
|
@@ -108,7 +117,6 @@ def usage
|
|
108
117
|
exit(1)
|
109
118
|
end
|
110
119
|
|
111
|
-
|
112
120
|
opts = GetoptLong.new(*OPT_ARGS.map {|o| o[0..-2]})
|
113
121
|
|
114
122
|
opts.each do |opt, arg|
|
@@ -125,18 +133,29 @@ opts.each do |opt, arg|
|
|
125
133
|
when '--output' then options[:output] = File.open(arg, "w")
|
126
134
|
when '--parse-only' then options[:parse_only] = true
|
127
135
|
when '--quiet' then options[:quiet] = true
|
136
|
+
when '--stream' then parser_options[:stream] = true
|
128
137
|
when '--uri' then parser_options[:base] = arg
|
129
|
-
when '--
|
138
|
+
when '--validate' then parser_options[:validate] = true
|
130
139
|
when '--help' then usage
|
131
140
|
end
|
132
141
|
end
|
133
142
|
|
143
|
+
# Hack
|
144
|
+
options[:parser_options][:context] = options[:context] if parser_options[:stream]
|
145
|
+
|
146
|
+
if !(options.keys & [:expand, :compact, :flatten, :frame]).empty? &&
|
147
|
+
(parser_options[:stream] || options[:output_format] != :jsonld)
|
148
|
+
STDERR.puts "Incompatible options"
|
149
|
+
exit(1)
|
150
|
+
end
|
151
|
+
|
134
152
|
if ARGV.empty?
|
135
153
|
s = input ? input : $stdin.read
|
136
154
|
run(StringIO.new(s), options)
|
137
155
|
else
|
138
156
|
ARGV.each do |file|
|
139
|
-
|
157
|
+
# Call with opened files
|
158
|
+
RDF::Util::File.open_file(file, options) {|f| run(f, options)}
|
140
159
|
end
|
141
160
|
end
|
142
161
|
puts
|
data/lib/json/ld.rb
CHANGED
@@ -25,7 +25,7 @@ module JSON
|
|
25
25
|
require 'json/ld/format'
|
26
26
|
require 'json/ld/utils'
|
27
27
|
autoload :API, 'json/ld/api'
|
28
|
-
autoload :Context,
|
28
|
+
autoload :Context, 'json/ld/context'
|
29
29
|
autoload :Normalize, 'json/ld/normalize'
|
30
30
|
autoload :Reader, 'json/ld/reader'
|
31
31
|
autoload :Resource, 'json/ld/resource'
|
@@ -77,11 +77,11 @@ module JSON
|
|
77
77
|
NATIVE_DATATYPES = [RDF::XSD.integer.to_s, RDF::XSD.boolean.to_s, RDF::XSD.double.to_s]
|
78
78
|
|
79
79
|
JSON_STATE = JSON::State.new(
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
:
|
80
|
+
indent: " ",
|
81
|
+
space: " ",
|
82
|
+
space_before: "",
|
83
|
+
object_nl: "\n",
|
84
|
+
array_nl: "\n"
|
85
85
|
)
|
86
86
|
|
87
87
|
def self.debug?; @debug; end
|
data/lib/json/ld/api.rb
CHANGED
@@ -26,7 +26,7 @@ module JSON::LD
|
|
26
26
|
|
27
27
|
# Options used for open_file
|
28
28
|
OPEN_OPTS = {
|
29
|
-
:
|
29
|
+
headers: {"Accept" => "application/ld+json, application/json"}
|
30
30
|
}
|
31
31
|
|
32
32
|
# Current input
|
@@ -79,21 +79,32 @@ module JSON::LD
|
|
79
79
|
# @yield [api]
|
80
80
|
# @yieldparam [API]
|
81
81
|
def initialize(input, context, options = {}, &block)
|
82
|
-
@options = {:
|
82
|
+
@options = {compactArrays: true, rename_bnodes: true}.merge(options)
|
83
83
|
@options[:validate] = true if @options[:processingMode] == "json-ld-1.0"
|
84
84
|
@options[:documentLoader] ||= self.class.method(:documentLoader)
|
85
|
-
options[:rename_bnodes]
|
86
|
-
|
85
|
+
@namer = options[:unique_bnodes] ? BlankNodeUniqer.new : (@options[:rename_bnodes] ? BlankNodeNamer.new("b") : BlankNodeMapper.new)
|
86
|
+
|
87
|
+
# For context via Link header
|
88
|
+
context_ref = nil
|
89
|
+
|
87
90
|
@value = case input
|
88
91
|
when Array, Hash then input.dup
|
89
92
|
when IO, StringIO
|
90
|
-
@options = {:
|
93
|
+
@options = {base: input.base_uri}.merge(@options) if input.respond_to?(:base_uri)
|
94
|
+
|
95
|
+
# if input impelements #links, attempt to get a contextUrl from that link
|
96
|
+
content_type = input.respond_to?(:content_type) ? input.content_type : "application/json"
|
97
|
+
context_ref = if content_type.start_with?('application/json') && input.respond_to?(:links)
|
98
|
+
link = input.links.find_link(%w(rel http://www.w3.org/ns/json-ld#context))
|
99
|
+
link.href if link
|
100
|
+
end
|
101
|
+
|
91
102
|
JSON.parse(input.read)
|
92
103
|
when String
|
93
104
|
remote_doc = @options[:documentLoader].call(input, @options)
|
94
105
|
|
95
|
-
@options = {:
|
96
|
-
|
106
|
+
@options = {base: remote_doc.documentUrl}.merge(@options)
|
107
|
+
context_ref = remote_doc.contextUrl
|
97
108
|
|
98
109
|
case remote_doc.document
|
99
110
|
when String then JSON.parse(remote_doc.document)
|
@@ -103,6 +114,9 @@ module JSON::LD
|
|
103
114
|
|
104
115
|
# Update calling context :base option, if not defined
|
105
116
|
options[:base] ||= @options[:base] if @options[:base]
|
117
|
+
|
118
|
+
# If not provided, first use context from document, or from a Link header
|
119
|
+
context ||= (@value['@context'] if @value.is_a?(Hash)) || context_ref
|
106
120
|
@context = Context.new(@options)
|
107
121
|
@context = @context.parse(context) if context
|
108
122
|
|
@@ -177,13 +191,13 @@ module JSON::LD
|
|
177
191
|
expanded = API.expand(input, options)
|
178
192
|
|
179
193
|
API.new(expanded, context, options) do
|
180
|
-
debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE)}"}
|
194
|
+
debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE) rescue 'malformed json'}"}
|
181
195
|
result = compact(value, nil)
|
182
196
|
|
183
197
|
# xxx) Add the given context to the output
|
184
198
|
ctx = self.context.serialize
|
185
199
|
if result.is_a?(Array)
|
186
|
-
kwgraph = self.context.compact_iri('@graph', :
|
200
|
+
kwgraph = self.context.compact_iri('@graph', vocab: true, quiet: true)
|
187
201
|
result = result.empty? ? {} : {kwgraph => result}
|
188
202
|
end
|
189
203
|
result = ctx.merge(result) unless ctx.empty?
|
@@ -219,7 +233,7 @@ module JSON::LD
|
|
219
233
|
|
220
234
|
# Initialize input using frame as context
|
221
235
|
API.new(expanded_input, context, options) do
|
222
|
-
debug(".flatten") {"expanded input: #{value.to_json(JSON_STATE)}"}
|
236
|
+
debug(".flatten") {"expanded input: #{value.to_json(JSON_STATE) rescue 'malformed json'}"}
|
223
237
|
|
224
238
|
# Initialize node map to a JSON object consisting of a single member whose key is @default and whose value is an empty JSON object.
|
225
239
|
node_map = {'@default' => {}}
|
@@ -242,7 +256,7 @@ module JSON::LD
|
|
242
256
|
# 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.
|
243
257
|
compacted = depth {compact(flattened, nil)}
|
244
258
|
compacted = [compacted] unless compacted.is_a?(Array)
|
245
|
-
kwgraph = self.context.compact_iri('@graph', :
|
259
|
+
kwgraph = self.context.compact_iri('@graph', quiet: true)
|
246
260
|
flattened = self.context.serialize.merge(kwgraph => compacted)
|
247
261
|
end
|
248
262
|
end
|
@@ -284,10 +298,10 @@ module JSON::LD
|
|
284
298
|
def self.frame(input, frame, options = {})
|
285
299
|
result = nil
|
286
300
|
framing_state = {
|
287
|
-
:
|
288
|
-
:
|
289
|
-
:
|
290
|
-
:
|
301
|
+
embed: true,
|
302
|
+
explicit: false,
|
303
|
+
omitDefault: false,
|
304
|
+
embeds: nil,
|
291
305
|
}
|
292
306
|
framing_state[:embed] = options[:embed] if options.has_key?(:embed)
|
293
307
|
framing_state[:explicit] = options[:explicit] if options.has_key?(:explicit)
|
@@ -315,9 +329,9 @@ module JSON::LD
|
|
315
329
|
# Initialize input using frame as context
|
316
330
|
API.new(expanded_input, nil, options) do
|
317
331
|
#debug(".frame") {"context from frame: #{context.inspect}"}
|
318
|
-
debug(".frame") {"raw frame: #{frame.to_json(JSON_STATE)}"}
|
319
|
-
debug(".frame") {"expanded frame: #{expanded_frame.to_json(JSON_STATE)}"}
|
320
|
-
debug(".frame") {"expanded input: #{value.to_json(JSON_STATE)}"}
|
332
|
+
debug(".frame") {"raw frame: #{frame.to_json(JSON_STATE) rescue 'malformed json'}"}
|
333
|
+
debug(".frame") {"expanded frame: #{expanded_frame.to_json(JSON_STATE) rescue 'malformed json'}"}
|
334
|
+
debug(".frame") {"expanded input: #{value.to_json(JSON_STATE) rescue 'malformed json'}"}
|
321
335
|
|
322
336
|
# Get framing nodes from expanded input, replacing Blank Node identifiers as necessary
|
323
337
|
all_nodes = {}
|
@@ -327,11 +341,11 @@ module JSON::LD
|
|
327
341
|
end
|
328
342
|
@options[:debug] = old_dbg
|
329
343
|
@node_map = all_nodes['@default']
|
330
|
-
debug(".frame") {"node_map: #{@node_map.to_json(JSON_STATE)}"}
|
344
|
+
debug(".frame") {"node_map: #{@node_map.to_json(JSON_STATE) rescue 'malformed json'}"}
|
331
345
|
|
332
346
|
result = []
|
333
347
|
frame(framing_state, @node_map, (expanded_frame.first || {}), parent: result)
|
334
|
-
debug(".frame") {"after frame: #{result.to_json(JSON_STATE)}"}
|
348
|
+
debug(".frame") {"after frame: #{result.to_json(JSON_STATE) rescue 'malformed json'}"}
|
335
349
|
|
336
350
|
# Initalize context from frame
|
337
351
|
@context = depth {@context.parse(frame['@context'])}
|
@@ -340,9 +354,9 @@ module JSON::LD
|
|
340
354
|
compacted = [compacted] unless compacted.is_a?(Array)
|
341
355
|
|
342
356
|
# Add the given context to the output
|
343
|
-
kwgraph = context.compact_iri('@graph', :
|
357
|
+
kwgraph = context.compact_iri('@graph', quiet: true)
|
344
358
|
result = context.serialize.merge({kwgraph => compacted})
|
345
|
-
debug(".frame") {"after compact: #{result.to_json(JSON_STATE)}"}
|
359
|
+
debug(".frame") {"after compact: #{result.to_json(JSON_STATE) rescue 'malformed json'}"}
|
346
360
|
result = cleanup_preserve(result)
|
347
361
|
end
|
348
362
|
|
@@ -374,17 +388,17 @@ module JSON::LD
|
|
374
388
|
end
|
375
389
|
|
376
390
|
# Expand input to simplify processing
|
377
|
-
expanded_input = API.expand(input, options.merge(:
|
391
|
+
expanded_input = API.expand(input, options.merge(ordered: false))
|
378
392
|
|
379
393
|
API.new(expanded_input, nil, options) do
|
380
394
|
# 1) Perform the Expansion Algorithm on the JSON-LD input.
|
381
395
|
# This removes any existing context to allow the given context to be cleanly applied.
|
382
|
-
debug(".toRdf") {"expanded input: #{expanded_input.to_json(JSON_STATE)}"}
|
396
|
+
debug(".toRdf") {"expanded input: #{expanded_input.to_json(JSON_STATE) rescue 'malformed json'}"}
|
383
397
|
|
384
398
|
# Generate _nodeMap_
|
385
399
|
node_map = {'@default' => {}}
|
386
400
|
generate_node_map(expanded_input, node_map)
|
387
|
-
debug(".toRdf") {"node map: #{node_map.to_json(JSON_STATE)}"}
|
401
|
+
debug(".toRdf") {"node map: #{node_map.to_json(JSON_STATE) rescue 'malformed json'}"}
|
388
402
|
|
389
403
|
# Start generating statements
|
390
404
|
node_map.each do |graph_name, graph|
|
@@ -439,7 +453,7 @@ module JSON::LD
|
|
439
453
|
# @return [Array<Hash>]
|
440
454
|
# The JSON-LD document in expanded form
|
441
455
|
def self.fromRdf(input, options = {}, &block)
|
442
|
-
options = {:
|
456
|
+
options = {useNativeTypes: false}.merge(options)
|
443
457
|
result = nil
|
444
458
|
|
445
459
|
API.new(nil, nil, options) do |api|
|
@@ -461,78 +475,39 @@ module JSON::LD
|
|
461
475
|
# @yieldparam [RemoteDocument] remote_document
|
462
476
|
# @raise [JsonLdError]
|
463
477
|
def self.documentLoader(url, options = {})
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
Net::HTTP::start(parsed_url.host, parsed_url.port,
|
474
|
-
open_timeout: 60 * 1000,
|
475
|
-
use_ssl: parsed_url.scheme == 'https',
|
476
|
-
verify_mode: OpenSSL::SSL::VERIFY_NONE
|
477
|
-
) do |http|
|
478
|
-
request = Net::HTTP::Get.new(parsed_url.request_uri, options[:headers])
|
479
|
-
http.request(request) do |response|
|
480
|
-
case response
|
481
|
-
when Net::HTTPSuccess
|
482
|
-
# found object
|
483
|
-
content_type, ct_param = response.content_type.to_s.downcase.split(";")
|
484
|
-
|
485
|
-
# 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.
|
486
|
-
if content_type && options[:validate]
|
487
|
-
main, sub = content_type.split("/")
|
488
|
-
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
489
|
-
main != 'application' ||
|
490
|
-
sub !~ /^(.*\+)?json$/
|
491
|
-
end
|
492
|
-
|
493
|
-
remote_document = RemoteDocument.new(parsed_url.to_s, response.body)
|
494
|
-
|
495
|
-
# 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.
|
496
|
-
unless content_type.to_s.start_with?("application/ld+json")
|
497
|
-
links = response["link"].to_s.
|
498
|
-
split(",").
|
499
|
-
map(&:strip).
|
500
|
-
select {|h| h =~ %r{rel=\"http://www.w3.org/ns/json-ld#context\"}}
|
501
|
-
case links.length
|
502
|
-
when 0 then #nothing to do
|
503
|
-
when 1
|
504
|
-
remote_document.contextUrl = links.first.match(/<([^>]*)>/) && $1
|
505
|
-
else
|
506
|
-
raise JSON::LD::JsonLdError::MultipleContextLinkHeaders,
|
507
|
-
"expected at most 1 Link header with rel=jsonld:context, got #{links.length}"
|
508
|
-
end
|
509
|
-
end
|
510
|
-
|
511
|
-
return block_given? ? yield(remote_document) : remote_document
|
512
|
-
when Net::HTTPRedirection
|
513
|
-
# Follow redirection
|
514
|
-
parsed_url = ::URI.parse(response["Location"])
|
515
|
-
else
|
516
|
-
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "<#{parsed_url}>: #{response.msg}(#{response.code})"
|
517
|
-
end
|
518
|
-
end
|
519
|
-
end
|
478
|
+
options = OPEN_OPTS.merge(options)
|
479
|
+
RDF::Util::File.open_file(url, options) do |remote_doc|
|
480
|
+
content_type = remote_doc.content_type if remote_doc.respond_to?(:content_type)
|
481
|
+
# 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.
|
482
|
+
if content_type && options[:validate]
|
483
|
+
main, sub = content_type.split("/")
|
484
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
485
|
+
main != 'application' ||
|
486
|
+
sub !~ /^(.*\+)?json$/
|
520
487
|
end
|
521
|
-
|
522
|
-
#
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
|
529
|
-
main != 'application' ||
|
530
|
-
sub !~ /^(.*\+)?json$/
|
488
|
+
|
489
|
+
# 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.
|
490
|
+
contextUrl = unless content_type.nil? || content_type.start_with?("application/ld+json")
|
491
|
+
# Get context link(s)
|
492
|
+
# Note, we can't simply use #find_link, as we need to detect multiple
|
493
|
+
links = remote_doc.links.links.select do |link|
|
494
|
+
link.attr_pairs.include?(%w(rel http://www.w3.org/ns/json-ld#context))
|
531
495
|
end
|
496
|
+
raise JSON::LD::JsonLdError::MultipleContextLinkHeaders,
|
497
|
+
"expected at most 1 Link header with rel=jsonld:context, got #{links.length}" if links.length > 1
|
498
|
+
Array(links.first).first
|
499
|
+
end
|
532
500
|
|
533
|
-
|
501
|
+
doc_uri = remote_doc.base_uri rescue url
|
502
|
+
doc = RemoteDocument.new(doc_uri, remote_doc.read, contextUrl)
|
503
|
+
if block_given?
|
504
|
+
yield(doc)
|
505
|
+
else
|
506
|
+
doc
|
534
507
|
end
|
535
508
|
end
|
509
|
+
rescue IOError => e
|
510
|
+
raise JSON::LD::JsonLdError::LoadingDocumentFailed, e.message
|
536
511
|
end
|
537
512
|
|
538
513
|
# Add class method aliases for backwards compatibility
|