Skip to content

Commit c0db8d2

Browse files
committed
Detect lists having nodes shared across different graphs, and add fromRdf test to check for this.
1 parent 2fde9fe commit c0db8d2

File tree

4 files changed

+104
-68
lines changed

4 files changed

+104
-68
lines changed

bin/jsonld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ rescue
6262
end
6363

6464
parser_options = {
65-
:base => "",
65+
:base => nil,
6666
:progress => false,
6767
:validate => false,
6868
:strict => false,

lib/json/ld/from_rdf.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module FromRDF
1313
def from_statements(input)
1414
default_graph = {}
1515
graph_map = {'@default' => default_graph}
16+
node_usages_map = {}
1617

1718
value = nil
1819
ec = Context.new
@@ -51,9 +52,12 @@ def from_statements(input)
5152
if statement.object.resource?
5253
# Append a new JSON object consisting of three members, node, property, and value to the usages array. The node member is set to a reference to node, property to predicate, and value to a reference to value.
5354
merge_value(node_map[statement.object.to_s], :usages, {
54-
:node => node,
55-
:property => statement.predicate.to_s,
56-
:value => value})
55+
node: node,
56+
property: statement.predicate.to_s,
57+
value: value
58+
})
59+
60+
(node_usages_map[statement.object.to_s] ||= []) << node['@id']
5761
end
5862
end
5963

@@ -69,6 +73,7 @@ def from_statements(input)
6973
# 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:
7074
debug("list element?") {node.to_json(JSON_STATE)}
7175
while property == RDF.rest.to_s &&
76+
node_usages_map[node['@id']].uniq.length == 1 &&
7277
blank_node?(node) &&
7378
node.keys.none? {|k| !["@id", '@type', :usages, RDF.first.to_s, RDF.rest.to_s].include?(k)} &&
7479
Array(node[:usages]).length == 1 &&

spec/from_rdf_spec.rb

Lines changed: 91 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -181,66 +181,101 @@
181181
], @debug)
182182
end
183183
end
184-
184+
185185
context "lists" do
186-
it "should generate literal list" do
187-
input = %(
188-
@prefix : <http://example.com/> .
189-
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
190-
:a :b ("apple" "banana") .
191-
)
192-
expect(serialize(input)).to produce([{
193-
'@id' => "http://example.com/a",
194-
"http://example.com/b" => [{
195-
"@list" => [
196-
{"@value" => "apple"},
197-
{"@value" => "banana"}
198-
]
186+
{
187+
"literal list" => [
188+
%q(
189+
@prefix : <http://example.com/> .
190+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
191+
:a :b ("apple" "banana") .
192+
),
193+
[{
194+
'@id' => "http://example.com/a",
195+
"http://example.com/b" => [{
196+
"@list" => [
197+
{"@value" => "apple"},
198+
{"@value" => "banana"}
199+
]
200+
}]
199201
}]
200-
}], @debug)
201-
end
202-
203-
it "should generate iri list" do
204-
input = %(@prefix : <http://example.com/> . :a :b (:c) .)
205-
expect(serialize(input)).to produce([{
206-
'@id' => "http://example.com/a",
207-
"http://example.com/b" => [{
208-
"@list" => [
209-
{"@id" => "http://example.com/c"}
210-
]
202+
],
203+
"iri list" => [
204+
%q(@prefix : <http://example.com/> . :a :b (:c) .),
205+
[{
206+
'@id' => "http://example.com/a",
207+
"http://example.com/b" => [{
208+
"@list" => [
209+
{"@id" => "http://example.com/c"}
210+
]
211+
}]
211212
}]
212-
}], @debug)
213-
end
214-
215-
it "should generate empty list" do
216-
input = %(@prefix : <http://example.com/> . :a :b () .)
217-
expect(serialize(input)).to produce([{
218-
'@id' => "http://example.com/a",
219-
"http://example.com/b" => [{"@list" => []}]
220-
}], @debug)
221-
end
222-
223-
it "should generate single element list" do
224-
input = %(@prefix : <http://example.com/> . :a :b ( "apple" ) .)
225-
expect(serialize(input)).to produce([{
226-
'@id' => "http://example.com/a",
227-
"http://example.com/b" => [{"@list" => [{"@value" => "apple"}]}]
228-
}], @debug)
229-
end
230-
231-
it "should generate single element list without @type" do
232-
input = %(
233-
@prefix : <http://example.com/> . :a :b ( _:a ) . _:a :b "foo" .)
234-
expect(serialize(input)).to produce([
235-
{
236-
'@id' => "_:a",
237-
"http://example.com/b" => [{"@value" => "foo"}]
238-
},
239-
{
213+
],
214+
"empty list" => [
215+
%q(@prefix : <http://example.com/> . :a :b () .),
216+
[{
240217
'@id' => "http://example.com/a",
241-
"http://example.com/b" => [{"@list" => [{"@id" => "_:a"}]}]
218+
"http://example.com/b" => [{"@list" => []}]
219+
}]
220+
],
221+
"single element list" => [
222+
%q(@prefix : <http://example.com/> . :a :b ( "apple" ) .),
223+
[{
224+
'@id' => "http://example.com/a",
225+
"http://example.com/b" => [{"@list" => [{"@value" => "apple"}]}]
226+
}]
227+
],
228+
"single element list without @type" => [
229+
%q(@prefix : <http://example.com/> . :a :b ( _:a ) . _:a :b "foo" .),
230+
[
231+
{
232+
'@id' => "_:a",
233+
"http://example.com/b" => [{"@value" => "foo"}]
234+
},
235+
{
236+
'@id' => "http://example.com/a",
237+
"http://example.com/b" => [{"@list" => [{"@id" => "_:a"}]}]
238+
},
239+
]
240+
],
241+
"multiple graphs with shared BNode" => [
242+
%q(
243+
<http://www.example.com/z> <http://www.example.com/q> _:z0 <http://www.example.com/G> .
244+
_:z0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "cell-A" <http://www.example.com/G> .
245+
_:z0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:z1 <http://www.example.com/G> .
246+
_:z1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "cell-B" <http://www.example.com/G> .
247+
_:z1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://www.example.com/G> .
248+
<http://www.example.com/x> <http://www.example.com/p> _:z1 <http://www.example.com/G1> .
249+
),
250+
[{
251+
"@id" => "http://www.example.com/G",
252+
"@graph" => [{
253+
"@id" => "_:z0",
254+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [{"@value" => "cell-A"}],
255+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [{"@id" => "_:z1"}]
256+
}, {
257+
"@id" => "_:z1",
258+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [{"@value" => "cell-B"}],
259+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [{"@list" => []}]
260+
}, {
261+
"@id" => "http://www.example.com/z",
262+
"http://www.example.com/q" => [{"@id" => "_:z0"}]
263+
}]
242264
},
243-
], @debug)
265+
{
266+
"@id" => "http://www.example.com/G1",
267+
"@graph" => [{
268+
"@id" => "http://www.example.com/x",
269+
"http://www.example.com/p" => [{"@id" => "_:z1"}]
270+
}]
271+
}],
272+
RDF::NQuads::Reader
273+
],
274+
}.each do |name, (input, output, reader)|
275+
it name do
276+
r = serialize(input, :reader => reader)
277+
expect(r).to produce(output, @debug)
278+
end
244279
end
245280
end
246281

@@ -363,7 +398,7 @@
363398
end
364399

365400
def parse(input, options = {})
366-
reader = options[:reader] || RDF::Turtle::Reader
401+
reader = options[:reader] || RDF::TriG::Reader
367402
RDF::Repository.new << reader.new(input, options)
368403
end
369404

spec/to_rdf_spec.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,7 @@
306306

307307
context "lists" do
308308
{
309-
"Empty" =>
310-
[
309+
"Empty" => [
311310
%q({
312311
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
313312
"@id": "http://greggkellogg.net/foaf#me",
@@ -317,8 +316,7 @@
317316
<http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
318317
)
319318
],
320-
"single value" =>
321-
[
319+
"single value" => [
322320
%q({
323321
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
324322
"@id": "http://greggkellogg.net/foaf#me",
@@ -330,8 +328,7 @@
330328
_:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
331329
)
332330
],
333-
"single value (with coercion)" =>
334-
[
331+
"single value (with coercion)" => [
335332
%q({
336333
"@context": {
337334
"foaf": "http://xmlns.com/foaf/0.1/",
@@ -346,8 +343,7 @@
346343
_:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
347344
)
348345
],
349-
"multiple values" =>
350-
[
346+
"multiple values" => [
351347
%q({
352348
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
353349
"@id": "http://greggkellogg.net/foaf#me",

0 commit comments

Comments
 (0)