Skip to content

Commit 702e80e

Browse files
committed
From RDF with embedded triples.
1 parent ed6e351 commit 702e80e

File tree

2 files changed

+217
-12
lines changed

2 files changed

+217
-12
lines changed

lib/json/ld/from_rdf.rb

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ def from_statements(dataset, useRdfType: false, useNativeTypes: false)
2222
referenced_once = {}
2323

2424
value = nil
25-
ec = @context
2625

2726
# Create an entry for compound-literal node detection
2827
compound_literal_subjects = {}
@@ -33,38 +32,37 @@ def from_statements(dataset, useRdfType: false, useNativeTypes: false)
3332
dataset.each do |statement|
3433
#log_debug("statement") { statement.to_nquads.chomp}
3534

36-
name = statement.graph_name ? ec.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
35+
name = statement.graph_name ? @context.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
3736

3837
# Create a graph entry as needed
3938
node_map = graph_map[name] ||= {}
4039
compound_literal_subjects[name] ||= {}
4140

4241
default_graph[name] ||= {'@id' => name} unless name == '@default'
4342

44-
subject = ec.expand_iri(statement.subject, as_string: true, base: @options[:base])
45-
node = node_map[subject] ||= {'@id' => subject}
43+
subject = statement.subject.to_s
44+
node = node_map[subject] ||= resource_representation(statement.subject,useNativeTypes)
4645

4746
# If predicate is rdf:datatype, note subject in compound literal subjects map
4847
if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF.to_uri + 'direction'
4948
compound_literal_subjects[name][subject] ||= true
5049
end
5150

52-
# If object is an IRI or blank node identifier, 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.
53-
node_map[statement.object.to_s] ||= {'@id' => statement.object.to_s} unless
54-
statement.object.literal?
51+
# 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.
52+
unless statement.object.literal?
53+
node_map[statement.object.to_s] ||=
54+
resource_representation(statement.object, useNativeTypes)
55+
end
5556

5657
# 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.
58+
# XXX JSON-LD* does not support embedded value of @type
5759
if statement.predicate == RDF.type && statement.object.resource? && !useRdfType
5860
merge_value(node, '@type', statement.object.to_s)
5961
next
6062
end
6163

6264
# Set value to the result of using the RDF to Object Conversion algorithm, passing object, rdfDirection, and use native types.
63-
value = ec.expand_value(nil,
64-
statement.object,
65-
rdfDirection: @options[:rdfDirection],
66-
useNativeTypes: useNativeTypes,
67-
base: @options[:base])
65+
value = resource_representation(statement.object, useNativeTypes)
6866

6967
merge_value(node, statement.predicate.to_s, value)
7068

@@ -162,5 +160,31 @@ def from_statements(dataset, useRdfType: false, useNativeTypes: false)
162160
#log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
163161
result
164162
end
163+
164+
private
165+
def resource_representation(resource, useNativeTypes)
166+
case resource
167+
when RDF::Statement
168+
# Note, if either subject or object are a BNode which is used elsewhere,
169+
# this might not work will with the BNode accounting from above.
170+
rep = {'@id' => resource_representation(resource.subject, false)}
171+
if resource.predicate == RDF.type
172+
rep['@id'].merge!('@type' => resource.object.to_s)
173+
else
174+
rep['@id'].merge!(
175+
resource.predicate.to_s =>
176+
as_array(resource_representation(resource.object, useNativeTypes)))
177+
end
178+
rep
179+
when RDF::Literal
180+
@context.expand_value(nil,
181+
resource,
182+
rdfDirection: @options[:rdfDirection],
183+
useNativeTypes: useNativeTypes,
184+
base: @options[:base])
185+
else
186+
{'@id' => resource.to_s}
187+
end
188+
end
165189
end
166190
end

spec/from_rdf_spec.rb

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,187 @@
766766
end
767767
end
768768

769+
context "RDF*" do
770+
{
771+
"subject-iii": {
772+
input: RDF::Statement(
773+
RDF::Statement(
774+
RDF::URI('http://example/s1'),
775+
RDF::URI('http://example/p1'),
776+
RDF::URI('http://example/o1')),
777+
RDF::URI('http://example/p'),
778+
RDF::URI('http://example/o')),
779+
output: %([{
780+
"@id": {
781+
"@id": "http://example/s1",
782+
"http://example/p1": [{"@id": "http://example/o1"}]
783+
},
784+
"http://example/p": [{"@id": "http://example/o"}]
785+
}])
786+
},
787+
"subject-iib": {
788+
input: RDF::Statement(
789+
RDF::Statement(
790+
RDF::URI('http://example/s1'),
791+
RDF::URI('http://example/p1'),
792+
RDF::Node.new('o1')),
793+
RDF::URI('http://example/p'),
794+
RDF::URI('http://example/o')),
795+
output: %([{
796+
"@id": {
797+
"@id": "http://example/s1",
798+
"http://example/p1": [{"@id": "_:o1"}]
799+
},
800+
"http://example/p": [{"@id": "http://example/o"}]
801+
}])
802+
},
803+
"subject-iil": {
804+
input: RDF::Statement(
805+
RDF::Statement(
806+
RDF::URI('http://example/s1'),
807+
RDF::URI('http://example/p1'),
808+
RDF::Literal('o1')),
809+
RDF::URI('http://example/p'),
810+
RDF::URI('http://example/o')),
811+
output: %([{
812+
"@id": {
813+
"@id": "http://example/s1",
814+
"http://example/p1": [{"@value": "o1"}]
815+
},
816+
"http://example/p": [{"@id": "http://example/o"}]
817+
}])
818+
},
819+
"subject-bii": {
820+
input: RDF::Statement(
821+
RDF::Statement(
822+
RDF::Node('s1'),
823+
RDF::URI('http://example/p1'),
824+
RDF::URI('http://example/o1')),
825+
RDF::URI('http://example/p'),
826+
RDF::URI('http://example/o')),
827+
output: %([{
828+
"@id": {
829+
"@id": "_:s1",
830+
"http://example/p1": [{"@id": "http://example/o1"}]
831+
},
832+
"http://example/p": [{"@id": "http://example/o"}]
833+
}])
834+
},
835+
"subject-bib": {
836+
input: RDF::Statement(
837+
RDF::Statement(
838+
RDF::Node('s1'),
839+
RDF::URI('http://example/p1'),
840+
RDF::Node.new('o1')),
841+
RDF::URI('http://example/p'), RDF::URI('http://example/o')),
842+
output: %([{
843+
"@id": {
844+
"@id": "_:s1",
845+
"http://example/p1": [{"@id": "_:o1"}]
846+
},
847+
"http://example/p": [{"@id": "http://example/o"}]
848+
}])
849+
},
850+
"subject-bil": {
851+
input: RDF::Statement(
852+
RDF::Statement(
853+
RDF::Node('s1'),
854+
RDF::URI('http://example/p1'),
855+
RDF::Literal('o1')),
856+
RDF::URI('http://example/p'),
857+
RDF::URI('http://example/o')),
858+
output: %([{
859+
"@id": {
860+
"@id": "_:s1",
861+
"http://example/p1": [{"@value": "o1"}]
862+
},
863+
"http://example/p": [{"@id": "http://example/o"}]
864+
}])
865+
},
866+
"object-iii": {
867+
input: RDF::Statement(
868+
RDF::URI('http://example/s'),
869+
RDF::URI('http://example/p'),
870+
RDF::Statement(
871+
RDF::URI('http://example/s1'),
872+
RDF::URI('http://example/p1'),
873+
RDF::URI('http://example/o1'))),
874+
output: %([{
875+
"@id": "http://example/s",
876+
"http://example/p": [{
877+
"@id": {
878+
"@id": "http://example/s1",
879+
"http://example/p1": [{"@id": "http://example/o1"}]
880+
}
881+
}]
882+
}])
883+
},
884+
"object-iib": {
885+
input: RDF::Statement(
886+
RDF::URI('http://example/s'),
887+
RDF::URI('http://example/p'),
888+
RDF::Statement(
889+
RDF::URI('http://example/s1'),
890+
RDF::URI('http://example/p1'),
891+
RDF::Node.new('o1'))),
892+
output: %([{
893+
"@id": "http://example/s",
894+
"http://example/p": [{
895+
"@id": {
896+
"@id": "http://example/s1",
897+
"http://example/p1": [{"@id": "_:o1"}]
898+
}
899+
}]
900+
}])
901+
},
902+
"object-iil": {
903+
input: RDF::Statement(
904+
RDF::URI('http://example/s'),
905+
RDF::URI('http://example/p'),
906+
RDF::Statement(
907+
RDF::URI('http://example/s1'),
908+
RDF::URI('http://example/p1'),
909+
RDF::Literal('o1'))),
910+
output: %([{
911+
"@id": "http://example/s",
912+
"http://example/p": [{
913+
"@id": {
914+
"@id": "http://example/s1",
915+
"http://example/p1": [{"@value": "o1"}]
916+
}
917+
}]
918+
}])
919+
},
920+
"recursive-subject": {
921+
input: RDF::Statement(
922+
RDF::Statement(
923+
RDF::Statement(
924+
RDF::URI('http://example/s2'),
925+
RDF::URI('http://example/p2'),
926+
RDF::URI('http://example/o2')),
927+
RDF::URI('http://example/p1'),
928+
RDF::URI('http://example/o1')),
929+
RDF::URI('http://example/p'),
930+
RDF::URI('http://example/o')),
931+
output: %([{
932+
"@id": {
933+
"@id": {
934+
"@id": "http://example/s2",
935+
"http://example/p2": [{"@id": "http://example/o2"}]
936+
},
937+
"http://example/p1": [{"@id": "http://example/o1"}]
938+
},
939+
"http://example/p": [{"@id": "http://example/o"}]
940+
}])
941+
},
942+
}.each do |name, params|
943+
it name do
944+
graph = RDF::Graph.new {|g| g << params[:input]}
945+
do_fromRdf(params.merge(input: graph, prefixes: {ex: 'http://example/'}))
946+
end
947+
end
948+
end
949+
769950
context "problems" do
770951
{
771952
"xsd:boolean as value" => {

0 commit comments

Comments
 (0)