json-ld 3.2.2 → 3.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/json/ld/api.rb +26 -17
- data/lib/json/ld/compact.rb +16 -16
- data/lib/json/ld/context.rb +52 -84
- data/lib/json/ld/expand.rb +23 -23
- data/lib/json/ld/format.rb +81 -115
- data/lib/json/ld/from_rdf.rb +56 -17
- data/lib/json/ld/streaming_writer.rb +6 -6
- data/lib/json/ld/to_rdf.rb +10 -8
- data/lib/json/ld/writer.rb +3 -3
- data/spec/context_spec.rb +31 -11
- data/spec/frame_spec.rb +43 -0
- data/spec/from_rdf_spec.rb +67 -0
- data/spec/to_rdf_spec.rb +133 -0
- metadata +33 -15
data/lib/json/ld/format.rb
CHANGED
@@ -45,8 +45,80 @@ module JSON::LD
|
|
45
45
|
!sample.include?("http://www.w3.org/ns/csvw")
|
46
46
|
end
|
47
47
|
|
48
|
+
# Specify how to execute CLI commands for each supported format.
|
49
|
+
# Derived formats (e.g., YAML-LD) define their own entrypoints.
|
50
|
+
LD_FORMATS = {
|
51
|
+
jsonld: {
|
52
|
+
expand: ->(input, **options) {
|
53
|
+
JSON::LD::API.expand(input,
|
54
|
+
serializer: JSON::LD::API.method(:serializer),
|
55
|
+
**options)
|
56
|
+
},
|
57
|
+
compact: ->(input, **options) {
|
58
|
+
JSON::LD::API.compact(input,
|
59
|
+
options[:context],
|
60
|
+
serializer: JSON::LD::API.method(:serializer),
|
61
|
+
**options)
|
62
|
+
},
|
63
|
+
flatten: ->(input, **options) {
|
64
|
+
JSON::LD::API.flatten(input,
|
65
|
+
options[:context],
|
66
|
+
serializer: JSON::LD::API.method(:serializer),
|
67
|
+
**options)
|
68
|
+
},
|
69
|
+
frame: ->(input, **options) {
|
70
|
+
JSON::LD::API.frame(input,
|
71
|
+
options[:frame],
|
72
|
+
serializer: JSON::LD::API.method(:serializer),
|
73
|
+
**options)
|
74
|
+
},
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
# Execute the body of a CLI command, generic for each different API method based on definitions on {LD_FORMATS}.
|
79
|
+
#
|
80
|
+
# Expands the input, or transforms from an RDF format based on the `:format` option, and then executes the appropriate command based on `:output_format` and does appropriate output serialization.
|
81
|
+
# @private
|
82
|
+
def self.cli_exec(command, files, output: $stdin, **options)
|
83
|
+
output.set_encoding(Encoding::UTF_8) if output.respond_to?(:set_encoding) && RUBY_PLATFORM == "java"
|
84
|
+
options[:base] ||= options[:base_uri]
|
85
|
+
|
86
|
+
# Parse using input format, serialize using output format
|
87
|
+
in_fmt = LD_FORMATS[options.fetch(:format, :jsonld)]
|
88
|
+
out_fmt = LD_FORMATS[options.fetch(:output_format, :jsonld)]
|
89
|
+
|
90
|
+
if in_fmt
|
91
|
+
# Input is a JSON-LD based source (or derived)
|
92
|
+
if files.empty?
|
93
|
+
# If files are empty, either use options[:evaluate] or STDIN
|
94
|
+
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
95
|
+
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
96
|
+
expanded = in_fmt[:expand].call(input, serializer: nil, **options)
|
97
|
+
output.puts out_fmt[command].call(expanded, expanded: true, **options)
|
98
|
+
else
|
99
|
+
files.each do |file|
|
100
|
+
expanded = in_fmt[:expand].call(file, serializer: nil, **options)
|
101
|
+
output.puts out_fmt[command].call(expanded, expanded: true, **options)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
else
|
105
|
+
# Turn RDF into JSON-LD first
|
106
|
+
RDF::CLI.parse(files, **options) do |reader|
|
107
|
+
JSON::LD::API.fromRdf(reader, serializer: nil, **options) do |expanded|
|
108
|
+
output.puts out_fmt[command].call(expanded, expanded: true, **options)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
48
114
|
##
|
49
|
-
# Hash of CLI commands appropriate for this format
|
115
|
+
# Hash of CLI commands appropriate for this format:
|
116
|
+
#
|
117
|
+
# * `expand` => {JSON::LD::API.expand}
|
118
|
+
# * `compact` => {JSON::LD::API.compact}
|
119
|
+
# * `flatten` => {JSON::LD::API.flatten}
|
120
|
+
# * `frame` => {JSON::LD::API.frame}
|
121
|
+
#
|
50
122
|
# @return [Hash{Symbol => Hash}]
|
51
123
|
def self.cli_commands
|
52
124
|
{
|
@@ -54,73 +126,21 @@ module JSON::LD
|
|
54
126
|
description: "Expand JSON-LD or parsed RDF",
|
55
127
|
parse: false,
|
56
128
|
help: "expand [--context <context-file>] files ...",
|
57
|
-
filter: {output_format:
|
129
|
+
filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
|
58
130
|
lambda: ->(files, **options) do
|
59
|
-
out = options[:output] || $stdout
|
60
|
-
out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
61
131
|
options = options.merge(expandContext: options.delete(:context)) if options.key?(:context)
|
62
|
-
|
63
|
-
if options[:format] == :jsonld
|
64
|
-
if files.empty?
|
65
|
-
# If files are empty, either use options[:evaluate] or STDIN
|
66
|
-
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
67
|
-
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
68
|
-
JSON::LD::API.expand(input, validate: false, **options) do |expanded|
|
69
|
-
out.puts expanded.to_json(JSON::LD::JSON_STATE)
|
70
|
-
end
|
71
|
-
else
|
72
|
-
files.each do |file|
|
73
|
-
JSON::LD::API.expand(file, validate: false, **options) do |expanded|
|
74
|
-
out.puts expanded.to_json(JSON::LD::JSON_STATE)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
else
|
79
|
-
# Turn RDF into JSON-LD first
|
80
|
-
RDF::CLI.parse(files, **options) do |reader|
|
81
|
-
JSON::LD::API.fromRdf(reader) do |expanded|
|
82
|
-
out.puts expanded.to_json(JSON::LD::JSON_STATE)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
132
|
+
cli_exec(:expand, files, **options)
|
86
133
|
end,
|
87
134
|
option_use: {context: :removed}
|
88
135
|
},
|
89
136
|
compact: {
|
90
137
|
description: "Compact JSON-LD or parsed RDF",
|
91
138
|
parse: false,
|
92
|
-
filter: {output_format:
|
139
|
+
filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
|
93
140
|
help: "compact --context <context-file> files ...",
|
94
141
|
lambda: ->(files, **options) do
|
95
142
|
raise ArgumentError, "Compacting requires a context" unless options[:context]
|
96
|
-
|
97
|
-
out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
98
|
-
options[:base] ||= options[:base_uri]
|
99
|
-
if options[:format] == :jsonld
|
100
|
-
if files.empty?
|
101
|
-
# If files are empty, either use options[:evaluate] or STDIN
|
102
|
-
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
103
|
-
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
104
|
-
JSON::LD::API.compact(input, options[:context], **options) do |compacted|
|
105
|
-
out.puts compacted.to_json(JSON::LD::JSON_STATE)
|
106
|
-
end
|
107
|
-
else
|
108
|
-
files.each do |file|
|
109
|
-
JSON::LD::API.compact(file, options[:context], **options) do |compacted|
|
110
|
-
out.puts compacted.to_json(JSON::LD::JSON_STATE)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
else
|
115
|
-
# Turn RDF into JSON-LD first
|
116
|
-
RDF::CLI.parse(files, **options) do |reader|
|
117
|
-
JSON::LD::API.fromRdf(reader) do |expanded|
|
118
|
-
JSON::LD::API.compact(expanded, options[:context], **options) do |compacted|
|
119
|
-
out.puts compacted.to_json(JSON::LD::JSON_STATE)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
143
|
+
cli_exec(:compact, files, **options)
|
124
144
|
end,
|
125
145
|
options: [
|
126
146
|
RDF::CLI::Option.new(
|
@@ -136,36 +156,9 @@ module JSON::LD
|
|
136
156
|
description: "Flatten JSON-LD or parsed RDF",
|
137
157
|
parse: false,
|
138
158
|
help: "flatten [--context <context-file>] files ...",
|
139
|
-
filter: {output_format:
|
159
|
+
filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
|
140
160
|
lambda: ->(files, **options) do
|
141
|
-
|
142
|
-
out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
143
|
-
options[:base] ||= options[:base_uri]
|
144
|
-
if options[:format] == :jsonld
|
145
|
-
if files.empty?
|
146
|
-
# If files are empty, either use options[:evaluate] or STDIN
|
147
|
-
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
148
|
-
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
149
|
-
JSON::LD::API.flatten(input, options[:context], **options) do |flattened|
|
150
|
-
out.puts flattened.to_json(JSON::LD::JSON_STATE)
|
151
|
-
end
|
152
|
-
else
|
153
|
-
files.each do |file|
|
154
|
-
JSON::LD::API.flatten(file, options[:context], **options) do |flattened|
|
155
|
-
out.puts flattened.to_json(JSON::LD::JSON_STATE)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
else
|
160
|
-
# Turn RDF into JSON-LD first
|
161
|
-
RDF::CLI.parse(files, **options) do |reader|
|
162
|
-
JSON::LD::API.fromRdf(reader) do |expanded|
|
163
|
-
JSON::LD::API.flatten(expanded, options[:context], **options) do |flattened|
|
164
|
-
out.puts flattened.to_json(JSON::LD::JSON_STATE)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
161
|
+
cli_exec(:compact, files, **options)
|
169
162
|
end,
|
170
163
|
options: [
|
171
164
|
RDF::CLI::Option.new(
|
@@ -188,37 +181,10 @@ module JSON::LD
|
|
188
181
|
description: "Frame JSON-LD or parsed RDF",
|
189
182
|
parse: false,
|
190
183
|
help: "frame --frame <frame-file> files ...",
|
191
|
-
filter: {output_format:
|
184
|
+
filter: {output_format: LD_FORMATS.keys}, # Only shows output format set
|
192
185
|
lambda: ->(files, **options) do
|
193
186
|
raise ArgumentError, "Framing requires a frame" unless options[:frame]
|
194
|
-
|
195
|
-
out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
|
196
|
-
options[:base] ||= options[:base_uri]
|
197
|
-
if options[:format] == :jsonld
|
198
|
-
if files.empty?
|
199
|
-
# If files are empty, either use options[:evaluate] or STDIN
|
200
|
-
input = options[:evaluate] ? StringIO.new(options[:evaluate]) : STDIN
|
201
|
-
input.set_encoding(options.fetch(:encoding, Encoding::UTF_8))
|
202
|
-
JSON::LD::API.frame(input, options[:frame], **options) do |framed|
|
203
|
-
out.puts framed.to_json(JSON::LD::JSON_STATE)
|
204
|
-
end
|
205
|
-
else
|
206
|
-
files.each do |file|
|
207
|
-
JSON::LD::API.frame(file, options[:frame], **options) do |framed|
|
208
|
-
out.puts framed.to_json(JSON::LD::JSON_STATE)
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
else
|
213
|
-
# Turn RDF into JSON-LD first
|
214
|
-
RDF::CLI.parse(files, **options) do |reader|
|
215
|
-
JSON::LD::API.fromRdf(reader) do |expanded|
|
216
|
-
JSON::LD::API.frame(expanded, options[:frame], **options) do |framed|
|
217
|
-
out.puts framed.to_json(JSON::LD::JSON_STATE)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
187
|
+
cli_exec(:compact, files, **options)
|
222
188
|
end,
|
223
189
|
option_use: {context: :removed},
|
224
190
|
options: [
|
data/lib/json/ld/from_rdf.rb
CHANGED
@@ -14,9 +14,11 @@ module JSON::LD
|
|
14
14
|
# @param [Boolean] useRdfType (false)
|
15
15
|
# If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
|
16
16
|
# @param [Boolean] useNativeTypes (false) use native representations
|
17
|
+
# @param extendedRepresentation (false)
|
18
|
+
# Use the extended internal representation for native types.
|
17
19
|
#
|
18
20
|
# @return [Array<Hash>] the JSON-LD document in normalized form
|
19
|
-
def from_statements(dataset, useRdfType: false, useNativeTypes: false)
|
21
|
+
def from_statements(dataset, useRdfType: false, useNativeTypes: false, extendedRepresentation: false)
|
20
22
|
default_graph = {}
|
21
23
|
graph_map = {'@default' => default_graph}
|
22
24
|
referenced_once = {}
|
@@ -30,7 +32,7 @@ module JSON::LD
|
|
30
32
|
|
31
33
|
# For each statement in dataset
|
32
34
|
dataset.each do |statement|
|
33
|
-
#log_debug("statement") { statement.to_nquads.chomp}
|
35
|
+
# log_debug("statement") { statement.to_nquads.chomp}
|
34
36
|
|
35
37
|
name = statement.graph_name ? @context.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
|
36
38
|
|
@@ -41,9 +43,9 @@ module JSON::LD
|
|
41
43
|
default_graph[name] ||= {'@id' => name} unless name == '@default'
|
42
44
|
|
43
45
|
subject = statement.subject.statement? ?
|
44
|
-
resource_representation(statement.subject, useNativeTypes)['@id'].to_json_c14n :
|
46
|
+
resource_representation(statement.subject, useNativeTypes, extendedRepresentation)['@id'].to_json_c14n :
|
45
47
|
statement.subject.to_s
|
46
|
-
node = node_map[subject] ||= resource_representation(statement.subject, useNativeTypes)
|
48
|
+
node = node_map[subject] ||= resource_representation(statement.subject, useNativeTypes, extendedRepresentation)
|
47
49
|
|
48
50
|
# If predicate is rdf:datatype, note subject in compound literal subjects map
|
49
51
|
if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF.to_uri + 'direction'
|
@@ -53,10 +55,10 @@ module JSON::LD
|
|
53
55
|
# If object is an IRI, blank node identifier, or statement, and node map does not have an object member, create one and initialize its value to a new JSON object consisting of a single member @id whose value is set to object.
|
54
56
|
unless statement.object.literal?
|
55
57
|
object = statement.object.statement? ?
|
56
|
-
resource_representation(statement.object, useNativeTypes)['@id'].to_json_c14n :
|
58
|
+
resource_representation(statement.object, useNativeTypes, extendedRepresentation)['@id'].to_json_c14n :
|
57
59
|
statement.object.to_s
|
58
60
|
node_map[object] ||=
|
59
|
-
resource_representation(statement.object, useNativeTypes)
|
61
|
+
resource_representation(statement.object, useNativeTypes, extendedRepresentation)
|
60
62
|
end
|
61
63
|
|
62
64
|
# If predicate equals rdf:type, and object is an IRI or blank node identifier, append object to the value of the @type member of node. If no such member exists, create one and initialize it to an array whose only item is object. Finally, continue to the next RDF triple.
|
@@ -66,7 +68,7 @@ module JSON::LD
|
|
66
68
|
end
|
67
69
|
|
68
70
|
# Set value to the result of using the RDF to Object Conversion algorithm, passing object, rdfDirection, and use native types.
|
69
|
-
value = resource_representation(statement.object, useNativeTypes)
|
71
|
+
value = resource_representation(statement.object, useNativeTypes, extendedRepresentation)
|
70
72
|
|
71
73
|
merge_value(node, statement.predicate.to_s, value)
|
72
74
|
|
@@ -124,7 +126,7 @@ module JSON::LD
|
|
124
126
|
list, list_nodes = [], []
|
125
127
|
|
126
128
|
# If property equals rdf:rest, the value associated to the usages member of node has exactly 1 entry, node has a rdf:first and rdf:rest property, both of which have as value an array consisting of a single element, and node has no other members apart from an optional @type member whose value is an array with a single item equal to rdf:List, node represents a well-formed list node. Continue with the following steps:
|
127
|
-
#log_debug("list element?") {node.to_json(JSON_STATE) rescue 'malformed json'}
|
129
|
+
# log_debug("list element?") {node.to_json(JSON_STATE) rescue 'malformed json'}
|
128
130
|
while property == RDF.rest.to_s &&
|
129
131
|
blank_node?(node) &&
|
130
132
|
referenced_once[node['@id']] &&
|
@@ -163,31 +165,68 @@ module JSON::LD
|
|
163
165
|
node.delete(:usages)
|
164
166
|
result << node unless node_reference?(node)
|
165
167
|
end
|
166
|
-
#log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
|
168
|
+
# log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
|
167
169
|
result
|
168
170
|
end
|
169
171
|
|
170
172
|
private
|
171
|
-
|
173
|
+
|
174
|
+
RDF_LITERAL_NATIVE_TYPES = Set.new([RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double]).freeze
|
175
|
+
|
176
|
+
def resource_representation(resource, useNativeTypes, extendedRepresentation)
|
172
177
|
case resource
|
173
178
|
when RDF::Statement
|
174
179
|
# Note, if either subject or object are a BNode which is used elsewhere,
|
175
180
|
# this might not work will with the BNode accounting from above.
|
176
|
-
rep = {'@id' => resource_representation(resource.subject, false)}
|
181
|
+
rep = {'@id' => resource_representation(resource.subject, false, extendedRepresentation)}
|
177
182
|
if resource.predicate == RDF.type
|
178
183
|
rep['@id'].merge!('@type' => resource.object.to_s)
|
179
184
|
else
|
180
185
|
rep['@id'].merge!(
|
181
186
|
resource.predicate.to_s =>
|
182
|
-
as_array(resource_representation(resource.object, useNativeTypes)))
|
187
|
+
as_array(resource_representation(resource.object, useNativeTypes, extendedRepresentation)))
|
183
188
|
end
|
184
189
|
rep
|
185
190
|
when RDF::Literal
|
186
|
-
@
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
+
base = @options[:base]
|
192
|
+
rdfDirection = @options[:rdfDirection]
|
193
|
+
res = {}
|
194
|
+
|
195
|
+
if resource.datatype == RDF::URI(RDF.to_uri + "JSON") && @context.processingMode('json-ld-1.1')
|
196
|
+
res['@type'] = '@json'
|
197
|
+
res['@value'] = begin
|
198
|
+
::JSON.parse(resource.object)
|
199
|
+
rescue ::JSON::ParserError => e
|
200
|
+
raise JSON::LD::JsonLdError::InvalidJsonLiteral, e.message
|
201
|
+
end
|
202
|
+
elsif useNativeTypes && extendedRepresentation
|
203
|
+
res['@value'] = resource # Raw literal
|
204
|
+
elsif resource.datatype.start_with?("https://www.w3.org/ns/i18n#") && rdfDirection == 'i18n-datatype' && @context.processingMode('json-ld-1.1')
|
205
|
+
lang, dir = resource.datatype.fragment.split('_')
|
206
|
+
res['@value'] = resource.to_s
|
207
|
+
unless lang.empty?
|
208
|
+
if lang !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/
|
209
|
+
if options[:validate]
|
210
|
+
raise JsonLdError::InvalidLanguageMapping, "rdf:language must be valid BCP47: #{lang.inspect}"
|
211
|
+
else
|
212
|
+
warn "rdf:language must be valid BCP47: #{lang.inspect}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
res['@language'] = lang
|
216
|
+
end
|
217
|
+
res['@direction'] = dir
|
218
|
+
elsif useNativeTypes && RDF_LITERAL_NATIVE_TYPES.include?(resource.datatype) && resource.valid?
|
219
|
+
res['@value'] = resource.object
|
220
|
+
else
|
221
|
+
resource.canonicalize! if resource.valid? && resource.datatype == RDF::XSD.double
|
222
|
+
if resource.datatype?
|
223
|
+
res['@type'] = resource.datatype.to_s
|
224
|
+
elsif resource.language?
|
225
|
+
res['@language'] = resource.language.to_s
|
226
|
+
end
|
227
|
+
res['@value'] = resource.to_s
|
228
|
+
end
|
229
|
+
res
|
191
230
|
else
|
192
231
|
{'@id' => resource.to_s}
|
193
232
|
end
|
@@ -19,7 +19,7 @@ module JSON::LD
|
|
19
19
|
else Context.parse(@options[:context])
|
20
20
|
end
|
21
21
|
|
22
|
-
#log_debug("prologue") {"context: #{context.inspect}"}
|
22
|
+
# log_debug("prologue") {"context: #{context.inspect}"}
|
23
23
|
if context
|
24
24
|
@output.puts %({"@context": #{context.serialize['@context'].to_json}, "@graph": [)
|
25
25
|
else
|
@@ -39,7 +39,7 @@ module JSON::LD
|
|
39
39
|
#
|
40
40
|
# @return [void] `self`
|
41
41
|
def stream_statement(statement)
|
42
|
-
#log_debug("ss") {"state: #{@state.inspect}, stmt: #{statement}"}
|
42
|
+
# log_debug("ss") {"state: #{@state.inspect}, stmt: #{statement}"}
|
43
43
|
if @current_graph != statement.graph_name
|
44
44
|
end_graph
|
45
45
|
start_graph(statement.graph_name)
|
@@ -76,7 +76,7 @@ module JSON::LD
|
|
76
76
|
# Complete open statements
|
77
77
|
# @return [void] `self`
|
78
78
|
def stream_epilogue
|
79
|
-
#log_debug("epilogue") {"state: #{@state.inspect}"}
|
79
|
+
# log_debug("epilogue") {"state: #{@state.inspect}"}
|
80
80
|
end_graph
|
81
81
|
if context
|
82
82
|
@output.puts "\n]}"
|
@@ -89,7 +89,7 @@ module JSON::LD
|
|
89
89
|
private
|
90
90
|
|
91
91
|
def start_graph(resource)
|
92
|
-
#log_debug("start_graph") {"state: #{@state.inspect}, resource: #{resource}"}
|
92
|
+
# log_debug("start_graph") {"state: #{@state.inspect}, resource: #{resource}"}
|
93
93
|
if resource
|
94
94
|
@output.puts(",") if %i(wrote_node wrote_graph).include?(@state)
|
95
95
|
@output.puts %({"@id": "#{resource}", "@graph": [)
|
@@ -99,7 +99,7 @@ module JSON::LD
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def end_graph
|
102
|
-
#log_debug("end_graph") {"state: #{@state.inspect}, ctx: #{@current_graph}"}
|
102
|
+
# log_debug("end_graph") {"state: #{@state.inspect}, ctx: #{@current_graph}"}
|
103
103
|
end_node
|
104
104
|
if @current_graph
|
105
105
|
@output.write %(]})
|
@@ -108,7 +108,7 @@ module JSON::LD
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def end_node
|
111
|
-
#log_debug("end_node") {"state: #{@state.inspect}, node: #{@current_node_def.to_json}"}
|
111
|
+
# log_debug("end_node") {"state: #{@state.inspect}, node: #{@current_node_def.to_json}"}
|
112
112
|
@output.puts(",") if %i(wrote_node wrote_graph).include?(@state)
|
113
113
|
if @current_node_def
|
114
114
|
node_def = if context
|
data/lib/json/ld/to_rdf.rb
CHANGED
@@ -25,6 +25,8 @@ module JSON::LD
|
|
25
25
|
datatype = RDF::URI(RDF.to_uri + "JSON") if datatype == '@json'
|
26
26
|
|
27
27
|
case value
|
28
|
+
when RDF::Value
|
29
|
+
return value
|
28
30
|
when TrueClass, FalseClass
|
29
31
|
# If value is true or false, then set value its canonical lexical form as defined in the section Data Round Tripping. If datatype is null, set it to xsd:boolean.
|
30
32
|
value = value.to_s
|
@@ -88,14 +90,14 @@ module JSON::LD
|
|
88
90
|
to_enum(:item_to_rdf, item['@id'], quoted: true).to_a.first
|
89
91
|
end
|
90
92
|
|
91
|
-
#log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
|
93
|
+
# log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
|
92
94
|
item.each do |property, values|
|
93
95
|
case property
|
94
96
|
when '@type'
|
95
97
|
# If property is @type, construct triple as an RDF Triple composed of id, rdf:type, and object from values where id and object are represented either as IRIs or Blank Nodes
|
96
98
|
values.each do |v|
|
97
99
|
object = as_resource(v)
|
98
|
-
#log_debug("item_to_rdf") {"type: #{object.to_ntriples rescue 'malformed rdf'}"}
|
100
|
+
# log_debug("item_to_rdf") {"type: #{object.to_ntriples rescue 'malformed rdf'}"}
|
99
101
|
yield RDF::Statement(subject, RDF.type, object, graph_name: graph_name, quoted: quoted)
|
100
102
|
end
|
101
103
|
when '@graph'
|
@@ -107,12 +109,12 @@ module JSON::LD
|
|
107
109
|
raise "Huh?" unless values.is_a?(Hash)
|
108
110
|
values.each do |prop, vv|
|
109
111
|
predicate = as_resource(prop)
|
110
|
-
#log_debug("item_to_rdf") {"@reverse predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
|
112
|
+
# log_debug("item_to_rdf") {"@reverse predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
|
111
113
|
# For each item in values
|
112
114
|
vv.each do |v|
|
113
115
|
# Item is a node definition. Generate object as the result of the Object Converstion algorithm passing item.
|
114
116
|
object = item_to_rdf(v, graph_name: graph_name, &block)
|
115
|
-
#log_debug("item_to_rdf") {"subject: #{object.to_ntriples rescue 'malformed rdf'}"}
|
117
|
+
# log_debug("item_to_rdf") {"subject: #{object.to_ntriples rescue 'malformed rdf'}"}
|
116
118
|
# yield subject, prediate, and literal to results.
|
117
119
|
yield RDF::Statement(object, predicate, subject, graph_name: graph_name, quoted: quoted)
|
118
120
|
end
|
@@ -127,12 +129,12 @@ module JSON::LD
|
|
127
129
|
# Otherwise, property is an IRI or Blank Node identifier
|
128
130
|
# Initialize predicate from property as an IRI or Blank node
|
129
131
|
predicate = as_resource(property)
|
130
|
-
#log_debug("item_to_rdf") {"predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
|
132
|
+
# log_debug("item_to_rdf") {"predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
|
131
133
|
|
132
134
|
# For each item in values
|
133
135
|
values.each do |v|
|
134
136
|
if list?(v)
|
135
|
-
#log_debug("item_to_rdf") {"list: #{v.inspect}"}
|
137
|
+
# log_debug("item_to_rdf") {"list: #{v.inspect}"}
|
136
138
|
# If item is a list object, initialize list_results as an empty array, and object to the result of the List Conversion algorithm, passing the value associated with the @list key from item and list_results.
|
137
139
|
object = parse_list(v['@list'], graph_name: graph_name, &block)
|
138
140
|
|
@@ -141,7 +143,7 @@ module JSON::LD
|
|
141
143
|
else
|
142
144
|
# Otherwise, item is a value object or a node definition. Generate object as the result of the Object Converstion algorithm passing item.
|
143
145
|
object = item_to_rdf(v, graph_name: graph_name, &block)
|
144
|
-
#log_debug("item_to_rdf") {"object: #{object.to_ntriples rescue 'malformed rdf'}"}
|
146
|
+
# log_debug("item_to_rdf") {"object: #{object.to_ntriples rescue 'malformed rdf'}"}
|
145
147
|
# yield subject, prediate, and literal to results.
|
146
148
|
yield RDF::Statement(subject, predicate, object, graph_name: graph_name, quoted: quoted)
|
147
149
|
end
|
@@ -162,7 +164,7 @@ module JSON::LD
|
|
162
164
|
# @return [Array<RDF::Statement>]
|
163
165
|
# Statements for each item in the list
|
164
166
|
def parse_list(list, graph_name: nil, &block)
|
165
|
-
#log_debug('parse_list') {"list: #{list.inspect}"}
|
167
|
+
# log_debug('parse_list') {"list: #{list.inspect}"}
|
166
168
|
|
167
169
|
last = list.pop
|
168
170
|
result = first_bnode = last ? node : RDF.nil
|
data/lib/json/ld/writer.rb
CHANGED
@@ -298,7 +298,7 @@ module JSON::LD
|
|
298
298
|
stream_epilogue
|
299
299
|
else
|
300
300
|
|
301
|
-
log_debug("writer") { "serialize #{@repo.count} statements, #{@options.inspect}"}
|
301
|
+
# log_debug("writer") { "serialize #{@repo.count} statements, #{@options.inspect}"}
|
302
302
|
result = API.fromRdf(@repo, **@options.merge(serializer: nil))
|
303
303
|
|
304
304
|
# Some options may be indicated from accept parameters
|
@@ -326,11 +326,11 @@ module JSON::LD
|
|
326
326
|
|
327
327
|
if frame = @options[:frame]
|
328
328
|
# Perform framing, if given a frame
|
329
|
-
log_debug("writer") { "frame result"}
|
329
|
+
# log_debug("writer") { "frame result"}
|
330
330
|
result = API.frame(result, frame, **@options.merge(serializer: nil))
|
331
331
|
elsif context
|
332
332
|
# Perform compaction, if we have a context
|
333
|
-
log_debug("writer") { "compact result"}
|
333
|
+
# log_debug("writer") { "compact result"}
|
334
334
|
result = API.compact(result, context, **@options.merge(serializer: nil))
|
335
335
|
end
|
336
336
|
|
data/spec/context_spec.rb
CHANGED
@@ -655,7 +655,6 @@ describe JSON::LD::Context do
|
|
655
655
|
"@language" => "en"
|
656
656
|
}
|
657
657
|
}, logger)
|
658
|
-
expect(subject.to_rb).not_to be_empty
|
659
658
|
end
|
660
659
|
|
661
660
|
it "@vocab" do
|
@@ -665,7 +664,6 @@ describe JSON::LD::Context do
|
|
665
664
|
"@vocab" => "http://example.com/"
|
666
665
|
}
|
667
666
|
}, logger)
|
668
|
-
expect(subject.to_rb).not_to be_empty
|
669
667
|
end
|
670
668
|
|
671
669
|
it "term mappings" do
|
@@ -676,7 +674,6 @@ describe JSON::LD::Context do
|
|
676
674
|
"foo" => "http://example.com/"
|
677
675
|
}
|
678
676
|
}, logger)
|
679
|
-
expect(c.to_rb).not_to be_empty
|
680
677
|
end
|
681
678
|
|
682
679
|
it "@context" do
|
@@ -931,6 +928,37 @@ describe JSON::LD::Context do
|
|
931
928
|
|
932
929
|
end
|
933
930
|
|
931
|
+
describe "#to_rb" do
|
932
|
+
before(:all) {JSON::LD::Context.instance_variable_set(:@cache, nil)}
|
933
|
+
subject {
|
934
|
+
allow(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
|
935
|
+
context.parse("http://example.com/context")
|
936
|
+
}
|
937
|
+
|
938
|
+
it "encodes as utf-8" do
|
939
|
+
expect(subject.to_rb).to match(/encoding: utf-8/)
|
940
|
+
end
|
941
|
+
|
942
|
+
it "marked as auto-generated" do
|
943
|
+
expect(subject.to_rb).to match(/This file generated automatically from/)
|
944
|
+
end
|
945
|
+
|
946
|
+
it "includes URL in preloaded" do
|
947
|
+
expect(subject.to_rb).to include(%(add_preloaded("http://example.com/context")))
|
948
|
+
end
|
949
|
+
|
950
|
+
it "includes processingMode" do
|
951
|
+
expect(subject.to_rb).to include(%(processingMode: "json-ld-1.1"))
|
952
|
+
end
|
953
|
+
|
954
|
+
it "term mappings" do
|
955
|
+
expect(subject.to_rb).to include(%("avatar" => TermDefinition.new("avatar", id: "http://xmlns.com/foaf/0.1/avatar", type_mapping: "@id")))
|
956
|
+
expect(subject.to_rb).to include(%("homepage" => TermDefinition.new("homepage", id: "http://xmlns.com/foaf/0.1/homepage", type_mapping: "@id")))
|
957
|
+
expect(subject.to_rb).to include(%("name" => TermDefinition.new("name", id: "http://xmlns.com/foaf/0.1/name", simple: true)))
|
958
|
+
expect(subject.to_rb).to include(%("xsd" => TermDefinition.new("xsd", id: "http://www.w3.org/2001/XMLSchema#", simple: true, prefix: true)))
|
959
|
+
end
|
960
|
+
end
|
961
|
+
|
934
962
|
describe "#base=" do
|
935
963
|
subject {
|
936
964
|
context.parse({
|
@@ -1553,14 +1581,6 @@ describe JSON::LD::Context do
|
|
1553
1581
|
"native double" => ["foo", 1.1e1, {"@value" => 1.1E1}],
|
1554
1582
|
"native date" => ["foo", Date.parse("2011-12-27"), {"@value" => "2011-12-27", "@type" => RDF::XSD.date.to_s}],
|
1555
1583
|
"native dateTime" =>["foo", DateTime.parse("2011-12-27T10:11:12Z"), {"@value" => "2011-12-27T10:11:12Z", "@type" => RDF::XSD.dateTime.to_s}],
|
1556
|
-
"rdf boolean" => ["foo", RDF::Literal(true), {"@value" => "true", "@type" => RDF::XSD.boolean.to_s}],
|
1557
|
-
"rdf integer" => ["foo", RDF::Literal(1), {"@value" => "1", "@type" => RDF::XSD.integer.to_s}],
|
1558
|
-
"rdf decimal" => ["foo", RDF::Literal::Decimal.new(1.1), {"@value" => "1.1", "@type" => RDF::XSD.decimal.to_s}],
|
1559
|
-
"rdf double" => ["foo", RDF::Literal::Double.new(1.1), {"@value" => "1.1E0", "@type" => RDF::XSD.double.to_s}],
|
1560
|
-
"rdf URI" => ["foo", RDF::URI("foo"), {"@id" => "foo"}],
|
1561
|
-
"rdf date " => ["foo", RDF::Literal(Date.parse("2011-12-27")), {"@value" => "2011-12-27", "@type" => RDF::XSD.date.to_s}],
|
1562
|
-
"rdf nonNeg" => ["foo", RDF::Literal::NonNegativeInteger.new(1), {"@value" => "1", "@type" => RDF::XSD.nonNegativeInteger}],
|
1563
|
-
"rdf float" => ["foo", RDF::Literal::Float.new(1.0), {"@value" => "1.0", "@type" => RDF::XSD.float}],
|
1564
1584
|
"ex:none string" => ["ex:none", "foo", {"@value" => "foo"}],
|
1565
1585
|
"ex:none boolean" =>["ex:none", true, {"@value" => true}],
|
1566
1586
|
"ex:none integer" =>["ex:none", 1, {"@value" => 1}],
|
data/spec/frame_spec.rb
CHANGED
@@ -2463,6 +2463,49 @@ describe JSON::LD::API do
|
|
2463
2463
|
}),
|
2464
2464
|
processingMode: "json-ld-1.1"
|
2465
2465
|
},
|
2466
|
+
"issue #142": {
|
2467
|
+
input: %({
|
2468
|
+
"@context":{
|
2469
|
+
"ex":"http://example.org/vocab#",
|
2470
|
+
"ex:info":{"@type":"@json"},
|
2471
|
+
"ex:other":{"@type":"@json"}
|
2472
|
+
},
|
2473
|
+
"@id":"http://example.org/test/#library",
|
2474
|
+
"@type":"ex:Library",
|
2475
|
+
"ex:info":{
|
2476
|
+
"author":"JOHN",
|
2477
|
+
"pages":200
|
2478
|
+
},
|
2479
|
+
"ex:other":{
|
2480
|
+
"publisher":"JANE"
|
2481
|
+
}
|
2482
|
+
}),
|
2483
|
+
frame: %({
|
2484
|
+
"@context":{
|
2485
|
+
"ex":"http://example.org/vocab#",
|
2486
|
+
"ex:info":{"@type":"@json"},
|
2487
|
+
"ex:other":{"@type":"@json"}
|
2488
|
+
},
|
2489
|
+
"http://example.org/vocab#info":{}
|
2490
|
+
}),
|
2491
|
+
output: %({
|
2492
|
+
"@context": {
|
2493
|
+
"ex": "http://example.org/vocab#",
|
2494
|
+
"ex:info": {"@type": "@json"},
|
2495
|
+
"ex:other": {"@type": "@json"}
|
2496
|
+
},
|
2497
|
+
"@id": "http://example.org/test/#library",
|
2498
|
+
"@type": "ex:Library",
|
2499
|
+
"ex:info": {
|
2500
|
+
"author": "JOHN",
|
2501
|
+
"pages": 200
|
2502
|
+
},
|
2503
|
+
"ex:other": {
|
2504
|
+
"publisher": "JANE"
|
2505
|
+
}
|
2506
|
+
}),
|
2507
|
+
processingMode: "json-ld-1.1"
|
2508
|
+
}
|
2466
2509
|
}.each do |title, params|
|
2467
2510
|
it title do
|
2468
2511
|
do_frame(params)
|