json-ld 3.2.3 → 3.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/json/ld/api.rb +807 -764
  4. data/lib/json/ld/compact.rb +304 -304
  5. data/lib/json/ld/conneg.rb +179 -161
  6. data/lib/json/ld/context.rb +2080 -1945
  7. data/lib/json/ld/expand.rb +745 -666
  8. data/lib/json/ld/extensions.rb +14 -13
  9. data/lib/json/ld/flatten.rb +257 -247
  10. data/lib/json/ld/format.rb +202 -194
  11. data/lib/json/ld/frame.rb +525 -502
  12. data/lib/json/ld/from_rdf.rb +224 -166
  13. data/lib/json/ld/html/nokogiri.rb +123 -121
  14. data/lib/json/ld/html/rexml.rb +151 -147
  15. data/lib/json/ld/reader.rb +107 -100
  16. data/lib/json/ld/resource.rb +224 -205
  17. data/lib/json/ld/streaming_reader.rb +574 -507
  18. data/lib/json/ld/streaming_writer.rb +93 -92
  19. data/lib/json/ld/to_rdf.rb +171 -167
  20. data/lib/json/ld/utils.rb +270 -264
  21. data/lib/json/ld/version.rb +24 -14
  22. data/lib/json/ld/writer.rb +334 -311
  23. data/lib/json/ld.rb +103 -96
  24. metadata +78 -209
  25. data/spec/api_spec.rb +0 -132
  26. data/spec/compact_spec.rb +0 -3482
  27. data/spec/conneg_spec.rb +0 -373
  28. data/spec/context_spec.rb +0 -2036
  29. data/spec/expand_spec.rb +0 -4496
  30. data/spec/flatten_spec.rb +0 -1203
  31. data/spec/format_spec.rb +0 -115
  32. data/spec/frame_spec.rb +0 -2498
  33. data/spec/from_rdf_spec.rb +0 -1005
  34. data/spec/matchers.rb +0 -20
  35. data/spec/rdfstar_spec.rb +0 -25
  36. data/spec/reader_spec.rb +0 -883
  37. data/spec/resource_spec.rb +0 -76
  38. data/spec/spec_helper.rb +0 -281
  39. data/spec/streaming_reader_spec.rb +0 -237
  40. data/spec/streaming_writer_spec.rb +0 -145
  41. data/spec/suite_compact_spec.rb +0 -22
  42. data/spec/suite_expand_spec.rb +0 -36
  43. data/spec/suite_flatten_spec.rb +0 -34
  44. data/spec/suite_frame_spec.rb +0 -29
  45. data/spec/suite_from_rdf_spec.rb +0 -22
  46. data/spec/suite_helper.rb +0 -411
  47. data/spec/suite_html_spec.rb +0 -22
  48. data/spec/suite_http_spec.rb +0 -35
  49. data/spec/suite_remote_doc_spec.rb +0 -22
  50. data/spec/suite_to_rdf_spec.rb +0 -30
  51. data/spec/support/extensions.rb +0 -44
  52. data/spec/test-files/test-1-compacted.jsonld +0 -10
  53. data/spec/test-files/test-1-context.jsonld +0 -7
  54. data/spec/test-files/test-1-expanded.jsonld +0 -5
  55. data/spec/test-files/test-1-input.jsonld +0 -10
  56. data/spec/test-files/test-1-rdf.ttl +0 -8
  57. data/spec/test-files/test-2-compacted.jsonld +0 -20
  58. data/spec/test-files/test-2-context.jsonld +0 -7
  59. data/spec/test-files/test-2-expanded.jsonld +0 -16
  60. data/spec/test-files/test-2-input.jsonld +0 -20
  61. data/spec/test-files/test-2-rdf.ttl +0 -14
  62. data/spec/test-files/test-3-compacted.jsonld +0 -11
  63. data/spec/test-files/test-3-context.jsonld +0 -8
  64. data/spec/test-files/test-3-expanded.jsonld +0 -10
  65. data/spec/test-files/test-3-input.jsonld +0 -11
  66. data/spec/test-files/test-3-rdf.ttl +0 -8
  67. data/spec/test-files/test-4-compacted.jsonld +0 -10
  68. data/spec/test-files/test-4-context.jsonld +0 -7
  69. data/spec/test-files/test-4-expanded.jsonld +0 -6
  70. data/spec/test-files/test-4-input.jsonld +0 -10
  71. data/spec/test-files/test-4-rdf.ttl +0 -5
  72. data/spec/test-files/test-5-compacted.jsonld +0 -13
  73. data/spec/test-files/test-5-context.jsonld +0 -7
  74. data/spec/test-files/test-5-expanded.jsonld +0 -9
  75. data/spec/test-files/test-5-input.jsonld +0 -13
  76. data/spec/test-files/test-5-rdf.ttl +0 -7
  77. data/spec/test-files/test-6-compacted.jsonld +0 -10
  78. data/spec/test-files/test-6-context.jsonld +0 -7
  79. data/spec/test-files/test-6-expanded.jsonld +0 -10
  80. data/spec/test-files/test-6-input.jsonld +0 -10
  81. data/spec/test-files/test-6-rdf.ttl +0 -6
  82. data/spec/test-files/test-7-compacted.jsonld +0 -23
  83. data/spec/test-files/test-7-context.jsonld +0 -4
  84. data/spec/test-files/test-7-expanded.jsonld +0 -20
  85. data/spec/test-files/test-7-input.jsonld +0 -23
  86. data/spec/test-files/test-7-rdf.ttl +0 -14
  87. data/spec/test-files/test-8-compacted.jsonld +0 -34
  88. data/spec/test-files/test-8-context.jsonld +0 -11
  89. data/spec/test-files/test-8-expanded.jsonld +0 -24
  90. data/spec/test-files/test-8-frame.jsonld +0 -18
  91. data/spec/test-files/test-8-framed.jsonld +0 -25
  92. data/spec/test-files/test-8-input.jsonld +0 -30
  93. data/spec/test-files/test-8-rdf.ttl +0 -15
  94. data/spec/test-files/test-9-compacted.jsonld +0 -20
  95. data/spec/test-files/test-9-context.jsonld +0 -13
  96. data/spec/test-files/test-9-expanded.jsonld +0 -14
  97. data/spec/test-files/test-9-input.jsonld +0 -12
  98. data/spec/to_rdf_spec.rb +0 -1551
  99. data/spec/writer_spec.rb +0 -427
@@ -1,195 +1,253 @@
1
- # -*- encoding: utf-8 -*-
2
1
  # frozen_string_literal: true
3
- require 'rdf/nquads'
4
-
5
- module JSON::LD
6
- module FromRDF
7
- include Utils
8
-
9
- ##
10
- # Generate a JSON-LD array representation from an array of `RDF::Statement`.
11
- # Representation is in expanded form
12
- #
13
- # @param [Array<RDF::Statement>, RDF::Enumerable] dataset
14
- # @param [Boolean] useRdfType (false)
15
- # If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
16
- # @param [Boolean] useNativeTypes (false) use native representations
17
- #
18
- # @return [Array<Hash>] the JSON-LD document in normalized form
19
- def from_statements(dataset, useRdfType: false, useNativeTypes: false)
20
- default_graph = {}
21
- graph_map = {'@default' => default_graph}
22
- referenced_once = {}
23
-
24
- value = nil
25
2
 
26
- # Create an entry for compound-literal node detection
27
- compound_literal_subjects = {}
28
-
29
- # Create a map for node to object representation
30
-
31
- # For each statement in dataset
32
- dataset.each do |statement|
33
- #log_debug("statement") { statement.to_nquads.chomp}
3
+ require 'rdf/nquads'
34
4
 
35
- name = statement.graph_name ? @context.expand_iri(statement.graph_name, base: @options[:base]).to_s : '@default'
5
+ module JSON
6
+ module LD
7
+ module FromRDF
8
+ include Utils
9
+
10
+ ##
11
+ # Generate a JSON-LD array representation from an array of `RDF::Statement`.
12
+ # Representation is in expanded form
13
+ #
14
+ # @param [Array<RDF::Statement>, RDF::Enumerable] dataset
15
+ # @param [Boolean] useRdfType (false)
16
+ # If set to `true`, the JSON-LD processor will treat `rdf:type` like a normal property instead of using `@type`.
17
+ # @param [Boolean] useNativeTypes (false) use native representations
18
+ # @param extendedRepresentation (false)
19
+ # Use the extended internal representation for native types.
20
+ #
21
+ # @return [Array<Hash>] the JSON-LD document in normalized form
22
+ def from_statements(dataset, useRdfType: false, useNativeTypes: false, extendedRepresentation: false)
23
+ default_graph = {}
24
+ graph_map = { '@default' => default_graph }
25
+ referenced_once = {}
26
+
27
+ value = nil
28
+
29
+ # Create an entry for compound-literal node detection
30
+ compound_literal_subjects = {}
31
+
32
+ # Create a map for node to object representation
33
+
34
+ # For each statement in dataset
35
+ dataset.each do |statement|
36
+ # log_debug("statement") { statement.to_nquads.chomp}
37
+
38
+ name = if statement.graph_name
39
+ @context.expand_iri(statement.graph_name,
40
+ base: @options[:base]).to_s
41
+ else
42
+ '@default'
43
+ end
36
44
 
37
- # Create a graph entry as needed
38
- node_map = graph_map[name] ||= {}
39
- compound_literal_subjects[name] ||= {}
45
+ # Create a graph entry as needed
46
+ node_map = graph_map[name] ||= {}
47
+ compound_literal_subjects[name] ||= {}
40
48
 
41
- default_graph[name] ||= {'@id' => name} unless name == '@default'
49
+ default_graph[name] ||= { '@id' => name } unless name == '@default'
42
50
 
43
- subject = statement.subject.statement? ?
44
- resource_representation(statement.subject, useNativeTypes)['@id'].to_json_c14n :
45
- statement.subject.to_s
46
- node = node_map[subject] ||= resource_representation(statement.subject, useNativeTypes)
51
+ subject = if statement.subject.statement?
52
+ resource_representation(statement.subject, useNativeTypes, extendedRepresentation)['@id'].to_json_c14n
53
+ else
54
+ statement.subject.to_s
55
+ end
56
+ node = node_map[subject] ||= resource_representation(statement.subject, useNativeTypes,
57
+ extendedRepresentation)
47
58
 
48
- # If predicate is rdf:datatype, note subject in compound literal subjects map
49
- if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF.to_uri + 'direction'
50
- compound_literal_subjects[name][subject] ||= true
51
- end
59
+ # If predicate is rdf:datatype, note subject in compound literal subjects map
60
+ if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF_DIRECTION
61
+ compound_literal_subjects[name][subject] ||= true
62
+ end
52
63
 
53
- # 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
- unless statement.object.literal?
55
- object = statement.object.statement? ?
56
- resource_representation(statement.object, useNativeTypes)['@id'].to_json_c14n :
57
- statement.object.to_s
58
- node_map[object] ||=
59
- resource_representation(statement.object, useNativeTypes)
60
- end
64
+ # 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.
65
+ unless statement.object.literal?
66
+ object = if statement.object.statement?
67
+ resource_representation(statement.object, useNativeTypes, extendedRepresentation)['@id'].to_json_c14n
68
+ else
69
+ statement.object.to_s
70
+ end
71
+ node_map[object] ||=
72
+ resource_representation(statement.object, useNativeTypes, extendedRepresentation)
73
+ end
61
74
 
62
- # 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.
63
- if statement.predicate == RDF.type && statement.object.resource? && !useRdfType
64
- merge_value(node, '@type', statement.object.to_s)
65
- next
66
- end
75
+ # 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.
76
+ if statement.predicate == RDF.type && statement.object.resource? && !useRdfType
77
+ merge_value(node, '@type', statement.object.to_s)
78
+ next
79
+ end
67
80
 
68
- # 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)
70
-
71
- merge_value(node, statement.predicate.to_s, value)
72
-
73
- # If object is a blank node identifier or rdf:nil, it might represent the a list node:
74
- if statement.object == RDF.nil
75
- # 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.
76
- object = node_map[statement.object.to_s]
77
- merge_value(object, :usages, {
78
- node: node,
79
- property: statement.predicate.to_s,
80
- value: value
81
- })
82
- elsif referenced_once.key?(statement.object.to_s)
83
- referenced_once[statement.object.to_s] = false
84
- elsif statement.object.node?
85
- referenced_once[statement.object.to_s] = {
86
- node: node,
87
- property: statement.predicate.to_s,
88
- value: value
89
- }
81
+ # Set value to the result of using the RDF to Object Conversion algorithm, passing object, rdfDirection, and use native types.
82
+ value = resource_representation(statement.object, useNativeTypes, extendedRepresentation)
83
+
84
+ merge_value(node, statement.predicate.to_s, value)
85
+
86
+ # If object is a blank node identifier or rdf:nil, it might represent the a list node:
87
+ if statement.object == RDF.nil
88
+ # 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.
89
+ object = node_map[statement.object.to_s]
90
+ merge_value(object, :usages, {
91
+ node: node,
92
+ property: statement.predicate.to_s,
93
+ value: value
94
+ })
95
+ elsif referenced_once.key?(statement.object.to_s)
96
+ referenced_once[statement.object.to_s] = false
97
+ elsif statement.object.node?
98
+ referenced_once[statement.object.to_s] = {
99
+ node: node,
100
+ property: statement.predicate.to_s,
101
+ value: value
102
+ }
103
+ end
90
104
  end
91
- end
92
105
 
93
- # For each name and graph object in graph map:
94
- graph_map.each do |name, graph_object|
95
-
96
- # If rdfDirection is compound-literal, check referenced_once for entries from compound_literal_subjects
97
- compound_literal_subjects.fetch(name, {}).keys.each do |cl|
98
- node = referenced_once[cl][:node]
99
- next unless node.is_a?(Hash)
100
- property = referenced_once[cl][:property]
101
- value = referenced_once[cl][:value]
102
- cl_node = graph_map[name].delete(cl)
103
- next unless cl_node.is_a?(Hash)
104
- node[property].select do |v|
105
- next unless v['@id'] == cl
106
- v.delete('@id')
107
- v['@value'] = cl_node[RDF.value.to_s].first['@value']
108
- if cl_node[RDF.to_uri.to_s + 'language']
109
- lang = cl_node[RDF.to_uri.to_s + 'language'].first['@value']
110
- if lang !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/
111
- warn "i18n datatype language must be valid BCP47: #{lang.inspect}"
106
+ # For each name and graph object in graph map:
107
+ graph_map.each do |name, graph_object|
108
+ # If rdfDirection is compound-literal, check referenced_once for entries from compound_literal_subjects
109
+ compound_literal_subjects.fetch(name, {}).each_key do |cl|
110
+ node = referenced_once[cl][:node]
111
+ next unless node.is_a?(Hash)
112
+
113
+ property = referenced_once[cl][:property]
114
+ value = referenced_once[cl][:value]
115
+ cl_node = graph_map[name].delete(cl)
116
+ next unless cl_node.is_a?(Hash)
117
+
118
+ node[property].select do |v|
119
+ next unless v['@id'] == cl
120
+
121
+ v.delete('@id')
122
+ v['@value'] = cl_node[RDF.value.to_s].first['@value']
123
+ if (langs = cl_node[RDF_LANGUAGE.to_s])
124
+ lang = langs.first['@value']
125
+ unless /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/.match?(lang)
126
+ warn "i18n datatype language must be valid BCP47: #{lang.inspect}"
127
+ end
128
+ v['@language'] = lang
112
129
  end
113
- v['@language'] = lang
130
+ v['@direction'] = cl_node[RDF_DIRECTION.to_s].first['@value']
114
131
  end
115
- v['@direction'] = cl_node[RDF.to_uri.to_s + 'direction'].first['@value']
116
132
  end
117
- end
118
133
 
119
- nil_var = graph_object.fetch(RDF.nil.to_s, {})
120
-
121
- # For each item usage in the usages member of nil, perform the following steps:
122
- nil_var.fetch(:usages, []).each do |usage|
123
- node, property, head = usage[:node], usage[:property], usage[:value]
124
- list, list_nodes = [], []
125
-
126
- # 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'}
128
- while property == RDF.rest.to_s &&
129
- blank_node?(node) &&
130
- referenced_once[node['@id']] &&
131
- node.keys.none? {|k| !["@id", '@type', :usages, RDF.first.to_s, RDF.rest.to_s].include?(k)} &&
132
- (f = node[RDF.first.to_s]).is_a?(Array) && f.length == 1 &&
133
- (r = node[RDF.rest.to_s]).is_a?(Array) && r.length == 1 &&
134
- ((t = node['@type']).nil? || t == [RDF.List.to_s])
135
- list << Array(node[RDF.first.to_s]).first
136
- list_nodes << node['@id']
137
-
138
- # get next node, moving backwards through list
139
- node_usage = referenced_once[node['@id']]
140
- node, property, head = node_usage[:node], node_usage[:property], node_usage[:value]
134
+ nil_var = graph_object.fetch(RDF.nil.to_s, {})
135
+
136
+ # For each item usage in the usages member of nil, perform the following steps:
137
+ nil_var.fetch(:usages, []).each do |usage|
138
+ node = usage[:node]
139
+ property = usage[:property]
140
+ head = usage[:value]
141
+ list = []
142
+ list_nodes = []
143
+
144
+ # 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:
145
+ # log_debug("list element?") {node.to_json(JSON_STATE) rescue 'malformed json'}
146
+ while property == RDF.rest.to_s &&
147
+ blank_node?(node) &&
148
+ referenced_once[node['@id']] &&
149
+ node.keys.none? { |k| !["@id", '@type', :usages, RDF.first.to_s, RDF.rest.to_s].include?(k) } &&
150
+ (f = node[RDF.first.to_s]).is_a?(Array) && f.length == 1 &&
151
+ (r = node[RDF.rest.to_s]).is_a?(Array) && r.length == 1 &&
152
+ ((t = node['@type']).nil? || t == [RDF.List.to_s])
153
+ list << Array(node[RDF.first.to_s]).first
154
+ list_nodes << node['@id']
155
+
156
+ # get next node, moving backwards through list
157
+ node_usage = referenced_once[node['@id']]
158
+ node = node_usage[:node]
159
+ property = node_usage[:property]
160
+ head = node_usage[:value]
161
+ end
162
+
163
+ head.delete('@id')
164
+ head['@list'] = list.reverse
165
+ list_nodes.each { |node_id| graph_object.delete(node_id) }
141
166
  end
142
167
 
143
- head.delete('@id')
144
- head['@list'] = list.reverse
145
- list_nodes.each {|node_id| graph_object.delete(node_id)}
168
+ # Create annotations on graph object
169
+ create_annotations(graph_object)
146
170
  end
147
171
 
148
- # Create annotations on graph object
149
- create_annotations(graph_object)
150
- end
151
-
152
- result = []
153
- default_graph.keys.opt_sort(ordered: @options[:ordered]).each do |subject|
154
- node = default_graph[subject]
155
- if graph_map.key?(subject)
156
- node['@graph'] = []
157
- graph_map[subject].keys.opt_sort(ordered: @options[:ordered]).each do |s|
158
- n = graph_map[subject][s]
159
- n.delete(:usages)
160
- node['@graph'] << n unless node_reference?(n)
172
+ result = []
173
+ default_graph.keys.opt_sort(ordered: @options[:ordered]).each do |subject|
174
+ node = default_graph[subject]
175
+ if graph_map.key?(subject)
176
+ node['@graph'] = []
177
+ graph_map[subject].keys.opt_sort(ordered: @options[:ordered]).each do |s|
178
+ n = graph_map[subject][s]
179
+ n.delete(:usages)
180
+ node['@graph'] << n unless node_reference?(n)
181
+ end
161
182
  end
183
+ node.delete(:usages)
184
+ result << node unless node_reference?(node)
162
185
  end
163
- node.delete(:usages)
164
- result << node unless node_reference?(node)
186
+ # log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
187
+ result
165
188
  end
166
- #log_debug("fromRdf") {result.to_json(JSON_STATE) rescue 'malformed json'}
167
- result
168
- end
169
189
 
170
- private
171
- def resource_representation(resource, useNativeTypes)
172
- case resource
173
- when RDF::Statement
174
- # Note, if either subject or object are a BNode which is used elsewhere,
175
- # this might not work will with the BNode accounting from above.
176
- rep = {'@id' => resource_representation(resource.subject, false)}
177
- if resource.predicate == RDF.type
178
- rep['@id'].merge!('@type' => resource.object.to_s)
190
+ private
191
+
192
+ RDF_LITERAL_NATIVE_TYPES = Set.new([RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double]).freeze
193
+
194
+ def resource_representation(resource, useNativeTypes, extendedRepresentation)
195
+ case resource
196
+ when RDF::Statement
197
+ # Note, if either subject or object are a BNode which is used elsewhere,
198
+ # this might not work will with the BNode accounting from above.
199
+ rep = { '@id' => resource_representation(resource.subject, false, extendedRepresentation) }
200
+ if resource.predicate == RDF.type
201
+ rep['@id']['@type'] = resource.object.to_s
202
+ else
203
+ rep['@id'][resource.predicate.to_s] =
204
+ as_array(resource_representation(resource.object, useNativeTypes, extendedRepresentation))
205
+ end
206
+ rep
207
+ when RDF::Literal
208
+ base = @options[:base]
209
+ rdfDirection = @options[:rdfDirection]
210
+ res = {}
211
+
212
+ if resource.datatype == RDF_JSON && @context.processingMode('json-ld-1.1')
213
+ res['@type'] = '@json'
214
+ res['@value'] = begin
215
+ ::JSON.parse(resource.object)
216
+ rescue ::JSON::ParserError => e
217
+ raise JSON::LD::JsonLdError::InvalidJsonLiteral, e.message
218
+ end
219
+ elsif useNativeTypes && extendedRepresentation
220
+ res['@value'] = resource # Raw literal
221
+ elsif resource.datatype.start_with?("https://www.w3.org/ns/i18n#") && rdfDirection == 'i18n-datatype' && @context.processingMode('json-ld-1.1')
222
+ lang, dir = resource.datatype.fragment.split('_')
223
+ res['@value'] = resource.to_s
224
+ unless lang.empty?
225
+ unless /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/.match?(lang)
226
+ if options[:validate]
227
+ raise JsonLdError::InvalidLanguageMapping, "rdf:language must be valid BCP47: #{lang.inspect}"
228
+ end
229
+
230
+ warn "rdf:language must be valid BCP47: #{lang.inspect}"
231
+
232
+ end
233
+ res['@language'] = lang
234
+ end
235
+ res['@direction'] = dir
236
+ elsif useNativeTypes && RDF_LITERAL_NATIVE_TYPES.include?(resource.datatype) && resource.valid?
237
+ res['@value'] = resource.object
238
+ else
239
+ resource.canonicalize! if resource.valid? && resource.datatype == RDF::XSD.double
240
+ if resource.datatype?
241
+ res['@type'] = resource.datatype.to_s
242
+ elsif resource.language?
243
+ res['@language'] = resource.language.to_s
244
+ end
245
+ res['@value'] = resource.to_s
246
+ end
247
+ res
179
248
  else
180
- rep['@id'].merge!(
181
- resource.predicate.to_s =>
182
- as_array(resource_representation(resource.object, useNativeTypes)))
249
+ { '@id' => resource.to_s }
183
250
  end
184
- rep
185
- when RDF::Literal
186
- @context.expand_value(nil,
187
- resource,
188
- rdfDirection: @options[:rdfDirection],
189
- useNativeTypes: useNativeTypes,
190
- base: @options[:base])
191
- else
192
- {'@id' => resource.to_s}
193
251
  end
194
252
  end
195
253
  end