json-ld 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/{README.markdown → README.md} +15 -3
  2. data/VERSION +1 -1
  3. data/lib/json/ld.rb +50 -87
  4. data/lib/json/ld/api.rb +85 -96
  5. data/lib/json/ld/compact.rb +103 -170
  6. data/lib/json/ld/context.rb +1137 -0
  7. data/lib/json/ld/expand.rb +212 -171
  8. data/lib/json/ld/extensions.rb +17 -1
  9. data/lib/json/ld/flatten.rb +145 -78
  10. data/lib/json/ld/frame.rb +1 -1
  11. data/lib/json/ld/from_rdf.rb +73 -103
  12. data/lib/json/ld/reader.rb +3 -1
  13. data/lib/json/ld/resource.rb +3 -3
  14. data/lib/json/ld/to_rdf.rb +98 -109
  15. data/lib/json/ld/utils.rb +54 -4
  16. data/lib/json/ld/writer.rb +5 -5
  17. data/spec/api_spec.rb +3 -28
  18. data/spec/compact_spec.rb +76 -113
  19. data/spec/{evaluation_context_spec.rb → context_spec.rb} +307 -563
  20. data/spec/expand_spec.rb +163 -187
  21. data/spec/flatten_spec.rb +119 -114
  22. data/spec/frame_spec.rb +5 -5
  23. data/spec/from_rdf_spec.rb +44 -24
  24. data/spec/suite_compact_spec.rb +11 -8
  25. data/spec/suite_error_expand_spec.rb +23 -0
  26. data/spec/suite_expand_spec.rb +3 -7
  27. data/spec/suite_flatten_spec.rb +3 -3
  28. data/spec/suite_frame_spec.rb +6 -6
  29. data/spec/suite_from_rdf_spec.rb +3 -3
  30. data/spec/suite_helper.rb +13 -6
  31. data/spec/suite_to_rdf_spec.rb +16 -10
  32. data/spec/test-files/test-1-rdf.ttl +4 -3
  33. data/spec/test-files/test-3-rdf.ttl +2 -1
  34. data/spec/test-files/test-4-compacted.json +1 -1
  35. data/spec/test-files/test-5-rdf.ttl +3 -2
  36. data/spec/test-files/test-6-rdf.ttl +3 -2
  37. data/spec/test-files/test-7-compacted.json +3 -3
  38. data/spec/test-files/test-7-expanded.json +3 -3
  39. data/spec/test-files/test-7-rdf.ttl +7 -6
  40. data/spec/test-files/test-9-compacted.json +1 -1
  41. data/spec/to_rdf_spec.rb +67 -75
  42. data/spec/writer_spec.rb +2 -0
  43. metadata +36 -24
  44. checksums.yaml +0 -15
  45. data/lib/json/ld/evaluation_context.rb +0 -984
@@ -32,6 +32,13 @@ module RDF
32
32
  end
33
33
  end
34
34
 
35
+ class Node
36
+ # Odd case of appending to a BNode identifier
37
+ def +(value)
38
+ Node.new(id + value.to_s)
39
+ end
40
+ end
41
+
35
42
  class Literal
36
43
  class Double
37
44
  ##
@@ -63,8 +70,9 @@ class Array
63
70
  # @yieldparam [Object] b
64
71
  # @yieldreturn [Integer]
65
72
  # @return [Array]
66
- KW_ORDER = %(@id @value @type @language @vocab @container @graph @list @set)
73
+ KW_ORDER = %w(@base @id @value @type @language @vocab @container @graph @list @set @index).freeze
67
74
 
75
+ # Order, considering keywords to come before other strings
68
76
  def kw_sort
69
77
  self.sort do |a, b|
70
78
  a = "@#{KW_ORDER.index(a)}" if KW_ORDER.include?(a)
@@ -72,6 +80,14 @@ class Array
72
80
  a <=> b
73
81
  end
74
82
  end
83
+
84
+ # Order terms, length first, then lexographically
85
+ def term_sort
86
+ self.sort do |a, b|
87
+ len_diff = a.length <=> b.length
88
+ len_diff == 0 ? a <=> b : len_diff
89
+ end
90
+ end
75
91
  end
76
92
 
77
93
  if RUBY_VERSION < "1.9"
@@ -3,104 +3,171 @@ module JSON::LD
3
3
  include Utils
4
4
 
5
5
  ##
6
- # Build hash of nodes used for framing. Also returns flattened representation of input.
6
+ # This algorithm creates a JSON object node map holding an indexed representation of the graphs and nodes represented in the passed expanded document. All nodes that are not uniquely identified by an IRI get assigned a (new) blank node identifier. The resulting node map will have a member for every graph in the document whose value is another object with a member for every node represented in the document. The default graph is stored under the @default member, all other graphs are stored under their graph name.
7
7
  #
8
8
  # @param [Array, Hash] element
9
9
  # Expanded element
10
10
  # @param [Hash{String => Hash}] node_map
11
11
  # map of nodes
12
- # @param [String] graph
12
+ # @param [String] active_graph
13
13
  # Graph name for results
14
14
  # @param [Array] list
15
15
  # List for saving list elements
16
16
  # @param [String] id (nil)
17
17
  # Identifier already associated with element
18
- def generate_node_map(element, node_map, graph, list = nil, id = nil)
18
+ def generate_node_map(element,
19
+ node_map,
20
+ active_graph = '@default',
21
+ active_subject = nil,
22
+ active_property = nil,
23
+ list = nil)
19
24
  depth do
20
- debug("nodeMap") {"element: #{element.inspect}, graph: #{graph}"}
25
+ debug("node_map") {"active_graph: #{active_graph}, element: #{element.inspect}"}
21
26
  if element.is_a?(Array)
22
- element.map {|o| generate_node_map(o, node_map, graph, list)}
23
- elsif !element.is_a?(Hash) || value?(element)
24
- list << element if list
27
+ # If element is an array, process each entry in element recursively, using this algorithm and return
28
+ element.map {|o|
29
+ generate_node_map(o,
30
+ node_map,
31
+ active_graph,
32
+ active_subject,
33
+ active_property,
34
+ list)
35
+ }
25
36
  else
26
- # If the @id property exists and is an IRI, set id to its value, otherwise set it to a blank node identifier created by the Generate Blank Node Identifier algorithm.
27
- # FIXME: (spec) id passed when it is allocated, so it is not re-allocated here.
28
- id ||= blank_node?(element) ? namer.get_name(element.fetch('@id', nil)) : element['@id']
29
-
30
- # If list is not nil, append a new node reference to list using id at the value for @id.
31
- list << {'@id' => id} if list
32
-
33
- # Let nodes be the value in nodeMap where the key is graph; if no such value exists, insert a new JSON object for the key graph.
34
- debug("nodeMap") {"new graph: #{graph}"} unless node_map.has_key?(graph)
35
- nodes = (node_map[graph] ||= Hash.ordered)
36
-
37
- # If id is not in nodes, create a new JSON object node with id as the value for @id. Let node be the value of id in nodes.
38
- debug("nodeMap") {"new node: #{id}"} unless nodes.has_key?(id)
39
- node = (nodes[id] ||= Hash.ordered)
40
- node['@id'] ||= id
41
-
42
- # For each property that is not @id and each value in element ordered by property:
43
- element.each do |prop, value|
44
- case prop
45
- when '@id'
46
- # Skip @id, already assigned
47
- when '@graph'
48
- # If property is @graph, recursively call this algorithm passing value for element, nodeMap, nil for list and if graph is @merged use graph, otherwise use id for graph and then continue.
49
- graph = graph == '@merged' ? '@merged' : id
50
- generate_node_map(value, node_map, graph)
51
- when /^@(?!type)/
52
- # If property is not @type and is a keyword, merge property and value into node and then continue.
53
- debug("nodeMap") {"merge keyword#{prop}: #{value.inspect}"}
54
- node[prop] = value
37
+ # Otherwise element is a JSON object. Reference the JSON object which is the value of the active graph member of node map using the variable graph. If the active subject is null, set node to null otherwise reference the active subject member of graph using the variable node.
38
+ # Spec FIXME: initializing it to an empty JSON object, if necessary
39
+ raise "Expected element to be a hash, was #{element.class}" unless element.is_a?(Hash)
40
+ graph = node_map[active_graph] ||= Hash.ordered
41
+ node = graph[active_subject] if active_subject
42
+
43
+ # If element has an @type member, perform for each item the following steps:
44
+ if element.has_key?('@type')
45
+ types = [element['@type']].flatten.map do |item|
46
+ # If item is a blank node identifier, replace it with a newly generated blank node identifier passing item for identifier.
47
+ item = namer.get_name(item) if blank_node?(item)
48
+
49
+ # If graph has no member item, create it and initialize its value to a JSON object consisting of a single member @id with the value item.
50
+ graph[item] ||= {'@id' => item}
51
+ item
52
+ end
53
+
54
+ element['@type'] = element['@type'].is_a?(Array) ? types : types.first
55
+ end
56
+
57
+ # If element has an @value member, perform the following steps:
58
+ if value?(element)
59
+ unless list
60
+ # If no list has been passed, merge element into the active property member of the active subject in graph.
61
+ merge_value(node, active_property, element)
55
62
  else
56
- raise InvalidFrame::Syntax,
57
- "unexpected value: #{value.inspect}, expected array" unless
58
- value.is_a?(Array)
59
-
60
- # For each value v in the array value:
61
- value.each do |v|
62
- if node?(v) || node_reference?(v)
63
- debug("nodeMap") {"node value #{prop}: #{v.inspect}"}
64
- # If v is a node definition or node reference:
65
- # If the property @id is not an IRI or it does not exist, map v to a new blank node identifier to avoid collisions.
66
- name = blank_node?(v) ?
67
- namer.get_name(v.fetch('@id', nil)) :
68
- v['@id']
69
-
70
- # If one does not already exist, add a node reference for v into node for property.
71
- node[prop] ||= []
72
- node[prop] << {'@id' => name} unless node[prop].any? {|n|
73
- node_reference?(n) && n['@id'] == name
74
- }
75
-
76
- # Recursively call this algorithm passing v for value, nodeMap, graph, and nil for list.
77
- generate_node_map(v, node_map, graph, nil, name)
78
- elsif list?(v)
79
- # Otherwise if v has the property @list then recursively call this algorithm with the value of @list as element, nodeMap, graph, and a new array flattenedList as list.
80
- debug("nodeMap") {"list value #{prop}: #{v.inspect}"}
81
- flattened_list = []
82
- generate_node_map(v['@list'],
83
- node_map,
84
- graph,
85
- flattened_list)
86
- # Create a new JSON object with the property @list set to flattenedList and add it to node for property.
87
- (node[prop] ||= []) << {'@list' => flattened_list}
88
- elsif prop == '@type'
89
- # Otherwise, if property is @type and v is not an IRI, generate a new blank node identifier and add it to node for property.
90
- # FIXME: @type shouldn't really be a BNode, and not clear how we even get here from expansion
91
- name = blank_node?({'@id' => v}) ? namer.get_name(v) : v
92
- (node[prop] ||= []) << name
93
- else
94
- debug("nodeMap") {"value #{prop}: #{v.inspect}"}
95
- # Otherwise, add v to node for property.
96
- (node[prop] ||= []) << v
63
+ # Otherwise, append element to the @list member of list.
64
+ merge_value(list, '@list', element)
65
+ end
66
+ elsif list?(element)
67
+ # Otherwise, if element has an @list member, perform the following steps:
68
+ # Initialize a new JSON object result having a single member @list whose value is initialized to an empty array.
69
+ result = {'@list' => []}
70
+
71
+ # Recursively call this algorithm passing the value of element's @list member as new element and result as list.
72
+ generate_node_map(element['@list'],
73
+ node_map,
74
+ active_graph,
75
+ active_subject,
76
+ active_property,
77
+ result)
78
+
79
+ # Append result to the the value of the active property member of node.
80
+ merge_value(node, active_property, result)
81
+ else
82
+ # Otherwise element is a node object, perform the following steps:
83
+
84
+ # If element has an @id member, set id to its value and remove the member from element. If id is a blank node identifier, replace it with a newly generated blank node identifier passing id for identifier.
85
+ # Otherwise, set id to the result of the Generate Blank Node Identifier algorithm passing null for identifier.
86
+ id = element.delete('@id')
87
+ id = namer.get_name(id) if blank_node?(id)
88
+ debug("node_map") {"id: #{id.inspect}"}
89
+
90
+ # If graph does not contain a member id, create one and initialize it to a JSON object consisting of a single member @id whose value is set to id.
91
+ graph[id] ||= Hash.ordered
92
+ graph[id]['@id'] ||= id
93
+
94
+ # If active property is not null, perform the following steps:
95
+ if active_property
96
+ # Create a new JSON object reference consisting of a single member @id whose value is id.
97
+ reference = Hash.ordered
98
+ reference['@id'] = id
99
+
100
+ # If list is null:
101
+ unless list
102
+ merge_value(node, active_property, reference)
103
+ else
104
+ merge_value(list, '@list', reference)
105
+ end
106
+ end
107
+
108
+ # Reference the value of the id member of graph using the variable node.
109
+ node = graph[id]
110
+
111
+ # If element has an @type key, append each item of its associated array to the array associated with the @type key of node unless it is already in that array. Finally remove the @type member from element.
112
+ if element.has_key?('@type')
113
+ [element.delete('@type')].flatten.each do |t|
114
+ merge_value(node, '@type', t)
115
+ end
116
+ end
117
+
118
+ # If element has an @index member, set the @index member of node to its value. If node has already an @index member with a different value, a conflicting indexes error has been detected and processing is aborted. Otherwise, continue by removing the @index member from element.
119
+ if element.has_key?('@index')
120
+ raise ProcessingError::ConflictingIndexesError,
121
+ "Element already has index #{node['@index']} dfferent from #{element['@index']}" if
122
+ node['@index'] && node['@index'] != element['@index']
123
+ node['@index'] = element.delete('@index')
124
+ end
125
+
126
+ # If element has an @reverse member:
127
+ if element.has_key?('@reverse')
128
+ element.delete('@reverse').each do |property, values|
129
+ values.each do |value|
130
+ debug("node_map") {"@reverse(#{id}): #{value.inspect}"}
131
+ # If value has a property member, append referenced node to its value; otherwise create a property member whose value is an array containing referenced node.
132
+ merge_value(value, property, {'@id' => id})
133
+
134
+ # Recursively invoke this algorithm passing value for element, node map, and active graph.
135
+ generate_node_map(value,
136
+ node_map,
137
+ active_graph)
97
138
  end
98
139
  end
99
140
  end
141
+
142
+ # If element has an @graph member, recursively invoke this algorithm passing the value of the @graph member for element, node map, and id for active graph before removing the @graph member from element.
143
+ if element.has_key?('@graph')
144
+ generate_node_map(element.delete('@graph'),
145
+ node_map,
146
+ id)
147
+ end
148
+
149
+ # Finally, for each key-value pair property-value in element ordered by property perform the following steps:
150
+ element.keys.sort.each do |property|
151
+ value = element[property]
152
+
153
+ # If property is a blank node identifier, replace it with a newly generated blank node identifier passing property for identifier.
154
+ property = namer.get_name(property) if blank_node?(property)
155
+
156
+ # If node does not have a property member, create one and initialize its value to an empty array.
157
+ node[property] ||= []
158
+
159
+ # Recursively invoke this algorithm passing value as new element, id as new active subject, and property as new active property.
160
+ generate_node_map(value,
161
+ node_map,
162
+ active_graph,
163
+ id,
164
+ property,
165
+ list)
166
+ end
100
167
  end
101
168
  end
102
169
 
103
- debug("nodeMap") {node_map.to_json(JSON_STATE)}
170
+ debug("node_map") {node_map.to_json(JSON_STATE)}
104
171
  end
105
172
  end
106
173
  end
@@ -255,7 +255,7 @@ module JSON::LD
255
255
 
256
256
  def validate_frame(state, frame)
257
257
  raise InvalidFrame::Syntax,
258
- "Invalid JSON-LD syntax; a JSON-LD frame must be an object" unless frame.is_a?(Hash)
258
+ "Invalid JSON-LD syntax; a JSON-LD frame must be an object: #{frame.inspect}" unless frame.is_a?(Hash)
259
259
  end
260
260
 
261
261
  # Return value of @name in frame, or default from state if it doesn't exist
@@ -11,11 +11,11 @@ module JSON::LD
11
11
  # @param [Array<RDF::Statement>, RDF::Enumerable] input
12
12
  # @return [Array<Hash>] the JSON-LD document in normalized form
13
13
  def from_statements(input)
14
- defaultGraph = {:nodes => {}, :listMap => {}, :name => ''}
15
- graphs = {'' => defaultGraph}
14
+ default_graph = {}
15
+ graph_map = {'@default' => default_graph}
16
16
 
17
17
  value = nil
18
- ec = EvaluationContext.new
18
+ ec = Context.new
19
19
 
20
20
  # Create a map for node to object representation
21
21
 
@@ -23,125 +23,95 @@ module JSON::LD
23
23
  input.each do |statement|
24
24
  debug("statement") { statement.to_nquads.chomp}
25
25
 
26
- subject = ec.expand_iri(statement.subject).to_s
27
- name = statement.context ? ec.expand_iri(statement.context).to_s : ''
26
+ name = statement.context ? ec.expand_iri(statement.context).to_s : '@default'
28
27
 
29
28
  # Create a graph entry as needed
30
- graph = graphs[name] ||= {:nodes => {}, :listMap => {}, :name => name}
29
+ node_map = graph_map[name] ||= {}
30
+ default_graph[name] ||= {'@id' => name} unless name == '@default'
31
31
 
32
- case statement.predicate
33
- when RDF.first
34
- # If property is rdf:first,
35
- # create a new entry in _listMap_ for _name_ and _subject_ and an array value
36
- # containing the object representation and continue to the next statement.
37
- listMap = graph[:listMap]
38
- entry = listMap[subject] ||= {}
39
- object_rep = ec.expand_value(nil, statement.object)
40
- entry[:first] = object_rep
41
- debug("rdf:first") { "save entry for #{subject.inspect} #{entry.inspect}"}
42
- next
43
- when RDF.rest
44
- # If property is rdf:rest,
45
- # and object is a blank node,
46
- # create a new entry in _restMap_ for _name_ and _subject_ and a value being the
47
- # result of IRI expansion on the object and continue to the next statement.
48
- next unless statement.object.is_a?(RDF::Node)
49
-
50
- listMap = graph[:listMap]
51
- entry = listMap[subject] ||= {}
52
-
53
- object_rep = ec.expand_iri(statement.object).to_s
54
- entry[:rest] = object_rep
55
- debug("rdf:rest") { "save entry for #{subject.inspect} #{entry.inspect}"}
32
+ subject = ec.expand_iri(statement.subject).to_s
33
+ node = node_map[subject] ||= {'@id' => subject}
34
+
35
+ # If object is an IRI or blank node identifier, does not equal rdf:nil, 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.
36
+ node_map[statement.object.to_s] ||= {'@id' => statement.object.to_s} unless
37
+ statement.object.literal? || statement.object == RDF.nil
38
+
39
+ # 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.
40
+ if statement.predicate == RDF.type && statement.object.resource?
41
+ merge_value(node, '@type', statement.object.to_s)
56
42
  next
57
43
  end
58
44
 
59
- # Add entry to default graph for name unless it is empty
60
- defaultGraph[:nodes][name] ||= {'@id' => name} unless name.empty?
61
-
62
- # Get value from graph nodes for subject, initializing it to a new node declaration for subject if it does not exist
63
- debug("@id") { "new subject: #{subject}"} unless graph[:nodes].has_key?(subject)
64
- value = graph[:nodes][subject] ||= {'@id' => subject}
65
-
66
- # If property is http://www.w3.org/1999/02/22-rdf-syntax-ns#type
67
- # and the useRdfType option is not true
68
- if statement.predicate == RDF.type && !@options[:useRdfType]
69
- object = ec.expand_iri(statement.object).to_s
70
- debug("@type") { object.inspect}
71
- # append the string representation of object to the array value for the key @type, creating
72
- # an entry if necessary
73
- (value['@type'] ||= []) << object
74
- # FIXME: 3.7) If object is a typed literal and the useNativeTypes option is set to true:
75
- elsif statement.object == RDF.nil
76
- # Otherwise, if object is http://www.w3.org/1999/02/22-rdf-syntax-ns#nil, let
77
- # key be the string representation of predicate. Set the value
78
- # for key to an empty @list representation {"@list": []}
79
- key = ec.expand_iri(statement.predicate).to_s
80
- (value[key] ||= []) << {"@list" => []}
45
+ # If object equals rdf:nil and predicate does not equal rdf:rest, set value to a new JSON object consisting of a single member @list whose value is set to an empty array.
46
+ value = if statement.object == RDF.nil && statement.predicate != RDF.rest
47
+ {'@list' => []}
81
48
  else
82
- # Otherwise, let key be the string representation of predicate and
83
- # let object representation be object represented in expanded form as
84
- # described in Value Expansion.
85
- key = ec.expand_iri(statement.predicate).to_s
86
- object = ec.expand_value(key, statement.object, @options)
87
- if blank_node?(object)
88
- # if object is an Unnamed Node, set as the head element in the listMap
89
- # entry for object
90
- listMap = graph[:listMap]
91
- entry = listMap[object['@id']] ||= {}
92
- entry[:head] = object
93
- debug("bnode") { "save entry #{entry.inspect}"}
94
- end
49
+ ec.expand_value(nil, statement.object, @options)
50
+ end
95
51
 
96
- debug("key/value") { "key: #{key}, :value #{object.inspect}"}
97
-
98
- # append the object object representation to the array value for key, creating
99
- # an entry if necessary
100
- (value[key] ||= []) << object
52
+ merge_value(node, statement.predicate.to_s, value)
53
+
54
+ # If object is a blank node identifier and predicate equals neither rdf:first nor rdf:rest, it might represent the head of a RDF list:
55
+ if statement.object.node? && ![RDF.first, RDF.rest].include?(statement.predicate)
56
+ merge_value(node_map[statement.object.to_s], :usages, value)
101
57
  end
102
58
  end
103
59
 
104
- # Build lists for each graph
105
- graphs.each do |name, graph|
106
- graph[:listMap].each do |subject, entry|
107
- debug("listMap(#{name}, #{subject})") { entry.inspect}
108
- if entry.has_key?(:head) && entry.has_key?(:first)
109
- debug("@list") { "List head for #{subject.inspect} in #{name.inspect}: #{entry.inspect}"}
110
- value = entry[:head]
111
- value.delete('@id')
112
- list = value['@list'] = [entry[:first]].compact
113
-
114
- while rest = entry.fetch(:rest, nil)
115
- entry = graph[:listMap][rest]
116
- debug(" => ") { "add #{entry.inspect}"}
117
- raise JSON::LD::ProcessingError, "list entry missing rdf:first" unless entry.has_key?(:first)
118
- list << entry[:first]
60
+ # For each name and graph object in graph map:
61
+ graph_map.each do |name, graph_object|
62
+ subjects = graph_object.keys
63
+ subjects.each do |subj|
64
+ next unless graph_object.has_key?(subj)
65
+ node = graph_object[subj]
66
+ next unless node[:usages].is_a?(Array) && node[:usages].length == 1
67
+ debug("list head") {node.to_json(JSON_STATE)}
68
+ value = node[:usages].first
69
+ list, list_nodes, subject = [], [], subj
70
+
71
+ while subject != RDF.nil.to_s && list
72
+ if node.nil? ||
73
+ !blank_node?(node) ||
74
+ node.keys.any? {|k| !["@id", :usages, RDF.first.to_s, RDF.rest.to_s].include?(k)} ||
75
+ !(f = node[RDF.first.to_s]).is_a?(Array) || f.length != 1 ||
76
+ !(r = node[RDF.rest.to_s]).is_a?(Array) || r.length != 1 || !node_reference?(r.first) ||
77
+ list_nodes.include?(subject)
78
+
79
+ debug("list") {"not valid list element: #{node.to_json(JSON_STATE)}"}
80
+ list = nil
81
+ else
82
+ list << f.first
83
+ list_nodes << node['@id']
84
+ subject = r.first['@id']
85
+ node = graph_object[subject]
86
+ debug("list") {"rest: #{node.to_json(JSON_STATE)}"}
87
+ list = nil if list_nodes.include?(subject)
119
88
  end
120
89
  end
90
+
91
+ next if list.nil?
92
+ value.delete('@id')
93
+ value['@list'] = list
94
+ list_nodes.each {|s| graph_object.delete(s)}
121
95
  end
122
96
  end
123
97
 
124
- # Build graphs in @id order
125
- debug("graphs") {graphs.to_json(JSON_STATE)}
126
- array = defaultGraph[:nodes].keys.sort.map do |subject|
127
- entry = defaultGraph[:nodes][subject]
128
- debug("=> default") {entry.to_json(JSON_STATE)}
129
-
130
- # If subject is a named graph, add serialized subject defintions
131
- if graphs.has_key?(subject) && !subject.empty?
132
- entry['@graph'] = graphs[subject][:nodes].keys.sort.map do |s|
133
- debug("=> #{s.inspect}")
134
- graphs[subject][:nodes][s]
98
+ result = []
99
+ debug("graph_map") {graph_map.to_json(JSON_STATE)}
100
+ default_graph.keys.sort.each do |subject|
101
+ node = default_graph[subject]
102
+ if graph_map.has_key?(subject)
103
+ node['@graph'] = []
104
+ graph_map[subject].keys.sort.each do |s|
105
+ n = graph_map[subject][s]
106
+ n.delete(:usages)
107
+ node['@graph'] << n
135
108
  end
136
109
  end
137
-
138
- debug("default graph") {entry.inspect}
139
- entry
110
+ node.delete(:usages)
111
+ result << node
140
112
  end
141
-
142
- # Return array as the graph representation.
143
- debug("fromRDF") {array.to_json(JSON_STATE)}
144
- array
113
+ debug("fromRDF") {result.to_json(JSON_STATE)}
114
+ result
145
115
  end
146
116
  end
147
117
  end