rdf_context 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|