rdf-rdfxml 0.0.2 → 0.0.3

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.
@@ -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"),