Skip to content

Commit f76ea9a

Browse files
committed
Updated toRdf algorithm without creating a node map. Fixes #25.
1 parent 5ccb3d2 commit f76ea9a

File tree

3 files changed

+67
-94
lines changed

3 files changed

+67
-94
lines changed

lib/json/ld/api.rb

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -414,22 +414,11 @@ def self.toRdf(input, options = {}, &block)
414414
# This removes any existing context to allow the given context to be cleanly applied.
415415
log_debug(".toRdf") {"expanded input: #{expanded_input.to_json(JSON_STATE) rescue 'malformed json'}"}
416416

417-
# Generate _nodeMap_
418-
graphs = {'@default' => {}}
419-
create_node_map(expanded_input, graphs)
420-
log_debug(".toRdf") {"node map: #{graphs.to_json(JSON_STATE) rescue 'malformed json'}"}
421-
422-
# Start generating statements
423-
graphs.each do |graph_name, graph|
424-
context = as_resource(graph_name) unless graph_name == '@default'
425-
log_debug(".toRdf") {"graph_name: #{context ? context.to_ntriples : 'null'}"}
426-
# Drop results for graphs which are named with relative IRIs
427-
if graph_name.is_a?(RDF::URI) && !graph_name.absolute
428-
log_debug(".toRdf") {"drop relative graph_name: #{statement.to_ntriples}"}
429-
next
430-
end
431-
graph_to_rdf(graph) do |statement|
417+
# Recurse through input
418+
expanded_input.each do |node|
419+
item_to_rdf(node) do |statement|
432420
next if statement.predicate.node? && !options[:produceGeneralizedRdf]
421+
433422
# Drop results with relative IRIs
434423
relative = statement.to_a.any? do |r|
435424
case r
@@ -446,12 +435,7 @@ def self.toRdf(input, options = {}, &block)
446435
next
447436
end
448437

449-
statement.graph_name = context if context
450-
if block_given?
451-
yield statement
452-
else
453-
results << statement
454-
end
438+
yield statement
455439
end
456440
end
457441
end

lib/json/ld/to_rdf.rb

Lines changed: 60 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,68 +6,14 @@ module ToRDF
66
include Utils
77

88
##
9-
#
10-
# @param [Hash{String => Hash}] active_graph
11-
# A hash of IRI to Node definitions
9+
# @param [Hash{String => Object}] node
10+
# @param [RDF::Resource] graph_name
1211
# @yield statement
1312
# @yieldparam [RDF::Statement] statement
14-
def graph_to_rdf(active_graph, &block)
15-
log_debug('graph_to_rdf') {"graph_to_rdf: #{active_graph.inspect}"}
16-
17-
# For each id-node in active_graph
18-
active_graph.each do |id, node|
19-
# Initialize subject as the IRI or BNode representation of id
20-
subject = as_resource(id)
21-
log_debug("graph_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'} (id: #{id})"}
22-
23-
# For each property-values in node
24-
node.each do |property, values|
25-
case property
26-
when '@type'
27-
# 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
28-
values.each do |value|
29-
object = as_resource(value)
30-
log_debug("graph_to_rdf") {"type: #{object.to_ntriples rescue 'malformed rdf'}"}
31-
yield RDF::Statement(subject, RDF.type, object)
32-
end
33-
when /^@/
34-
# Otherwise, if @type is any other keyword, skip to the next property-values pair
35-
else
36-
# Otherwise, property is an IRI or Blank Node identifier
37-
# Initialize predicate from property as an IRI or Blank node
38-
predicate = as_resource(property)
39-
log_debug("graph_to_rdf") {"predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
40-
41-
# For each item in values
42-
values.each do |item|
43-
if item.has_key?('@list')
44-
log_debug("graph_to_rdf") {"list: #{item.inspect}"}
45-
# 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.
46-
object = parse_list(item['@list']) {|stmt| yield stmt}
47-
48-
# Append a triple composed of subject, prediate, and object to results and add all triples from list_results to results.
49-
yield RDF::Statement(subject, predicate, object)
50-
else
51-
# Otherwise, item is a value object or a node definition. Generate object as the result of the Object Converstion algorithm passing item.
52-
object = parse_object(item)
53-
log_debug("graph_to_rdf") {"object: #{object.to_ntriples rescue 'malformed rdf'}"}
54-
# Append a triple composed of subject, prediate, and literal to results.
55-
yield RDF::Statement(subject, predicate, object)
56-
end
57-
end
58-
end
59-
end
60-
end
61-
end
62-
63-
##
64-
# Parse an item, either a value object or a node definition
65-
# @param [Hash] item
66-
# @return [RDF::Value]
67-
def parse_object(item)
68-
if item.has_key?('@value')
69-
# Otherwise, if element is a JSON object that contains the key @value
70-
# Initialize value to the value associated with the @value key in element. Initialize datatype to the value associated with the @type key in element, or null if element does not contain that key.
13+
# @return RDF::Resource the subject of this item
14+
def item_to_rdf(item, graph_name: nil, &block)
15+
# Just return value object as Term
16+
if value?(item)
7117
value, datatype = item.fetch('@value'), item.fetch('@type', nil)
7218

7319
case value
@@ -88,13 +34,54 @@ def parse_object(item)
8834

8935
# Initialize literal as an RDF literal using value and datatype. If element has the key @language and datatype is xsd:string, then add the value associated with the @language key as the language of the object.
9036
language = item.fetch('@language', nil)
91-
RDF::Literal.new(value, datatype: datatype, language: language)
92-
else
93-
# Otherwise, value must be a node definition containing only @id whos value is an IRI or Blank Node identifier
94-
raise "Expected node reference, got #{item.inspect}" unless item.keys == %w(@id)
95-
# Return value associated with @id as an IRI or Blank node
96-
as_resource(item['@id'])
37+
return RDF::Literal.new(value, datatype: datatype, language: language)
38+
end
39+
40+
subject = item['@id'] ? as_resource(item['@id']) : node
41+
log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
42+
item.each do |property, values|
43+
case property
44+
when '@type'
45+
# 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
46+
values.each do |v|
47+
object = as_resource(v)
48+
log_debug("item_to_rdf") {"type: #{object.to_ntriples rescue 'malformed rdf'}"}
49+
yield RDF::Statement(subject, RDF.type, object, graph_name: graph_name)
50+
end
51+
when '@graph'
52+
# Values are nodes using our subject as the graph name
53+
values.each do |nd|
54+
item_to_rdf(nd, subject, &block)
55+
end
56+
when /^@/
57+
# Otherwise, if @type is any other keyword, skip to the next property-values pair
58+
else
59+
# Otherwise, property is an IRI or Blank Node identifier
60+
# Initialize predicate from property as an IRI or Blank node
61+
predicate = as_resource(property)
62+
log_debug("item_to_rdf") {"predicate: #{predicate.to_ntriples rescue 'malformed rdf'}"}
63+
64+
# For each item in values
65+
values.each do |v|
66+
if list?(v)
67+
log_debug("item_to_rdf") {"list: #{v.inspect}"}
68+
# 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.
69+
object = parse_list(v['@list'], graph_name: graph_name, &block)
70+
71+
# Append a triple composed of subject, prediate, and object to results and add all triples from list_results to results.
72+
yield RDF::Statement(subject, predicate, object, graph_name: graph_name)
73+
else
74+
# Otherwise, item is a value object or a node definition. Generate object as the result of the Object Converstion algorithm passing item.
75+
object = item_to_rdf(v, graph_name: graph_name, &block)
76+
log_debug("item_to_rdf") {"object: #{object.to_ntriples rescue 'malformed rdf'}"}
77+
# yield subject, prediate, and literal to results.
78+
yield RDF::Statement(subject, predicate, object, graph_name: graph_name)
79+
end
80+
end
81+
end
9782
end
83+
84+
subject
9885
end
9986

10087
##
@@ -106,24 +93,24 @@ def parse_object(item)
10693
# @yieldparam [RDF::Resource] statement
10794
# @return [Array<RDF::Statement>]
10895
# Statements for each item in the list
109-
def parse_list(list)
96+
def parse_list(list, graph_name: nil, &block)
11097
log_debug('parse_list') {"list: #{list.inspect}"}
11198

11299
last = list.pop
113100
result = first_bnode = last ? node : RDF.nil
114101

115102
list.each do |list_item|
116103
# Set first to the result of the Object Converstion algorithm passing item.
117-
object = parse_object(list_item)
118-
yield RDF::Statement(first_bnode, RDF.first, object)
104+
object = item_to_rdf(list_item, graph_name: graph_name, &block)
105+
yield RDF::Statement(first_bnode, RDF.first, object, graph_name: graph_name)
119106
rest_bnode = node
120-
yield RDF::Statement(first_bnode, RDF.rest, rest_bnode)
107+
yield RDF::Statement(first_bnode, RDF.rest, rest_bnode, graph_name: graph_name)
121108
first_bnode = rest_bnode
122109
end
123110
if last
124-
object = parse_object(last)
125-
yield RDF::Statement(first_bnode, RDF.first, object)
126-
yield RDF::Statement(first_bnode, RDF.rest, RDF.nil)
111+
object = item_to_rdf(last, graph_name: graph_name, &block)
112+
yield RDF::Statement(first_bnode, RDF.first, object, graph_name: graph_name)
113+
yield RDF::Statement(first_bnode, RDF.rest, RDF.nil, graph_name: graph_name)
127114
end
128115
result
129116
end

script/parse

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ opts = GetoptLong.new(
100100
["--context", GetoptLong::REQUIRED_ARGUMENT],
101101
["--execute", "-e", GetoptLong::REQUIRED_ARGUMENT],
102102
["--expand", GetoptLong::NO_ARGUMENT],
103+
["--expanded", GetoptLong::NO_ARGUMENT],
103104
["--flatten", GetoptLong::NO_ARGUMENT],
104105
["--format", GetoptLong::REQUIRED_ARGUMENT],
105106
["--frame", GetoptLong::REQUIRED_ARGUMENT],
@@ -118,6 +119,7 @@ opts.each do |opt, arg|
118119
when '--context' then options[:context] = arg
119120
when '--execute' then input = arg
120121
when '--expand' then options[:expand] = true
122+
when '--expanded' then options[:expanded] = true
121123
when '--flatten' then options[:flatten] = true
122124
when '--format' then options[:output_format] = arg.to_sym
123125
when '--frame' then options[:frame] = arg

0 commit comments

Comments
 (0)