rdf-rdfxml 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,84 @@
1
1
  require 'nokogiri' # FIXME: Implement using different modules as in RDF::TriX
2
+ require 'rdf/rdfxml/patches/graph_properties'
2
3
 
3
4
  module RDF::RDFXML
4
5
  ##
5
6
  # An RDF/XML serialiser in Ruby
6
7
  #
8
+ # Note that the natural interface is to write a whole graph at a time.
9
+ # Writing statements or Triples will create a graph to add them to
10
+ # and then serialize the graph.
11
+ #
12
+ # @example Obtaining a RDF/XML writer class
13
+ # RDF::Writer.for(:rdf) #=> RDF::TriX::Writer
14
+ # RDF::Writer.for("etc/test.rdf")
15
+ # RDF::Writer.for(:file_name => "etc/test.rdf")
16
+ # RDF::Writer.for(:file_extension => "rdf")
17
+ # RDF::Writer.for(:content_type => "application/rdf+xml")
18
+ #
19
+ # @example Serializing RDF graph into an RDF/XML file
20
+ # RDF::RDFXML::Write.open("etc/test.rdf") do |writer|
21
+ # writer.write_graph(graph)
22
+ # end
23
+ #
24
+ # @example Serializing RDF statements into an RDF/XML file
25
+ # RDF::RDFXML::Writer.open("etc/test.rdf") do |writer|
26
+ # graph.each_statement do |statement|
27
+ # writer << statement
28
+ # end
29
+ # end
30
+ #
31
+ # @example Serializing RDF statements into an RDF/XML string
32
+ # RDF::RDFXML::Writer.buffer do |writer|
33
+ # graph.each_statement do |statement|
34
+ # writer << statement
35
+ # end
36
+ # end
37
+ #
7
38
  # @author [Gregg Kellogg](http://kellogg-assoc.com/)
8
39
  class Writer < RDF::Writer
9
40
  format RDF::RDFXML::Format
10
41
 
11
42
  VALID_ATTRIBUTES = [:none, :untyped, :typed]
12
43
 
13
- attr_accessor :graph, :base
14
-
44
+ attr_accessor :graph, :base_uri
15
45
 
16
46
  ##
47
+ # Initializes the RDF/XML writer instance.
48
+ #
49
+ # Opitons:
50
+ # max_depth:: Maximum depth for recursively defining resources, defaults to 3
51
+ # base_uri:: Base URI of graph, used to shorting URI references
52
+ # lang:: Output as root xml:lang attribute, and avoid generation _xml:lang_ where possible
53
+ # attributes:: How to use XML attributes when serializing, one of :none, :untyped, :typed. The default is :none.
54
+ # defafult_ns:: URI to use as default namespace
55
+ #
17
56
  # @param [IO, File] output
18
57
  # @param [Hash{Symbol => Object}] options
58
+ # @option options [Integer] :max_depth (nil)
59
+ # @option options [String, #to_s] :base_uri (nil)
60
+ # @option options [String, #to_s] :lang (nil)
61
+ # @option options [Array] :attributes (nil)
62
+ # @option options [String] :default_namespace
19
63
  # @yield [writer]
20
64
  # @yieldparam [RDF::Writer] writer
21
65
  def initialize(output = $stdout, options = {}, &block)
22
- super do
23
- @graph = RDF::Graph.new
24
- @stream = nil
25
- @base = nil
26
- @force_RDF_about = {}
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
- self.reset
33
- end
66
+ @graph = RDF::Graph.new
67
+ super
68
+ end
69
+
70
+ ##
71
+ # @param [Graph] graph
72
+ # @return [void]
73
+ def write_graph(graph)
74
+ @graph = graph
75
+ end
76
+
77
+ ##
78
+ # @param [Statement] statement
79
+ # @return [void]
80
+ def write_statement(statement)
81
+ @graph << statement
34
82
  end
35
83
 
36
84
  ##
@@ -42,7 +90,7 @@ module RDF::RDFXML
42
90
  # @return [void]
43
91
  # @see #write_epilogue
44
92
  def write_triple(subject, predicate, object)
45
- @graph << [subject, predicate, object]
93
+ @graph << RDF::Statement.new(subject, predicate, object)
46
94
  end
47
95
 
48
96
  ##
@@ -51,64 +99,59 @@ module RDF::RDFXML
51
99
  # @return [void]
52
100
  # @see #write_triple
53
101
  def write_epilogue
102
+ @base_uri = nil
103
+ @force_RDF_about = {}
104
+ @max_depth = @options[:max_depth] || 3
105
+ @base_uri = @options[:base_uri]
106
+ @lang = @options[:lang]
107
+ @attributes = @options[:attributes] || :none
108
+ @debug = @options[:debug]
109
+ @default_namespace = @options[:default_namespace]
110
+ raise "Invalid attribute option '#{@attributes}', should be one of #{VALID_ATTRIBUTES.to_sentence}" unless VALID_ATTRIBUTES.include?(@attributes.to_sym)
111
+ self.reset
112
+
54
113
  doc = Nokogiri::XML::Document.new
55
114
 
56
- puts "\nserialize: graph namespaces: #{@graph.nsbinding.inspect}" if $DEBUG
115
+ add_debug "\nserialize: graph namespaces: #{@namespaces.inspect}"
116
+ add_debug "\nserialize: graph: #{@graph.size}"
57
117
 
58
118
  preprocess
59
119
 
60
120
  predicates = @graph.predicates.uniq
121
+ add_debug "\nserialize: predicates #{predicates.inspect}"
61
122
  possible = predicates + @graph.objects.uniq
62
123
  namespaces = {}
63
124
  required_namespaces = {}
64
125
  possible.each do |res|
65
- next unless res.is_a?(RDF::URI)
66
- if res.namespace
67
- add_namespace(res.namespace)
68
- else
69
- required_namespaces[res.base] = true
70
- end
71
- #puts "possible namespace for #{res}: #{res.namespace || %(<#{res.base}>)}"
126
+ get_qname(res)
72
127
  end
73
- add_namespace(RDF_NS)
74
- add_namespace(XML_NS) if @base || @lang
128
+ add_namespace(:rdf, RDF_NS)
129
+ add_namespace(:xml, RDF::XML) if @base_uri || @lang
75
130
 
76
- # See if there's a default namespace, and favor it when generating element names.
77
- # Lookup an equivalent prefixed namespace for use in generating attributes
78
- @default_ns = @graph.namespace("")
79
- if @default_ns
80
- add_namespace(@default_ns)
81
- prefix = @graph.prefix(@default_ns.uri)
82
- @prefixed_default_ns = @graph.namespace(prefix)
83
- add_namespace(@prefixed_default_ns) if @prefixed_default_ns
131
+ if @default_namespace
132
+ add_namespace("", @default_namespace)
133
+ @default_namespace_prefix = @namespaces.invert[@default_namespace]
134
+ add_debug("def_namespace: #{@default_namespace}, prefix: #{@default_namespace_prefix}")
84
135
  end
85
136
 
86
- # Add bindings for predicates not already having bindings
87
- tmp_ns = "ns0"
88
- required_namespaces.keys.each do |uri|
89
- puts "create namespace definition for #{uri}" if $DEBUG
90
- add_namespace(Namespace.new(uri, tmp_ns))
91
- tmp_ns = tmp_ns.succ
92
- end
93
-
94
137
  doc.root = Nokogiri::XML::Element.new("rdf:RDF", doc)
95
- @namespaces.each_pair do |p, ns|
138
+ @namespaces.each_pair do |p, uri|
96
139
  if p.to_s.empty?
97
- doc.root.default_namespace = ns.uri.to_s
140
+ doc.root.default_namespace = uri.to_s
98
141
  else
99
- doc.root.add_namespace(p, ns.uri.to_s)
142
+ doc.root.add_namespace(p.to_s, uri.to_s)
100
143
  end
101
144
  end
102
145
  doc.root["xml:lang"] = @lang if @lang
103
- doc.root["xml:base"] = @base if @base
146
+ doc.root["xml:base"] = @base_uri if @base_uri
104
147
 
105
148
  # Add statements for each subject
106
149
  order_subjects.each do |subject|
107
- #puts "subj: #{subject.inspect}"
150
+ #add_debug "subj: #{subject.inspect}"
108
151
  subject(subject, doc.root)
109
152
  end
110
153
 
111
- doc.write_xml_to(stream, :encoding => "UTF-8", :indent => 2)
154
+ doc.write_xml_to(@output, :encoding => "UTF-8", :indent => 2)
112
155
  end
113
156
 
114
157
  protected
@@ -119,23 +162,25 @@ module RDF::RDFXML
119
162
  subject_done(subject)
120
163
  properties = @graph.properties(subject)
121
164
  prop_list = sort_properties(properties)
122
- puts "subject: #{subject.to_n3}, props: #{properties.inspect}" if $DEBUG
165
+ add_debug "subject: #{subject.inspect}, props: #{properties.inspect}"
123
166
 
124
- rdf_type, *rest = properties.fetch(RDF_TYPE.to_s, [])
167
+ rdf_type, *rest = properties.fetch(RDF.type.to_s, [])
125
168
  if rdf_type.is_a?(RDF::URI)
126
169
  element = get_qname(rdf_type)
127
- properties[RDF_TYPE.to_s] = rest
128
- type_ns = rdf_type.namespace rescue nil
129
- if type_ns && @default_ns && type_ns.uri == @default_ns.uri
130
- properties[RDF_TYPE.to_s] = rest
131
- element = rdf_type.short_name
170
+ properties[RDF.type.to_s] = rest
171
+
172
+ # FIXME: different namespace logic
173
+ type_ns = rdf_type.vocab rescue nil
174
+ if type_ns && @default_namespace && type_ns.to_s == @default_namespace.to_s
175
+ properties[RDF.type.to_s] = rest
176
+ element = rdf_type.qname.last
132
177
  end
133
178
  end
134
179
  element ||= "rdf:Description"
135
180
 
136
181
  node = Nokogiri::XML::Element.new(element, parent_node.document)
137
182
 
138
- if subject.is_a?(BNode)
183
+ if subject.is_a?(RDF::Node)
139
184
  # Only need nodeID if it's referenced elsewhere
140
185
  node["rdf:nodeID"] = subject.to_s if ref_count(subject) > (@depth == 0 ? 0 : 1)
141
186
  else
@@ -152,7 +197,7 @@ module RDF::RDFXML
152
197
  end
153
198
  end
154
199
  elsif @force_RDF_about.include?(subject)
155
- puts "subject: #{subject.to_n3}, force about" if $DEBUG
200
+ add_debug "subject: #{subject.inspect}, force about"
156
201
  node = Nokogiri::XML::Element.new("rdf:Description", parent_node.document)
157
202
  node["rdf:about"] = relativize(subject)
158
203
  @force_RDF_about.delete(subject)
@@ -165,7 +210,7 @@ module RDF::RDFXML
165
210
  #
166
211
  # If _is_unique_ is true, this predicate may be able to be serialized as an attribute
167
212
  def predicate(prop, object, node, is_unique)
168
- qname = prop.to_qname(uri_binding)
213
+ qname = get_qname(prop)
169
214
  raise RdfException, "No qname generated for <#{prop}>" unless qname
170
215
 
171
216
  # See if we can serialize as attribute.
@@ -173,72 +218,77 @@ module RDF::RDFXML
173
218
  # * typed attributes that aren't duplicated if @dt_as_attr is true
174
219
  # * rdf:type
175
220
  as_attr = false
176
- as_attr ||= true if [:untyped, :typed].include?(@attributes) && prop == RDF_TYPE
221
+ as_attr ||= true if [:untyped, :typed].include?(@attributes) && prop == RDF.type
177
222
 
178
- # Untyped attribute with no lang, or whos lang is the same as the default and RDF_TYPE
223
+ # Untyped attribute with no lang, or whos lang is the same as the default and RDF.type
224
+ add_debug("as_attr? #{@attributes}, plain? #{object.plain?}, lang #{@lang || 'nil'}:#{object.language || 'nil'}") if object.is_a?(RDF::Literal)
179
225
  as_attr ||= true if [:untyped, :typed].include?(@attributes) &&
180
- (object.is_a?(Literal) && object.untyped? && (object.lang.nil? || object.lang == @lang))
226
+ object.is_a?(RDF::Literal) && (object.plain? || (@lang && object.language.to_s == @lang.to_s))
181
227
 
182
- as_attr ||= true if [:typed].include?(@attributes) && object.is_a?(Literal) && object.typed?
228
+ as_attr ||= true if [:typed].include?(@attributes) && object.is_a?(RDF::Literal) && object.typed?
183
229
 
184
230
  as_attr = false unless is_unique
185
231
 
186
232
  # Can't do as an attr if the qname has no prefix and there is no prefixed version
187
- if @default_ns && prop.namespace.uri == @default_ns.uri
233
+ if @default_namespace && prop.vocab.to_s == @default_namespace.to_s
188
234
  if as_attr
189
- if @prefixed_default_ns
190
- qname = "#{@prefixed_default_ns.prefix}:#{prop.short_name}"
235
+ if @default_namespace_prefix
236
+ qname = "#{@default_namespace_prefix}:#{prop.qname.last}"
191
237
  else
192
238
  as_attr = false
193
239
  end
194
240
  else
195
- qname = prop.short_name
241
+ qname = prop.qname.last
196
242
  end
197
243
  end
198
244
 
199
- puts "predicate: #{qname}, as_attr: #{as_attr}, object: #{object.inspect}, done: #{is_done?(object)}, sub: #{@subjects.include?(object)}" if $DEBUG
245
+ add_debug "predicate: #{qname}, as_attr: #{as_attr}, object: #{object.inspect}, done: #{is_done?(object)}, sub: #{@subjects.include?(object)}"
200
246
  qname = "rdf:li" if qname.match(/rdf:_\d+/)
201
247
  pred_node = Nokogiri::XML::Element.new(qname, node.document)
202
248
 
203
- if object.is_a?(Literal) || is_done?(object) || !@subjects.include?(object)
249
+ if object.is_a?(RDF::Literal) || is_done?(object) || !@subjects.include?(object)
204
250
  # Literals or references to objects that aren't subjects, or that have already been serialized
205
251
 
206
- args = object.xml_args
207
- puts "predicate: args=#{args.inspect}" if $DEBUG
252
+ args = xml_args(object)
253
+ add_debug "predicate: args=#{args.inspect}"
208
254
  attrs = args.pop
209
255
 
210
256
  if as_attr
211
257
  # Serialize as attribute
212
258
  pred_node.unlink
213
259
  pred_node = nil
214
- node[qname] = object.is_a?(RDF::URI) ? relativize(object) : object.to_s
260
+ node[qname] = object.is_a?(RDF::URI) ? relativize(object) : object.value
261
+ add_debug("node[#{qname}]=#{node[qname]}, #{object.class}")
215
262
  else
216
263
  # Serialize as element
264
+ add_debug("serialize as element: #{attrs.inspect}")
217
265
  attrs.each_pair do |a, av|
218
- next if a == "xml:lang" && av == @lang # Lang already specified, don't repeat
219
- av = relativize(object) if a == "#{RDF_NS.prefix}:resource"
220
- puts " elt attr #{a}=#{av}" if $DEBUG
266
+ next if a.to_s == "xml:lang" && av.to_s == @lang # Lang already specified, don't repeat
267
+ av = relativize(object) if a == "rdf:resource"
268
+ add_debug " elt attr #{a}=#{av}"
221
269
  pred_node[a] = av.to_s
222
270
  end
223
- puts " elt #{'xmllit ' if object.is_a?(Literal) && object.xmlliteral?}content=#{args.first}" if $DEBUG && !args.empty?
224
- if object.is_a?(Literal) && object.xmlliteral?
271
+ add_debug " elt #{'xmllit ' if object.is_a?(RDF::Literal) && object.xmlliteral?}content=#{args.first}" if !args.empty?
272
+ if object.is_a?(RDF::Literal) && object.xmlliteral?
225
273
  pred_node.add_child(Nokogiri::XML::CharacterData.new(args.first, node.document))
226
274
  elsif args.first
227
275
  pred_node.content = args.first unless args.empty?
228
276
  end
229
277
  end
230
278
  else
279
+ require 'rdf/rdfxml/patches/seq' unless RDF::Graph.respond_to?(:seq)
280
+
231
281
  # Check to see if it can be serialized as a collection
232
282
  col = @graph.seq(object)
233
- conformant_list = col.all? {|item| !item.is_a?(Literal)}
283
+ conformant_list = col.all? {|item| !item.is_a?(RDF::Literal)}
234
284
  o_props = @graph.properties(object)
235
- if conformant_list && o_props[RDF_NS.first.to_s]
285
+ if conformant_list && o_props[RDF.first.to_s]
236
286
  # Serialize list as parseType="Collection"
237
287
  pred_node["rdf:parseType"] = "Collection"
238
288
  col.each do |item|
239
289
  # Mark the BNode subject of each item as being complete, so that it is not serialized
240
- @graph.triples(Triple.new(nil, RDF_NS.first, item)) do |triple, ctx|
241
- subject_done(triple.subject)
290
+ @graph.query(:predicate => RDF.first, :object => item) do |statement|
291
+ subject_done(statement.subject)
242
292
  end
243
293
  @force_RDF_about[item] = true
244
294
  subject(item, pred_node)
@@ -248,7 +298,7 @@ module RDF::RDFXML
248
298
  @depth += 1
249
299
  subject(object, pred_node)
250
300
  @depth -= 1
251
- elsif object.is_a?(BNode)
301
+ elsif object.is_a?(RDF::Node)
252
302
  pred_node["rdf:nodeID"] = object.identifier
253
303
  else
254
304
  pred_node["rdf:resource"] = relativize(object)
@@ -260,7 +310,7 @@ module RDF::RDFXML
260
310
 
261
311
  def relativize(uri)
262
312
  uri = uri.to_s
263
- self.base ? uri.sub(/^#{self.base}/, "") : uri
313
+ self.base_uri ? uri.sub(/^#{self.base_uri}/, "") : uri
264
314
  end
265
315
 
266
316
  def preprocess_triple(triple)
@@ -268,7 +318,7 @@ module RDF::RDFXML
268
318
 
269
319
  # Pre-fetch qnames, to fill namespaces
270
320
  get_qname(triple.predicate)
271
- get_qname(triple.object) if triple.predicate == RDF_TYPE
321
+ get_qname(triple.object) if triple.predicate == RDF.type
272
322
 
273
323
  @references[triple.predicate] = ref_count(triple.predicate) + 1
274
324
  end
@@ -276,8 +326,8 @@ module RDF::RDFXML
276
326
  MAX_DEPTH = 10
277
327
  INDENT_STRING = " "
278
328
 
279
- def top_classes; [RDFS_NS.Class]; end
280
- def predicate_order; [RDF_TYPE, RDFS_NS.label, DC_NS.title]; end
329
+ def top_classes; [RDF::RDFS.Class]; end
330
+ def predicate_order; [RDF.type, RDF::RDFS.label, RDF::DC.title]; end
281
331
 
282
332
  def is_done?(subject)
283
333
  @serialized.include?(subject)
@@ -293,8 +343,8 @@ module RDF::RDFXML
293
343
  subjects = []
294
344
 
295
345
  top_classes.each do |class_uri|
296
- graph.triples(Triple.new(nil, RDF_TYPE, class_uri)).map {|t| t.subject}.sort.uniq.each do |subject|
297
- #puts "order_subjects: #{subject.inspect}"
346
+ graph.query(:predicate => RDF.type, :object => class_uri).map {|st| st.subject}.sort.uniq.each do |subject|
347
+ #add_debug "order_subjects: #{subject.inspect}"
298
348
  subjects << subject
299
349
  seen[subject] = @top_levels[subject] = true
300
350
  end
@@ -303,21 +353,21 @@ module RDF::RDFXML
303
353
  # Sort subjects by resources over bnodes, ref_counts and the subject URI itself
304
354
  recursable = @subjects.keys.
305
355
  select {|s| !seen.include?(s)}.
306
- map {|r| [r.is_a?(BNode) ? 1 : 0, ref_count(r), r]}.
356
+ map {|r| [r.is_a?(RDF::Node) ? 1 : 0, ref_count(r), r]}.
307
357
  sort
308
358
 
309
359
  subjects += recursable.map{|r| r.last}
310
360
  end
311
361
 
312
362
  def preprocess
313
- @graph.triples.each {|t| preprocess_triple(t)}
363
+ @graph.each {|statement| preprocess_statement(statement)}
314
364
  end
315
365
 
316
- def preprocess_triple(triple)
317
- #puts "preprocess: #{triple.inspect}"
318
- references = ref_count(triple.object) + 1
319
- @references[triple.object] = references
320
- @subjects[triple.subject] = true
366
+ def preprocess_statement(statement)
367
+ #add_debug "preprocess: #{statement.inspect}"
368
+ references = ref_count(statement.object) + 1
369
+ @references[statement.object] = references
370
+ @subjects[statement.subject] = true
321
371
  end
322
372
 
323
373
  # Return the number of times this node has been referenced in the object position
@@ -328,22 +378,51 @@ module RDF::RDFXML
328
378
  # Return a QName for the URI, or nil. Adds namespace of QName to defined namespaces
329
379
  def get_qname(uri)
330
380
  if uri.is_a?(RDF::URI)
331
- qn = @graph.qname(uri)
332
- # Local parts with . will mess up serialization
333
- return false if qn.nil? || qn.index('.')
381
+ # Duplicate logic from URI#qname to remember namespace assigned
382
+ if uri.qname
383
+ add_namespace(uri.qname.first, uri.vocab)
384
+ add_debug "get_qname(uri.qname): #{uri.qname.join(':')}"
385
+ return uri.qname.join(":")
386
+ end
334
387
 
335
- add_namespace(uri.namespace)
336
- qn
388
+ # No vocabulary assigned, find one from cache of created namespace URIs
389
+ @namespaces.each_pair do |prefix, vocab|
390
+ if uri.to_s.index(vocab.to_s) == 0
391
+ uri.vocab = vocab
392
+ local_name = uri.to_s[(vocab.to_s.length)..-1]
393
+ add_debug "get_qname(ns): #{prefix}:#{local_name}"
394
+ return "#{prefix}:#{local_name}"
395
+ end
396
+ end
397
+
398
+ # No vocabulary found, invent one
399
+ # Add bindings for predicates not already having bindings
400
+ # short_name of URI for creating QNames.
401
+ # "#{base_uri]{#short_name}}" == uri
402
+ local_name = uri.fragment
403
+ local_name ||= begin
404
+ path = uri.path.split("/")
405
+ unless path &&
406
+ path.length > 1 &&
407
+ path.last.class == String &&
408
+ path.last.length > 0 &&
409
+ path.last.index("/") != 0
410
+ return false
411
+ end
412
+ path.last
413
+ end
414
+ base_uri = uri.to_s[0..-(local_name.length + 1)]
415
+ @tmp_ns = @tmp_ns ? @tmp_ns.succ : "ns0"
416
+ add_debug "create namespace definition for #{uri}"
417
+ uri.vocab = RDF::Vocabulary.new(base_uri)
418
+ add_namespace(@tmp_ns.to_sym, uri.vocab)
419
+ add_debug "get_qname(tmp_ns): #{@tmp_ns}:#{local_name}"
420
+ return "#{@tmp_ns}:#{local_name}"
337
421
  end
338
422
  end
339
423
 
340
- def add_namespace(ns)
341
- @namespaces[ns.prefix.to_s] = ns
342
- end
343
-
344
- # URI -> Namespace bindings (similar to graph) for looking up qnames
345
- def uri_binding
346
- @uri_binding ||= @namespaces.values.inject({}) {|hash, ns| hash[ns.uri.to_s] = ns; hash}
424
+ def add_namespace(prefix, ns)
425
+ @namespaces[prefix.to_sym] = ns.to_s
347
426
  end
348
427
 
349
428
  def reset
@@ -361,8 +440,8 @@ module RDF::RDFXML
361
440
  def sort_properties(properties)
362
441
  properties.keys.each do |k|
363
442
  properties[k] = properties[k].sort do |a, b|
364
- a_li = a.is_a?(RDF::URI) && a.short_name =~ /^_\d+$/ ? a.to_i : a.to_s
365
- b_li = b.is_a?(RDF::URI) && b.short_name =~ /^_\d+$/ ? b.to_i : b.to_s
443
+ a_li = a.is_a?(RDF::URI) && a.qname.last =~ /^_\d+$/ ? a.to_i : a.to_s
444
+ b_li = b.is_a?(RDF::URI) && b.qname.last =~ /^_\d+$/ ? b.to_i : b.to_s
366
445
 
367
446
  a_li <=> b_li
368
447
  end
@@ -381,19 +460,41 @@ module RDF::RDFXML
381
460
  prop_list << prop.to_s
382
461
  end
383
462
 
384
- puts "sort_properties: #{prop_list.to_sentence}" if $DEBUG
463
+ add_debug "sort_properties: #{prop_list.to_sentence}"
385
464
  prop_list
386
465
  end
387
466
 
388
- # Returns indent string multiplied by the depth
389
- def indent(modifier = 0)
390
- INDENT_STRING * (@depth + modifier)
467
+ # XML content and arguments for serialization
468
+ # Encoding.the_null_encoding.xml_args("foo", "en-US") => ["foo", {"xml:lang" => "en-US"}]
469
+ def xml_args(object)
470
+ case object
471
+ when RDF::Literal
472
+ if object.plain?
473
+ [object.value, {}]
474
+ elsif object.has_language?
475
+ [object.value, {"xml:lang" => object.language}]
476
+ elsif object.xmlliteral?
477
+ [object.value, {"rdf:parseType" => "Literal"}]
478
+ else
479
+ [object.value, {"rdf:datatype" => object.datatype.to_s}]
480
+ end
481
+ when RDF::Node
482
+ [{"rdf:nodeID" => object.id}]
483
+ when RDF::URI
484
+ [{"rdf:resource" => object.to_s}]
485
+ end
391
486
  end
392
487
 
393
- # Write text
394
- def write(text)
395
- @stream.write(text)
488
+ # Add debug event to debug array, if specified
489
+ #
490
+ # @param [String] message::
491
+ def add_debug(message)
492
+ @debug << message if @debug.is_a?(Array)
396
493
  end
397
494
 
495
+ # Returns indent string multiplied by the depth
496
+ def indent(modifier = 0)
497
+ INDENT_STRING * (@depth + modifier)
498
+ end
398
499
  end
399
500
  end
data/lib/rdf/rdfxml.rb CHANGED
@@ -23,8 +23,11 @@ module RDF
23
23
  require 'rdf/rdfxml/format'
24
24
  require 'rdf/rdfxml/vocab'
25
25
  require 'rdf/rdfxml/patches/array_hacks'
26
+ require 'rdf/rdfxml/patches/literal_hacks'
26
27
  require 'rdf/rdfxml/patches/nokogiri_hacks'
28
+ require 'rdf/rdfxml/patches/qname_hacks'
27
29
  require 'rdf/rdfxml/patches/rdf_escape'
30
+ require 'rdf/rdfxml/patches/uri_hacks'
28
31
  autoload :Reader, 'rdf/rdfxml/reader'
29
32
  autoload :Writer, 'rdf/rdfxml/writer'
30
33
  autoload :VERSION, 'rdf/rdfxml/version'
@@ -32,5 +35,6 @@ module RDF
32
35
 
33
36
  # Fixme: RDF.to_s should generate this, but it doesn't
34
37
  RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
38
+ XML_LITERAL = RDF['XMLLiteral']
35
39
  end
36
40
  end
data/rdf-rdfxml.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rdf-rdfxml}
8
- s.version = "0.0.2"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Gregg Kellogg"]
12
- s.date = %q{2010-06-07}
12
+ s.date = %q{2010-06-12}
13
13
  s.description = %q{ RDF::RDFXML is an RDF/XML reader and writer for Ruby using the RDF.rb library suite.
14
14
  }
15
15
  s.email = %q{gregg@kellogg-assoc.com}
@@ -31,8 +31,13 @@ Gem::Specification.new do |s|
31
31
  "lib/rdf/rdfxml.rb",
32
32
  "lib/rdf/rdfxml/format.rb",
33
33
  "lib/rdf/rdfxml/patches/array_hacks.rb",
34
+ "lib/rdf/rdfxml/patches/graph_properties.rb",
35
+ "lib/rdf/rdfxml/patches/literal_hacks.rb",
34
36
  "lib/rdf/rdfxml/patches/nokogiri_hacks.rb",
37
+ "lib/rdf/rdfxml/patches/qname_hacks.rb",
35
38
  "lib/rdf/rdfxml/patches/rdf_escape.rb",
39
+ "lib/rdf/rdfxml/patches/seq.rb",
40
+ "lib/rdf/rdfxml/patches/uri_hacks.rb",
36
41
  "lib/rdf/rdfxml/reader.rb",
37
42
  "lib/rdf/rdfxml/version.rb",
38
43
  "lib/rdf/rdfxml/vocab.rb",
@@ -40,7 +45,10 @@ Gem::Specification.new do |s|
40
45
  "rdf-rdfxml.gemspec",
41
46
  "script/console",
42
47
  "spec/format_spec.rb",
48
+ "spec/graph_spec.rb",
49
+ "spec/literal_spec.rb",
43
50
  "spec/matchers.rb",
51
+ "spec/rdf_escape_spec.rb",
44
52
  "spec/rdf_helper.rb",
45
53
  "spec/rdf_tests/cc197bad-dc9c-440d-a5b5-d52ba2e14234.nt",
46
54
  "spec/rdf_tests/cc197bad-dc9c-440d-a5b5-d52ba2e14234.rdf",
@@ -404,7 +412,8 @@ Gem::Specification.new do |s|
404
412
  "spec/reader_spec.rb",
405
413
  "spec/spec.opts",
406
414
  "spec/spec_helper.rb",
407
- "spec/xml_serializer_spec.rb"
415
+ "spec/uri_spec.rb",
416
+ "spec/writer_spec.rb"
408
417
  ]
409
418
  s.homepage = %q{http://github.com/gkellogg/rdf-rdfxml}
410
419
  s.rdoc_options = ["--charset=UTF-8"]
@@ -413,11 +422,15 @@ Gem::Specification.new do |s|
413
422
  s.summary = %q{RDF/XML reader/writer for RDF.rb.}
414
423
  s.test_files = [
415
424
  "spec/format_spec.rb",
425
+ "spec/graph_spec.rb",
426
+ "spec/literal_spec.rb",
416
427
  "spec/matchers.rb",
428
+ "spec/rdf_escape_spec.rb",
417
429
  "spec/rdf_helper.rb",
418
430
  "spec/reader_spec.rb",
419
431
  "spec/spec_helper.rb",
420
- "spec/xml_serializer_spec.rb"
432
+ "spec/uri_spec.rb",
433
+ "spec/writer_spec.rb"
421
434
  ]
422
435
 
423
436
  if s.respond_to? :specification_version then
data/spec/format_spec.rb CHANGED
@@ -4,7 +4,7 @@ describe RDF::RDFXML::Format do
4
4
  context "descovery" do
5
5
  {
6
6
  "rdf" => RDF::Format.for(:rdf),
7
- "xml" => RDF::Format.for(:xml),
7
+ "rdfxml" => RDF::Format.for(:rdfxml),
8
8
  "etc/foaf.xml" => RDF::Format.for("etc/foaf.xml"),
9
9
  "etc/foaf.rdf" => RDF::Format.for("etc/foaf.rdf"),
10
10
  "foaf.xml" => RDF::Format.for(:file_name => "foaf.xml"),