json-ld 3.2.2 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|