json-ld 3.2.4 → 3.3.0

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