json-ld 3.0.2 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -1
  3. data/README.md +90 -53
  4. data/UNLICENSE +1 -1
  5. data/VERSION +1 -1
  6. data/bin/jsonld +4 -4
  7. data/lib/json/ld.rb +27 -10
  8. data/lib/json/ld/api.rb +325 -96
  9. data/lib/json/ld/compact.rb +75 -27
  10. data/lib/json/ld/conneg.rb +188 -0
  11. data/lib/json/ld/context.rb +677 -292
  12. data/lib/json/ld/expand.rb +240 -75
  13. data/lib/json/ld/flatten.rb +5 -3
  14. data/lib/json/ld/format.rb +19 -19
  15. data/lib/json/ld/frame.rb +135 -85
  16. data/lib/json/ld/from_rdf.rb +44 -17
  17. data/lib/json/ld/html/nokogiri.rb +151 -0
  18. data/lib/json/ld/html/rexml.rb +186 -0
  19. data/lib/json/ld/reader.rb +25 -5
  20. data/lib/json/ld/resource.rb +2 -2
  21. data/lib/json/ld/streaming_writer.rb +3 -1
  22. data/lib/json/ld/to_rdf.rb +47 -17
  23. data/lib/json/ld/utils.rb +4 -2
  24. data/lib/json/ld/writer.rb +75 -14
  25. data/spec/api_spec.rb +13 -34
  26. data/spec/compact_spec.rb +968 -9
  27. data/spec/conneg_spec.rb +373 -0
  28. data/spec/context_spec.rb +447 -53
  29. data/spec/expand_spec.rb +1872 -416
  30. data/spec/flatten_spec.rb +434 -47
  31. data/spec/frame_spec.rb +979 -344
  32. data/spec/from_rdf_spec.rb +305 -5
  33. data/spec/spec_helper.rb +177 -0
  34. data/spec/streaming_writer_spec.rb +4 -4
  35. data/spec/suite_compact_spec.rb +2 -2
  36. data/spec/suite_expand_spec.rb +14 -2
  37. data/spec/suite_flatten_spec.rb +10 -2
  38. data/spec/suite_frame_spec.rb +3 -2
  39. data/spec/suite_from_rdf_spec.rb +2 -2
  40. data/spec/suite_helper.rb +55 -20
  41. data/spec/suite_html_spec.rb +22 -0
  42. data/spec/suite_http_spec.rb +35 -0
  43. data/spec/suite_remote_doc_spec.rb +2 -2
  44. data/spec/suite_to_rdf_spec.rb +14 -3
  45. data/spec/support/extensions.rb +5 -1
  46. data/spec/test-files/test-4-input.json +3 -3
  47. data/spec/test-files/test-5-input.json +2 -2
  48. data/spec/test-files/test-8-framed.json +14 -18
  49. data/spec/to_rdf_spec.rb +606 -16
  50. data/spec/writer_spec.rb +5 -5
  51. metadata +144 -88
@@ -155,6 +155,119 @@ describe JSON::LD::API do
155
155
  "http://example.com/b" => [{"@value" => "foo", "@language" => "en-us"}]
156
156
  }], logger)
157
157
  end
158
+
159
+ context "with @type: @json" do
160
+ {
161
+ "true": {
162
+ output: %([{
163
+ "@id": "http://example.org/vocab#id",
164
+ "http://example.org/vocab#bool": [{"@value": true, "@type": "@json"}]
165
+ }]),
166
+ input:%(
167
+ @prefix ex: <http://example.org/vocab#> .
168
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
169
+ ex:id ex:bool "true"^^rdf:JSON .
170
+ )
171
+ },
172
+ "false": {
173
+ output: %([{
174
+ "@id": "http://example.org/vocab#id",
175
+ "http://example.org/vocab#bool": [{"@value": false, "@type": "@json"}]
176
+ }]),
177
+ input: %(
178
+ @prefix ex: <http://example.org/vocab#> .
179
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
180
+ ex:id ex:bool "false"^^rdf:JSON .
181
+ )
182
+ },
183
+ "double": {
184
+ output: %([{
185
+ "@id": "http://example.org/vocab#id",
186
+ "http://example.org/vocab#double": [{"@value": 1.23E0, "@type": "@json"}]
187
+ }]),
188
+ input: %(
189
+ @prefix ex: <http://example.org/vocab#> .
190
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
191
+ ex:id ex:double "1.23E0"^^rdf:JSON .
192
+ )
193
+ },
194
+ "double-zero": {
195
+ output: %([{
196
+ "@id": "http://example.org/vocab#id",
197
+ "http://example.org/vocab#double": [{"@value": 0, "@type": "@json"}]
198
+ }]),
199
+ input: %(
200
+ @prefix ex: <http://example.org/vocab#> .
201
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
202
+ ex:id ex:double "0.0E0"^^rdf:JSON .
203
+ )
204
+ },
205
+ "integer": {
206
+ output: %([{
207
+ "@id": "http://example.org/vocab#id",
208
+ "http://example.org/vocab#integer": [{"@value": 123, "@type": "@json"}]
209
+ }]),
210
+ input: %(
211
+ @prefix ex: <http://example.org/vocab#> .
212
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
213
+ ex:id ex:integer "123"^^rdf:JSON .
214
+ )
215
+ },
216
+ "string": {
217
+ output: %([{
218
+ "@id": "http://example.org/vocab#id",
219
+ "http://example.org/vocab#string": [{
220
+ "@value": "string",
221
+ "@type": "@json"
222
+ }]
223
+ }]),
224
+ input: %(
225
+ @prefix ex: <http://example.org/vocab#> .
226
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
227
+ ex:id ex:string "\\"string\\""^^rdf:JSON .
228
+ )
229
+ },
230
+ "null": {
231
+ output: %([{
232
+ "@id": "http://example.org/vocab#id",
233
+ "http://example.org/vocab#null": [{
234
+ "@value": null,
235
+ "@type": "@json"
236
+ }]
237
+ }]),
238
+ input: %(
239
+ @prefix ex: <http://example.org/vocab#> .
240
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
241
+ ex:id ex:null "null"^^rdf:JSON .
242
+ )
243
+ },
244
+ "object": {
245
+ output: %([{
246
+ "@id": "http://example.org/vocab#id",
247
+ "http://example.org/vocab#object": [{"@value": {"foo": "bar"}, "@type": "@json"}]
248
+ }]),
249
+ input: %(
250
+ @prefix ex: <http://example.org/vocab#> .
251
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
252
+ ex:id ex:object """{"foo":"bar"}"""^^rdf:JSON .
253
+ )
254
+ },
255
+ "array": {
256
+ output: %([{
257
+ "@id": "http://example.org/vocab#id",
258
+ "http://example.org/vocab#array": [{"@value": [{"foo": "bar"}], "@type": "@json"}]
259
+ }]),
260
+ input: %(
261
+ @prefix ex: <http://example.org/vocab#> .
262
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
263
+ ex:id ex:array """[{"foo":"bar"}]"""^^rdf:JSON .
264
+ )
265
+ },
266
+ }.each do |title, params|
267
+ params[:input] = RDF::Graph.new << RDF::Turtle::Reader.new(params[:input])
268
+ it(title) {do_fromRdf(processingMode: "json-ld-1.1", **params)}
269
+ end
270
+ end
158
271
  end
159
272
 
160
273
  context "anons" do
@@ -470,7 +583,189 @@ describe JSON::LD::API do
470
583
  end
471
584
  end
472
585
  end
473
-
586
+
587
+ context "@direction" do
588
+ context "rdfDirection: null" do
589
+ {
590
+ "no language rtl datatype": {
591
+ input: %q(
592
+ <http://example.com/a> <http://example.org/label> "no language"^^<https://www.w3.org/ns/i18n#_rtl> .
593
+ ),
594
+ output: %q([{
595
+ "@id": "http://example.com/a",
596
+ "http://example.org/label": [{"@value": "no language", "@type": "https://www.w3.org/ns/i18n#_rtl"}]
597
+ }]),
598
+ },
599
+ "no language rtl compound-literal": {
600
+ input: %q(
601
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
602
+ <http://example.com/a> <http://example.org/label> _:cl1 .
603
+
604
+ _:cl1 rdf:value "no language";
605
+ rdf:direction "rtl" .
606
+ ),
607
+ output: %q([{
608
+ "@id": "http://example.com/a",
609
+ "http://example.org/label": [{"@id": "_:cl1"}]
610
+ }, {
611
+ "@id": "_:cl1",
612
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#value": [{"@value": "no language"}],
613
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#direction": [{"@value": "rtl"}]
614
+ }]),
615
+ },
616
+ "en-US rtl datatype": {
617
+ input: %q(
618
+ <http://example.com/a> <http://example.org/label> "en-US"^^<https://www.w3.org/ns/i18n#en-us_rtl> .
619
+ ),
620
+ output: %q([{
621
+ "@id": "http://example.com/a",
622
+ "http://example.org/label": [{"@value": "en-US", "@type": "https://www.w3.org/ns/i18n#en-us_rtl"}]
623
+ }]),
624
+ },
625
+ "en-US rtl compound-literal": {
626
+ input: %q(
627
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
628
+ <http://example.com/a> <http://example.org/label> _:cl1 .
629
+
630
+ _:cl1 rdf:value "en-US";
631
+ rdf:language "en-us";
632
+ rdf:direction "rtl" .
633
+ ),
634
+ output: %q([{
635
+ "@id": "http://example.com/a",
636
+ "http://example.org/label": [{"@id": "_:cl1"}]
637
+ }, {
638
+ "@id": "_:cl1",
639
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#value": [{"@value": "en-US"}],
640
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#language": [{"@value": "en-us"}],
641
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#direction": [{"@value": "rtl"}]
642
+ }]),
643
+ }
644
+ }.each_pair do |name, params|
645
+ it name do
646
+ do_fromRdf(params.merge(reader: RDF::Turtle::Reader, rdfDirection: nil))
647
+ end
648
+ end
649
+ end
650
+
651
+ context "rdfDirection: i18n-datatype" do
652
+ {
653
+ "no language rtl datatype": {
654
+ input: %q(
655
+ <http://example.com/a> <http://example.org/label> "no language"^^<https://www.w3.org/ns/i18n#_rtl> .
656
+ ),
657
+ output: %q([{
658
+ "@id": "http://example.com/a",
659
+ "http://example.org/label": [{"@value": "no language", "@direction": "rtl"}]
660
+ }]),
661
+ },
662
+ "no language rtl compound-literal": {
663
+ input: %q(
664
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
665
+ <http://example.com/a> <http://example.org/label> _:cl1 .
666
+
667
+ _:cl1 rdf:value "no language";
668
+ rdf:direction "rtl" .
669
+ ),
670
+ output: %q([{
671
+ "@id": "http://example.com/a",
672
+ "http://example.org/label": [{"@id": "_:cl1"}]
673
+ }, {
674
+ "@id": "_:cl1",
675
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#value": [{"@value": "no language"}],
676
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#direction": [{"@value": "rtl"}]
677
+ }]),
678
+ },
679
+ "en-US rtl datatype": {
680
+ input: %q(
681
+ <http://example.com/a> <http://example.org/label> "en-US"^^<https://www.w3.org/ns/i18n#en-US_rtl> .
682
+ ),
683
+ output: %q([{
684
+ "@id": "http://example.com/a",
685
+ "http://example.org/label": [{"@value": "en-US", "@language": "en-US", "@direction": "rtl"}]
686
+ }]),
687
+ },
688
+ "en-US rtl compound-literal": {
689
+ input: %q(
690
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
691
+ <http://example.com/a> <http://example.org/label> _:cl1 .
692
+
693
+ _:cl1 rdf:value "en-US";
694
+ rdf:language "en-US";
695
+ rdf:direction "rtl" .
696
+ ),
697
+ output: %q([{
698
+ "@id": "http://example.com/a",
699
+ "http://example.org/label": [{"@id": "_:cl1"}]
700
+ }, {
701
+ "@id": "_:cl1",
702
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#value": [{"@value": "en-US"}],
703
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#language": [{"@value": "en-US"}],
704
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#direction": [{"@value": "rtl"}]
705
+ }]),
706
+ }
707
+ }.each_pair do |name, params|
708
+ it name do
709
+ do_fromRdf(params.merge(reader: RDF::Turtle::Reader, rdfDirection: 'i18n-datatype', processingMode: 'json-ld-1.1'))
710
+ end
711
+ end
712
+ end
713
+
714
+ context "rdfDirection: compound-literal" do
715
+ {
716
+ "no language rtl datatype": {
717
+ input: %q(
718
+ <http://example.com/a> <http://example.org/label> "no language"^^<https://www.w3.org/ns/i18n#_rtl> .
719
+ ),
720
+ output: %q([{
721
+ "@id": "http://example.com/a",
722
+ "http://example.org/label": [{"@value": "no language", "@type": "https://www.w3.org/ns/i18n#_rtl"}]
723
+ }]),
724
+ },
725
+ "no language rtl compound-literal": {
726
+ input: %q(
727
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
728
+ <http://example.com/a> <http://example.org/label> _:cl1 .
729
+
730
+ _:cl1 rdf:value "no language";
731
+ rdf:direction "rtl" .
732
+ ),
733
+ output: %q([{
734
+ "@id": "http://example.com/a",
735
+ "http://example.org/label": [{"@value": "no language", "@direction": "rtl"}]
736
+ }]),
737
+ },
738
+ "en-US rtl datatype": {
739
+ input: %q(
740
+ <http://example.com/a> <http://example.org/label> "en-US"^^<https://www.w3.org/ns/i18n#en-us_rtl> .
741
+ ),
742
+ output: %q([{
743
+ "@id": "http://example.com/a",
744
+ "http://example.org/label": [{"@value": "en-US", "@type": "https://www.w3.org/ns/i18n#en-us_rtl"}]
745
+ }]),
746
+ },
747
+ "en-US rtl compound-literal": {
748
+ input: %q(
749
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
750
+ <http://example.com/a> <http://example.org/label> _:cl1 .
751
+
752
+ _:cl1 rdf:value "en-US";
753
+ rdf:language "en-us";
754
+ rdf:direction "rtl" .
755
+ ),
756
+ output: %q([{
757
+ "@id": "http://example.com/a",
758
+ "http://example.org/label": [{"@value": "en-US", "@language": "en-us", "@direction": "rtl"}]
759
+ }]),
760
+ }
761
+ }.each_pair do |name, params|
762
+ it name do
763
+ do_fromRdf(params.merge(reader: RDF::Turtle::Reader, rdfDirection: 'compound-literal', processingMode: 'json-ld-1.1'))
764
+ end
765
+ end
766
+ end
767
+ end
768
+
474
769
  context "problems" do
475
770
  {
476
771
  "xsd:boolean as value" => {
@@ -497,13 +792,13 @@ describe JSON::LD::API do
497
792
 
498
793
  def parse(input, **options)
499
794
  reader = options[:reader] || RDF::TriG::Reader
500
- reader.new(input, options, &:each_statement).to_a.extend(RDF::Enumerable)
795
+ reader.new(input, **options, &:each_statement).to_a.extend(RDF::Enumerable)
501
796
  end
502
797
 
503
798
  # Serialize ntstr to a string and compare against regexps
504
799
  def serialize(ntstr, **options)
505
800
  logger.info ntstr if ntstr.is_a?(String)
506
- g = ntstr.is_a?(String) ? parse(ntstr, options) : ntstr
801
+ g = ntstr.is_a?(String) ? parse(ntstr, **options) : ntstr
507
802
  logger.info g.dump(:trig)
508
803
  statements = g.each_statement.to_a
509
804
  JSON::LD::API.fromRdf(statements, logger: logger, **options)
@@ -511,9 +806,14 @@ describe JSON::LD::API do
511
806
 
512
807
  def do_fromRdf(params)
513
808
  begin
514
- input, output, processingMode = params[:input], params[:output], params.fetch(:processingMode, 'json-ld-1.0')
809
+ input, output = params[:input], params[:output]
515
810
  output = ::JSON.parse(output) if output.is_a?(String)
516
- jld = serialize(input, **params)
811
+ jld = nil
812
+ if params[:write]
813
+ expect{jld = serialize(input, **params)}.to write(params[:write]).to(:error)
814
+ else
815
+ expect{jld = serialize(input, **params)}.not_to write.to(:error)
816
+ end
517
817
  expect(jld).to produce_jsonld(output, logger)
518
818
  rescue JSON::LD::JsonLdError => e
519
819
  fail("#{e.class}: #{e.message}\n" +
@@ -36,6 +36,9 @@ JSON_STATE = JSON::State.new(
36
36
  array_nl: "\n"
37
37
  )
38
38
 
39
+ require 'webmock'
40
+ WebMock.disable_net_connect!
41
+
39
42
  # Create and maintain a cache of downloaded URIs
40
43
  URI_CACHE = File.expand_path(File.join(File.dirname(__FILE__), "uri-cache"))
41
44
  Dir.mkdir(URI_CACHE) unless File.directory?(URI_CACHE)
@@ -64,3 +67,177 @@ def detect_format(stream)
64
67
  end
65
68
  end
66
69
 
70
+ LIBRARY_INPUT = JSON.parse(%([
71
+ {
72
+ "@id": "http://example.org/library",
73
+ "@type": "http://example.org/vocab#Library",
74
+ "http://example.org/vocab#contains": {"@id": "http://example.org/library/the-republic"}
75
+ }, {
76
+ "@id": "http://example.org/library/the-republic",
77
+ "@type": "http://example.org/vocab#Book",
78
+ "http://purl.org/dc/elements/1.1/creator": "Plato",
79
+ "http://purl.org/dc/elements/1.1/title": "The Republic",
80
+ "http://example.org/vocab#contains": {
81
+ "@id": "http://example.org/library/the-republic#introduction",
82
+ "@type": "http://example.org/vocab#Chapter",
83
+ "http://purl.org/dc/elements/1.1/description": "An introductory chapter on The Republic.",
84
+ "http://purl.org/dc/elements/1.1/title": "The Introduction"
85
+ }
86
+ }
87
+ ]))
88
+
89
+ LIBRARY_EXPANDED = JSON.parse(%([
90
+ {
91
+ "@id": "http://example.org/library",
92
+ "@type": ["http://example.org/vocab#Library"],
93
+ "http://example.org/vocab#contains": [{"@id": "http://example.org/library/the-republic"}]
94
+ }, {
95
+ "@id": "http://example.org/library/the-republic",
96
+ "@type": ["http://example.org/vocab#Book"],
97
+ "http://purl.org/dc/elements/1.1/creator": [{"@value": "Plato"}],
98
+ "http://purl.org/dc/elements/1.1/title": [{"@value": "The Republic"}],
99
+ "http://example.org/vocab#contains": [{
100
+ "@id": "http://example.org/library/the-republic#introduction",
101
+ "@type": ["http://example.org/vocab#Chapter"],
102
+ "http://purl.org/dc/elements/1.1/description": [{"@value": "An introductory chapter on The Republic."}],
103
+ "http://purl.org/dc/elements/1.1/title": [{"@value": "The Introduction"}]
104
+ }]
105
+ }
106
+ ]))
107
+
108
+ LIBRARY_COMPACTED_DEFAULT = JSON.parse(%({
109
+ "@context": "http://schema.org",
110
+ "@graph": [
111
+ {
112
+ "id": "http://example.org/library",
113
+ "type": "http://example.org/vocab#Library",
114
+ "http://example.org/vocab#contains": {"id": "http://example.org/library/the-republic"}
115
+ }, {
116
+ "id": "http://example.org/library/the-republic",
117
+ "type": "http://example.org/vocab#Book",
118
+ "http://purl.org/dc/elements/1.1/creator": "Plato",
119
+ "http://purl.org/dc/elements/1.1/title": "The Republic",
120
+ "http://example.org/vocab#contains": {
121
+ "id": "http://example.org/library/the-republic#introduction",
122
+ "type": "http://example.org/vocab#Chapter",
123
+ "http://purl.org/dc/elements/1.1/description": "An introductory chapter on The Republic.",
124
+ "http://purl.org/dc/elements/1.1/title": "The Introduction"
125
+ }
126
+ }
127
+ ]
128
+ }))
129
+
130
+ LIBRARY_COMPACTED = JSON.parse(%({
131
+ "@context": "http://conneg.example.com/context",
132
+ "@graph": [
133
+ {
134
+ "@id": "http://example.org/library",
135
+ "@type": "ex:Library",
136
+ "ex:contains": {
137
+ "@id": "http://example.org/library/the-republic"
138
+ }
139
+ },
140
+ {
141
+ "@id": "http://example.org/library/the-republic",
142
+ "@type": "ex:Book",
143
+ "dc:creator": "Plato",
144
+ "dc:title": "The Republic",
145
+ "ex:contains": {
146
+ "@id": "http://example.org/library/the-republic#introduction",
147
+ "@type": "ex:Chapter",
148
+ "dc:description": "An introductory chapter on The Republic.",
149
+ "dc:title": "The Introduction"
150
+ }
151
+ }
152
+ ]
153
+ }))
154
+
155
+ LIBRARY_FLATTENED_EXPANDED = JSON.parse(%([
156
+ {
157
+ "@id": "http://example.org/library",
158
+ "@type": ["http://example.org/vocab#Library"],
159
+ "http://example.org/vocab#contains": [{"@id": "http://example.org/library/the-republic"}]
160
+ },
161
+ {
162
+ "@id": "http://example.org/library/the-republic",
163
+ "@type": ["http://example.org/vocab#Book"],
164
+ "http://purl.org/dc/elements/1.1/creator": [{"@value": "Plato"}],
165
+ "http://purl.org/dc/elements/1.1/title": [{"@value": "The Republic"}],
166
+ "http://example.org/vocab#contains": [{"@id": "http://example.org/library/the-republic#introduction"}]
167
+ },
168
+ {
169
+ "@id": "http://example.org/library/the-republic#introduction",
170
+ "@type": ["http://example.org/vocab#Chapter"],
171
+ "http://purl.org/dc/elements/1.1/description": [{"@value": "An introductory chapter on The Republic."}],
172
+ "http://purl.org/dc/elements/1.1/title": [{"@value": "The Introduction"}]
173
+ }
174
+ ]))
175
+
176
+ LIBRARY_FLATTENED_COMPACTED_DEFAULT = JSON.parse(%({
177
+ "@context": "http://schema.org",
178
+ "@graph": [
179
+ {
180
+ "id": "http://example.org/library",
181
+ "type": "http://example.org/vocab#Library",
182
+ "http://example.org/vocab#contains": {"id": "http://example.org/library/the-republic"}
183
+ },
184
+ {
185
+ "id": "http://example.org/library/the-republic",
186
+ "type": "http://example.org/vocab#Book",
187
+ "http://purl.org/dc/elements/1.1/creator": "Plato",
188
+ "http://purl.org/dc/elements/1.1/title": "The Republic",
189
+ "http://example.org/vocab#contains": {"id": "http://example.org/library/the-republic#introduction"}
190
+ },
191
+ {
192
+ "id": "http://example.org/library/the-republic#introduction",
193
+ "type": "http://example.org/vocab#Chapter",
194
+ "http://purl.org/dc/elements/1.1/description": "An introductory chapter on The Republic.",
195
+ "http://purl.org/dc/elements/1.1/title": "The Introduction"
196
+ }
197
+ ]
198
+ }))
199
+
200
+ LIBRARY_FLATTENED_COMPACTED = JSON.parse(%({
201
+ "@context": "http://conneg.example.com/context",
202
+ "@graph": [
203
+ {
204
+ "@id": "http://example.org/library",
205
+ "@type": "ex:Library",
206
+ "ex:contains": {"@id": "http://example.org/library/the-republic"}
207
+ },
208
+ {
209
+ "@id": "http://example.org/library/the-republic",
210
+ "@type": "ex:Book",
211
+ "dc:creator": "Plato",
212
+ "dc:title": "The Republic",
213
+ "ex:contains": {"@id": "http://example.org/library/the-republic#introduction"}
214
+ },
215
+ {
216
+ "@id": "http://example.org/library/the-republic#introduction",
217
+ "@type": "ex:Chapter",
218
+ "dc:description": "An introductory chapter on The Republic.",
219
+ "dc:title": "The Introduction"
220
+ }
221
+ ]
222
+ }))
223
+
224
+ LIBRARY_FRAMED = JSON.parse(%({
225
+ "@context": {
226
+ "dc": "http://purl.org/dc/elements/1.1/",
227
+ "ex": "http://example.org/vocab#"
228
+ },
229
+ "@id": "http://example.org/library",
230
+ "@type": "ex:Library",
231
+ "ex:contains": {
232
+ "@id": "http://example.org/library/the-republic",
233
+ "@type": "ex:Book",
234
+ "dc:creator": "Plato",
235
+ "dc:title": "The Republic",
236
+ "ex:contains": {
237
+ "@id": "http://example.org/library/the-republic#introduction",
238
+ "@type": "ex:Chapter",
239
+ "dc:description": "An introductory chapter on The Republic.",
240
+ "dc:title": "The Introduction"
241
+ }
242
+ }
243
+ }))