json-ld 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }))