rdf_context 0.5.0 → 0.5.1
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.
- data/History.txt +15 -0
- data/README.rdoc +84 -8
- data/VERSION +1 -1
- data/bin/rdf_context +2 -6
- data/lib/rdf_context.rb +12 -2
- data/lib/rdf_context/bnode.rb +5 -1
- data/lib/rdf_context/graph.rb +97 -70
- data/lib/rdf_context/literal.rb +8 -3
- data/lib/rdf_context/parser.rb +4 -4
- data/lib/rdf_context/serializer/abstract_serializer.rb +26 -0
- data/lib/rdf_context/serializer/nt_serializer.rb +12 -0
- data/lib/rdf_context/serializer/recursive_serializer.rb +140 -0
- data/lib/rdf_context/serializer/turtle_serializer.rb +219 -0
- data/lib/rdf_context/serializer/xml_serializer.rb +236 -0
- data/lib/rdf_context/store/abstract_store.rb +1 -0
- data/lib/rdf_context/store/memory_store.rb +1 -1
- data/lib/rdf_context/string_hacks.rb +1 -1
- data/lib/rdf_context/uriref.rb +5 -2
- data/spec/bnode_spec.rb +1 -1
- data/spec/graph_spec.rb +77 -10
- data/spec/rdf_helper.rb +4 -1
- data/spec/turtle_serializer_spec.rb +227 -0
- data/spec/xml_serializer_spec.rb +378 -0
- metadata +12 -3
@@ -0,0 +1,236 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'abstract_serializer')
|
2
|
+
|
3
|
+
module RdfContext
|
4
|
+
# Serialize RDF graphs in NTriples format
|
5
|
+
class XmlSerializer < RecursiveSerializer
|
6
|
+
VALID_ATTRIBUTES = [:none, :untyped, :typed]
|
7
|
+
|
8
|
+
def initialize(graph)
|
9
|
+
super
|
10
|
+
@force_RDF_about = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Serialize the graph
|
14
|
+
#
|
15
|
+
# @param [IO, StreamIO] stream:: Stream in which to place serialized graph
|
16
|
+
# @param [Hash] options:: Options for parser
|
17
|
+
# <em>options[:base]</em>:: Base URI of graph, used to shorting URI references
|
18
|
+
# <em>options[:max_depth]</em>:: Maximum depth for recursively defining resources, defaults to 3
|
19
|
+
# <em>options[:lang]</em>:: Output as root xml:lang attribute, and avoid generation xml:lang where possible
|
20
|
+
# <em>options[:attributes]</em>:: How to use XML attributes when serializing, one of :none, :untyped, :typed. The default is none.
|
21
|
+
#
|
22
|
+
# -- Serialization Examples
|
23
|
+
# attributes == :none
|
24
|
+
#
|
25
|
+
# serialize(io, :attributes => none)
|
26
|
+
def serialize(stream, options = {})
|
27
|
+
@max_depth = options[:max_depth] || 3
|
28
|
+
@base = options[:base]
|
29
|
+
@lang = options[:lang]
|
30
|
+
@attributes = options[:attributes] || :none
|
31
|
+
raise "Invalid attribute option '#{@attributes}', should be one of #{VALID_ATTRIBUTES.to_sentence}" unless VALID_ATTRIBUTES.include?(@attributes.to_sym)
|
32
|
+
|
33
|
+
doc = Nokogiri::XML::Document.new
|
34
|
+
|
35
|
+
preprocess
|
36
|
+
|
37
|
+
predicates = @graph.predicates.uniq
|
38
|
+
possible = predicates | @graph.objects.uniq
|
39
|
+
namespaces = {}
|
40
|
+
required_namespaces = {}
|
41
|
+
possible.each do |res|
|
42
|
+
next unless res.is_a?(URIRef)
|
43
|
+
if !get_qname(res) # Creates Namespace mappings
|
44
|
+
[RDF_NS, DC_NS, OWL_NS, LOG_NS, RDF_NS, RDFS_NS, XHV_NS, XML_NS, XSD_NS, XSI_NS].each do |ns|
|
45
|
+
# Bind a standard namespace to the graph and try the lookup again
|
46
|
+
@graph.bind(ns) if ns.uri == res.base
|
47
|
+
required_namespaces[res.base] = true if !get_qname(res) && predicates.include?(res)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
add_namespace(RDF_NS)
|
52
|
+
add_namespace(XML_NS) if @base || @lang
|
53
|
+
|
54
|
+
# See if there's a default namespace, and favor it when generating element names.
|
55
|
+
# Lookup an equivalent prefixed namespace for use in generating attributes
|
56
|
+
@default_ns = @graph.namespace("")
|
57
|
+
if @default_ns
|
58
|
+
add_namespace(@default_ns)
|
59
|
+
prefix = @graph.prefix(@default_ns.uri)
|
60
|
+
@prefixed_default_ns = @graph.namespace(prefix)
|
61
|
+
add_namespace(@prefixed_default_ns) if @prefixed_default_ns
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add bindings for predicates not already having bindings
|
65
|
+
tmp_ns = "ns0"
|
66
|
+
required_namespaces.keys.each do |uri|
|
67
|
+
puts "serialize: create temporary namespace for <#{uri}>" if $DEBUG
|
68
|
+
add_namespace(Namespace.new(uri, tmp_ns))
|
69
|
+
tmp_ns = tmp_ns.succ
|
70
|
+
end
|
71
|
+
|
72
|
+
doc.root = Nokogiri::XML::Element.new("rdf:RDF", doc)
|
73
|
+
@namespaces.each_pair do |p, ns|
|
74
|
+
if p.to_s.empty?
|
75
|
+
doc.root.default_namespace = ns.uri.to_s
|
76
|
+
else
|
77
|
+
doc.root.add_namespace(p, ns.uri.to_s)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
doc.root["xml:lang"] = @lang if @lang
|
81
|
+
doc.root["xml:base"] = @base if @base
|
82
|
+
|
83
|
+
# Add statements for each subject
|
84
|
+
order_subjects.each do |subject|
|
85
|
+
#puts "subj: #{subject.inspect}"
|
86
|
+
subject(subject, doc.root)
|
87
|
+
end
|
88
|
+
|
89
|
+
doc.write_xml_to(stream, :encoding => "UTF-8", :indent => 2)
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
93
|
+
def subject(subject, parent_node)
|
94
|
+
node = nil
|
95
|
+
|
96
|
+
if !is_done?(subject)
|
97
|
+
subject_done(subject)
|
98
|
+
properties = @graph.properties(subject)
|
99
|
+
prop_list = sort_properties(properties)
|
100
|
+
puts "subject: #{subject.to_n3}, props: #{properties.inspect}" if $DEBUG
|
101
|
+
|
102
|
+
rdf_type, *rest = properties.fetch(RDF_TYPE.to_s, [])
|
103
|
+
properties[RDF_TYPE.to_s] = rest
|
104
|
+
if rdf_type.is_a?(URIRef)
|
105
|
+
element = get_qname(rdf_type)
|
106
|
+
if rdf_type.namespace && @default_ns && rdf_type.namespace.uri == @default_ns.uri
|
107
|
+
element = rdf_type.short_name
|
108
|
+
end
|
109
|
+
end
|
110
|
+
element ||= "rdf:Description"
|
111
|
+
|
112
|
+
node = Nokogiri::XML::Element.new(element, parent_node.document)
|
113
|
+
|
114
|
+
if subject.is_a?(BNode)
|
115
|
+
# Only need nodeID if it's referenced elsewhere
|
116
|
+
node["rdf:nodeID"] = subject.to_s if ref_count(subject) > (@depth == 0 ? 0 : 1)
|
117
|
+
else
|
118
|
+
node["rdf:about"] = relativize(subject)
|
119
|
+
end
|
120
|
+
|
121
|
+
prop_list.each do |prop|
|
122
|
+
prop_ref = URIRef.new(prop)
|
123
|
+
|
124
|
+
properties[prop].each do |object|
|
125
|
+
@depth += 1
|
126
|
+
predicate(prop_ref, object, node, properties[prop].length == 1)
|
127
|
+
@depth -= 1
|
128
|
+
end
|
129
|
+
end
|
130
|
+
elsif @force_RDF_about.include?(subject)
|
131
|
+
puts "subject: #{subject.to_n3}, force about" if $DEBUG
|
132
|
+
node = Nokogiri::XML::Element.new("rdf:Description", parent_node.document)
|
133
|
+
node["rdf:about"] = relativize(subject)
|
134
|
+
@force_RDF_about.delete(subject)
|
135
|
+
end
|
136
|
+
|
137
|
+
parent_node.add_child(node) if node
|
138
|
+
end
|
139
|
+
|
140
|
+
# Output a predicate into the specified node.
|
141
|
+
#
|
142
|
+
# If _is_unique_ is true, this predicate may be able to be serialized as an attribute
|
143
|
+
def predicate(prop, object, node, is_unique)
|
144
|
+
qname = prop.to_qname(uri_binding)
|
145
|
+
|
146
|
+
# See if we can serialize as attribute.
|
147
|
+
# * untyped attributes that aren't duplicated where xml:lang == @lang
|
148
|
+
# * typed attributes that aren't duplicated if @dt_as_attr is true
|
149
|
+
# * rdf:type
|
150
|
+
as_attr = false
|
151
|
+
as_attr ||= true if [:untyped, :typed].include?(@attributes) && prop == RDF_TYPE
|
152
|
+
|
153
|
+
# Untyped attribute with no lang, or whos lang is the same as the default and RDF_TYPE
|
154
|
+
as_attr ||= true if [:untyped, :typed].include?(@attributes) &&
|
155
|
+
(object.is_a?(Literal) && object.untyped? && (object.lang.nil? || object.lang == @lang))
|
156
|
+
|
157
|
+
as_attr ||= true if [:typed].include?(@attributes) && object.is_a?(Literal) && object.typed?
|
158
|
+
|
159
|
+
as_attr = false unless is_unique
|
160
|
+
|
161
|
+
# Can't do as an attr if the qname has no prefix and there is no prefixed version
|
162
|
+
if @default_ns && prop.namespace.uri == @default_ns.uri
|
163
|
+
if as_attr
|
164
|
+
if @prefixed_default_ns
|
165
|
+
qname = "#{@prefixed_default_ns.prefix}:#{prop.short_name}"
|
166
|
+
else
|
167
|
+
as_attr = false
|
168
|
+
end
|
169
|
+
else
|
170
|
+
qname = prop.short_name
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
puts "predicate: #{qname}, as_attr: #{as_attr}, object: #{object.inspect}, done: #{is_done?(object)}, sub: #{@subjects.include?(object)}" if $DEBUG
|
175
|
+
qname = "rdf:li" if qname.match(/rdf:_\d+/)
|
176
|
+
pred_node = Nokogiri::XML::Element.new(qname, node.document)
|
177
|
+
|
178
|
+
if object.is_a?(Literal) || is_done?(object) || !@subjects.include?(object)
|
179
|
+
# Literals or references to objects that aren't subjects, or that have already been serialized
|
180
|
+
|
181
|
+
args = object.xml_args
|
182
|
+
puts "predicate: args=#{args.inspect}" if $DEBUG
|
183
|
+
attrs = args.pop
|
184
|
+
|
185
|
+
if as_attr
|
186
|
+
# Serialize as attribute
|
187
|
+
pred_node.unlink
|
188
|
+
pred_node = nil
|
189
|
+
node[qname] = object.is_a?(URIRef) ? relativize(object) : object.to_s
|
190
|
+
else
|
191
|
+
# Serialize as element
|
192
|
+
attrs.each_pair do |a, av|
|
193
|
+
next if a == "xml:lang" && av == @lang # Lang already specified, don't repeat
|
194
|
+
av = relativize(object) if a == "#{RDF_NS.prefix}:resource"
|
195
|
+
puts " elt attr #{a}=#{av}" if $DEBUG
|
196
|
+
pred_node[a] = av.to_s
|
197
|
+
end
|
198
|
+
puts " elt #{'xmllit ' if object.is_a?(Literal) && object.xmlliteral?}content=#{args.first}" if $DEBUG && !args.empty?
|
199
|
+
if object.is_a?(Literal) && object.xmlliteral?
|
200
|
+
pred_node.add_child(Nokogiri::XML::CharacterData.new(args.first, node.document))
|
201
|
+
elsif args.first
|
202
|
+
pred_node.content = args.first unless args.empty?
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
# Check to see if it can be serialized as a collection
|
207
|
+
col = @graph.seq(object)
|
208
|
+
conformant_list = col.all? {|item| !item.is_a?(Literal)}
|
209
|
+
o_props = @graph.properties(object)
|
210
|
+
if conformant_list && o_props[RDF_NS.first.to_s]
|
211
|
+
# Serialize list as parseType="Collection"
|
212
|
+
pred_node["rdf:parseType"] = "Collection"
|
213
|
+
col.each do |item|
|
214
|
+
# Mark the BNode subject of each item as being complete, so that it is not serialized
|
215
|
+
@graph.triples(Triple.new(nil, RDF_NS.first, item)) do |triple, ctx|
|
216
|
+
subject_done(triple.subject)
|
217
|
+
end
|
218
|
+
@force_RDF_about[item] = true
|
219
|
+
subject(item, pred_node)
|
220
|
+
end
|
221
|
+
else
|
222
|
+
if @depth < @max_depth
|
223
|
+
@depth += 1
|
224
|
+
subject(object, pred_node)
|
225
|
+
@depth -= 1
|
226
|
+
elsif object.is_a?(BNode)
|
227
|
+
pred_node["rdf:nodeID"] = object.identifier
|
228
|
+
else
|
229
|
+
pred_node["rdf:resource"] = relativize(object)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
node.add_child(pred_node) if pred_node
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
@@ -252,7 +252,7 @@ module RdfContext
|
|
252
252
|
end
|
253
253
|
|
254
254
|
def size(context = nil)
|
255
|
-
context = nil if
|
255
|
+
context = nil if (context.respond_to?(:identifier) ? context.identifier : context) == @identifier
|
256
256
|
|
257
257
|
triples(Triple.new(nil, nil, nil), context).length
|
258
258
|
end
|
@@ -102,7 +102,7 @@ class String
|
|
102
102
|
(?:\\[\\bfnrt"/]) # Escaped control characters, " and /
|
103
103
|
|(?:\\U00\h{6}) # 6 byte escaped Unicode
|
104
104
|
|(?:\\u\h{4}) # 4 byte escaped Unicode
|
105
|
-
)
|
105
|
+
)x
|
106
106
|
else
|
107
107
|
UNESCAPE_RE = %r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n
|
108
108
|
end
|
data/lib/rdf_context/uriref.rb
CHANGED
@@ -72,6 +72,10 @@ module RdfContext
|
|
72
72
|
self.to_s == other.to_s
|
73
73
|
end
|
74
74
|
alias_method :==, :eql?
|
75
|
+
|
76
|
+
def <=>(other)
|
77
|
+
self.to_s <=> other.to_s
|
78
|
+
end
|
75
79
|
|
76
80
|
# Needed for uniq
|
77
81
|
def hash; to_s.hash; end
|
@@ -88,8 +92,7 @@ module RdfContext
|
|
88
92
|
# Output URI as QName using URI binding
|
89
93
|
def to_qname(uri_binding = {})
|
90
94
|
ns = namespace(uri_binding)
|
91
|
-
|
92
|
-
"#{ns.prefix}:#{sn}"
|
95
|
+
"#{ns.prefix}:#{short_name}"
|
93
96
|
end
|
94
97
|
|
95
98
|
def namespace(uri_binding = {})
|
data/spec/bnode_spec.rb
CHANGED
@@ -47,7 +47,7 @@ describe "Blank nodes" do
|
|
47
47
|
describe "which has a blank identifier" do
|
48
48
|
subject { BNode.new("", @context) }
|
49
49
|
it "should not be the same as an anonymous identifier" do should_not == BNode.new end
|
50
|
-
it "should be the same as another blank identifier" do
|
50
|
+
it "should not be the same as another blank identifier" do should_not == BNode.new("", @context) end
|
51
51
|
end
|
52
52
|
|
53
53
|
describe "which are anonymous" do
|
data/spec/graph_spec.rb
CHANGED
@@ -299,6 +299,62 @@ HERE
|
|
299
299
|
subject.size.should == 0
|
300
300
|
end
|
301
301
|
|
302
|
+
describe "properties" do
|
303
|
+
subject { Graph.new }
|
304
|
+
|
305
|
+
it "should get asserted properties" do
|
306
|
+
subject.add_triple(@ex.a, @ex.b, @ex.c)
|
307
|
+
subject.properties(@ex.a).should be_a(Hash)
|
308
|
+
subject.properties(@ex.a).size.should == 1
|
309
|
+
subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
|
310
|
+
subject.properties(@ex.a)[@ex.b.to_s].should == [@ex.c]
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should get asserted properties with 2 properties" do
|
314
|
+
subject.add_triple(@ex.a, @ex.b, @ex.c)
|
315
|
+
subject.add_triple(@ex.a, @ex.b, @ex.d)
|
316
|
+
subject.properties(@ex.a).should be_a(Hash)
|
317
|
+
subject.properties(@ex.a).size.should == 1
|
318
|
+
subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
|
319
|
+
subject.properties(@ex.a)[@ex.b.to_s].should include(@ex.c, @ex.d)
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should get asserted properties with 3 properties" do
|
323
|
+
subject.add_triple(@ex.a, @ex.b, @ex.c)
|
324
|
+
subject.add_triple(@ex.a, @ex.b, @ex.d)
|
325
|
+
subject.add_triple(@ex.a, @ex.b, @ex.e)
|
326
|
+
subject.properties(@ex.a).should be_a(Hash)
|
327
|
+
subject.properties(@ex.a).size.should == 1
|
328
|
+
subject.properties(@ex.a).has_key?(@ex.b.to_s).should be_true
|
329
|
+
subject.properties(@ex.a)[@ex.b.to_s].should include(@ex.c, @ex.d, @ex.e)
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should get asserted type with single type" do
|
333
|
+
subject.add_triple(@ex.a, RDF_TYPE, @ex.Audio)
|
334
|
+
subject.properties(@ex.a)[RDF_TYPE.to_s].should == [@ex.Audio]
|
335
|
+
subject.type_of(@ex.a).should == [@ex.Audio]
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should get nil with no type" do
|
339
|
+
subject.add_triple(@ex.a, @ex.b, @ex.c)
|
340
|
+
subject.properties(@ex.a)[RDF_TYPE.to_s].should == nil
|
341
|
+
subject.type_of(@ex.a).should == []
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should sync properties to graph" do
|
345
|
+
props = subject.properties(@ex.a)
|
346
|
+
props.should be_a(Hash)
|
347
|
+
props[RDF_TYPE.to_s] = @ex.Audio
|
348
|
+
props[DC_NS.title.to_s] = "title"
|
349
|
+
props[@ex.b.to_s] = [@ex.c, @ex.d]
|
350
|
+
subject.sync_properties(@ex.a)
|
351
|
+
subject.contains?(Triple.new(@ex.a, RDF_TYPE, @ex.Audio)).should be_true
|
352
|
+
subject.contains?(Triple.new(@ex.a, DC_NS.title, "title")).should be_true
|
353
|
+
subject.contains?(Triple.new(@ex.a, @ex.b, @ex.c)).should be_true
|
354
|
+
subject.contains?(Triple.new(@ex.a, @ex.b, @ex.d)).should be_true
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
302
358
|
describe "find triples" do
|
303
359
|
it "should find subjects" do
|
304
360
|
subject.triples(Triple.new(@ex.john, nil, nil)).size.should == 2
|
@@ -331,12 +387,13 @@ HERE
|
|
331
387
|
it "should output RDF/XML" do
|
332
388
|
rdfxml = <<-HERE
|
333
389
|
<?xml version="1.0" encoding="UTF-8"?>
|
334
|
-
<rdf:RDF xmlns:
|
390
|
+
<rdf:RDF xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:ex="http://example.org/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
335
391
|
<rdf:Description rdf:about="http://example.org/john">
|
336
|
-
<foaf:knows
|
337
|
-
|
338
|
-
|
339
|
-
|
392
|
+
<foaf:knows>
|
393
|
+
<rdf:Description rdf:about="http://example.org/jane">
|
394
|
+
<foaf:knows rdf:resource="http://example.org/rick"/>
|
395
|
+
</rdf:Description>
|
396
|
+
</foaf:knows>
|
340
397
|
<foaf:knows rdf:resource="http://example.org/rick"/>
|
341
398
|
</rdf:Description>
|
342
399
|
</rdf:RDF>
|
@@ -362,7 +419,7 @@ HERE
|
|
362
419
|
end
|
363
420
|
|
364
421
|
describe "rdf:first/rdf:rest sequences" do
|
365
|
-
|
422
|
+
it "should return object list" do
|
366
423
|
a, b = BNode.new("a"), BNode.new("b"), BNode.new("c")
|
367
424
|
g = Graph.new(:store => ListStore.new)
|
368
425
|
g.add_triple(@ex.List, RDF_NS.first, @ex.john)
|
@@ -372,11 +429,21 @@ HERE
|
|
372
429
|
g.add_triple(b, RDF_NS.first, @ex.rick)
|
373
430
|
g.add_triple(b, RDF_NS.rest, RDF_NS.nil)
|
374
431
|
g.bind(@ex)
|
375
|
-
|
376
|
-
|
432
|
+
|
433
|
+
#puts g.seq(@ex.List).inspect
|
434
|
+
g.seq(@ex.List).should == [@ex.john, @ex.jane, @ex.rick]
|
435
|
+
end
|
377
436
|
|
378
|
-
it "should
|
379
|
-
|
437
|
+
it "should generate a list of resources" do
|
438
|
+
g = Graph.new(:store => ListStore.new)
|
439
|
+
g.add_seq(@ex.List, RDF_NS.first, [@ex.john, @ex.jane, @ex.rick])
|
440
|
+
g.seq(@ex.List).should == [@ex.john, @ex.jane, @ex.rick]
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should generate an empty list" do
|
444
|
+
g = Graph.new(:store => ListStore.new)
|
445
|
+
g.add_seq(@ex.List, RDF_NS.first, [])
|
446
|
+
g.seq(@ex.List).should == []
|
380
447
|
end
|
381
448
|
end
|
382
449
|
end
|
data/spec/rdf_helper.rb
CHANGED
@@ -105,7 +105,10 @@ module RdfHelper
|
|
105
105
|
|
106
106
|
return unless output
|
107
107
|
|
108
|
-
|
108
|
+
case self.compare
|
109
|
+
when :none
|
110
|
+
# Don't check output, just parse to graph
|
111
|
+
when :array
|
109
112
|
@parser.graph.should be_equivalent_graph(self.output, self)
|
110
113
|
else
|
111
114
|
output_parser = Parser.new
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
include RdfContext
|
3
|
+
|
4
|
+
describe "Turtle Serializer" do
|
5
|
+
describe "simple tests" do
|
6
|
+
it "should use full URIs without base" do
|
7
|
+
input = %(<http://a/b> <http://a/c> <http://a/d> .)
|
8
|
+
serialize(input, nil, %r(^<http://a/b> <http://a/c> <http://a/d> \.$))
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should use relative URIs with base" do
|
12
|
+
input = %(<http://a/b> <http://a/c> <http://a/d> .)
|
13
|
+
serialize(input, "http://a/",
|
14
|
+
%r(^@base <http://a/> \.$),
|
15
|
+
%r(^<b> <c> <d> \.$)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should use qname URIs with prefix" do
|
20
|
+
input = %(@prefix a: <http://a/> . <http://a/b> <http://a/c> <http://a/d> .)
|
21
|
+
serialize(input, nil,
|
22
|
+
%r(^@prefix a: <http://a/> \.$),
|
23
|
+
%r(^a:b a:c a:d \.$)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should use qname URIs with empty prefix" do
|
28
|
+
input = %(@prefix : <http://a/> . <http://a/b> <http://a/c> <http://a/d> .)
|
29
|
+
serialize(input, nil,
|
30
|
+
%r(^@prefix : <http://a/> \.$),
|
31
|
+
%r(^:b :c :d \.$)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should order properties" do
|
36
|
+
input = %(
|
37
|
+
@prefix : <http://a/> .
|
38
|
+
@prefix dc: <http://purl.org/dc/elements/1.1/> .
|
39
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
40
|
+
:b :c :d .
|
41
|
+
:b dc:title "title" .
|
42
|
+
:b a :class .
|
43
|
+
:b rdfs:label "label" .
|
44
|
+
)
|
45
|
+
serialize(input, nil,
|
46
|
+
%r(^:b a :class;$),
|
47
|
+
%r(^\s+rdfs:label "label";$),
|
48
|
+
%r(^\s+dc:title \"title\";$),
|
49
|
+
%r(^\s+:c :d \.$),
|
50
|
+
%r(a :class.*label.*title.*:c :d)m
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should generate object list" do
|
55
|
+
input = %(@prefix : <http://a/> . :b :c :d, :e .)
|
56
|
+
serialize(input, nil,
|
57
|
+
%r(^@prefix : <http://a/> \.$),
|
58
|
+
%r(^:b :c :d,$),
|
59
|
+
%r(^\s+:e \.$)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should generate property list" do
|
64
|
+
input = %(@prefix : <http://a/> . :b :c :d; :e :f .)
|
65
|
+
serialize(input, nil,
|
66
|
+
%r(^@prefix : <http://a/> \.$),
|
67
|
+
%r(^:b :c :d;$),
|
68
|
+
%r(^\s+:e :f \.$)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "anons" do
|
74
|
+
it "should generate bare anon" do
|
75
|
+
input = %(@prefix : <http://a/> . [:a :b] .)
|
76
|
+
serialize(input, nil,
|
77
|
+
%r(^\s*\[ :a :b\] \.$)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should generate anon as subject" do
|
82
|
+
input = %(@prefix : <http://a/> . [:a :b] :c :d .)
|
83
|
+
serialize(input, nil,
|
84
|
+
%r(^\s*\[ :a :b;$),
|
85
|
+
%r(^\s+:c :d\] \.$)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should generate anon as object" do
|
90
|
+
input = %(@prefix : <http://a/> . :a :b [:c :d] .)
|
91
|
+
serialize(input, nil,
|
92
|
+
%r(^\s*\:a :b \[ :c :d\] \.$)
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "lists" do
|
98
|
+
it "should generate bare list" do
|
99
|
+
input = %(@prefix : <http://a/> . (:a :b) .)
|
100
|
+
serialize(input, nil,
|
101
|
+
%r(^\(:a :b\) \.$)
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should generate literal list" do
|
106
|
+
input = %(@prefix : <http://a/> . :a :b ( "apple" "banana" ) .)
|
107
|
+
serialize(input, nil,
|
108
|
+
%r(^:a :b \("apple" "banana"\) \.$)
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should generate empty list" do
|
113
|
+
input = %(@prefix : <http://a/> . :a :b () .)
|
114
|
+
serialize(input, nil,
|
115
|
+
%r(^:a :b \(\) \.$)
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should generate empty list(2)" do
|
120
|
+
input = %(@prefix : <http://a/> . :emptyList = () .)
|
121
|
+
serialize(input, nil,
|
122
|
+
%r(^:emptyList <.*sameAs> \(\) \.$)
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should generate empty list as subject" do
|
127
|
+
input = %(@prefix : <http://a/> . () :a :b .)
|
128
|
+
serialize(input, nil,
|
129
|
+
%r(^\(\) :a :b \.$)
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should generate list as subject" do
|
134
|
+
input = %(@prefix : <http://a/> . (:a) :b :c .)
|
135
|
+
serialize(input, nil,
|
136
|
+
%r(^\(:a\) :b :c \.$)
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should generate list of empties" do
|
141
|
+
input = %(@prefix : <http://a/> . :listOf2Empties = (() ()) .)
|
142
|
+
serialize(input, nil,
|
143
|
+
%r(^:listOf2Empties <.*sameAs> \(\(\) \(\)\) \.$)
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should generate list anon" do
|
148
|
+
input = %(@prefix : <http://a/> . :twoAnons = ([a :mother] [a :father]) .)
|
149
|
+
serialize(input, nil,
|
150
|
+
%r(^:twoAnons <.*sameAs> \(\[\s*a :mother\] \[\s*a :father\]\) \.$)
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should generate owl:unionOf list" do
|
155
|
+
input = %(
|
156
|
+
@prefix : <http://a/> .
|
157
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
158
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
159
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
160
|
+
:a rdfs:domain [
|
161
|
+
a owl:Class;
|
162
|
+
owl:unionOf [
|
163
|
+
a owl:Class;
|
164
|
+
rdf:first :b;
|
165
|
+
rdf:rest [
|
166
|
+
a owl:Class;
|
167
|
+
rdf:first :c;
|
168
|
+
rdf:rest rdf:nil
|
169
|
+
]
|
170
|
+
]
|
171
|
+
] .
|
172
|
+
)
|
173
|
+
serialize(input, nil,
|
174
|
+
%r(:a rdfs:domain \[\s*a owl:Class;\s+owl:unionOf\s+\(:b\s+:c\)\]\s*\.$)m
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# W3C Turtle Test suite from http://www.w3.org/2000/10/swap/test/regression.n3
|
180
|
+
describe "w3c turtle tests" do
|
181
|
+
require 'rdf_helper'
|
182
|
+
|
183
|
+
def self.positive_tests
|
184
|
+
RdfHelper::TestCase.test_cases(TURTLE_TEST, TURTLE_DIR) rescue []
|
185
|
+
end
|
186
|
+
|
187
|
+
positive_tests.each do |t|
|
188
|
+
#puts t.inspect
|
189
|
+
#next unless t.name == "test-04"
|
190
|
+
|
191
|
+
specify "#{t.name}: " + (t.description || "#{t.inputDocument}") do
|
192
|
+
# Skip tests for very long files, too long
|
193
|
+
if %w(test-14 test-15 test-16 rdfq-results).include?(t.name)
|
194
|
+
pending("Skip very long input file")
|
195
|
+
elsif !defined?(::Encoding) && %w(test-18).include?(t.name)
|
196
|
+
pending("Not supported in Ruby 1.8")
|
197
|
+
elsif %w(test-29).include?(t.name)
|
198
|
+
pending("Silly test")
|
199
|
+
else
|
200
|
+
begin
|
201
|
+
t.run_test do |rdf_string, parser|
|
202
|
+
parser.parse(rdf_string, t.about.uri.to_s, :strict => true, :debug => [])
|
203
|
+
parser.graph.serialize(:format => :ttl, :base => t.about.uri.to_s)
|
204
|
+
t.compare = :none
|
205
|
+
end
|
206
|
+
#rescue #Spec::Expectations::ExpectationNotMetError => e
|
207
|
+
# pending() { raise }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Serialize ntstr to a string and compare against regexps
|
215
|
+
def serialize(ntstr, base = nil, *regexps)
|
216
|
+
g = Graph.new
|
217
|
+
g.parse(ntstr, base)
|
218
|
+
result = g.serialize(:format => :ttl, :base => base)
|
219
|
+
puts result if $verbose
|
220
|
+
|
221
|
+
regexps.each do |re|
|
222
|
+
result.should =~ re
|
223
|
+
end
|
224
|
+
|
225
|
+
result
|
226
|
+
end
|
227
|
+
end
|