the-experimenters-rdf-rdfxml 0.3.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.
@@ -0,0 +1,18 @@
1
+ module RDF::RDFXML::VERSION
2
+ VERSION_FILE = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..", "..", "VERSION")
3
+ MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chop.split(".")
4
+
5
+ STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
6
+
7
+ ##
8
+ # @return [String]
9
+ def self.to_s() STRING end
10
+
11
+ ##
12
+ # @return [String]
13
+ def self.to_str() STRING end
14
+
15
+ ##
16
+ # @return [Array(Integer, Integer, Integer)]
17
+ def self.to_a() STRING.split(".") end
18
+ end
@@ -0,0 +1,3 @@
1
+ module RDF
2
+ class XML < Vocabulary("http://www.w3.org/XML/1998/namespace"); end
3
+ end
@@ -0,0 +1,559 @@
1
+ require 'nokogiri' # FIXME: Implement using different modules as in RDF::TriX
2
+ require 'rdf/rdfxml/patches/graph_properties'
3
+
4
+ module RDF::RDFXML
5
+ ##
6
+ # An RDF/XML serialiser in Ruby
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
+ # The writer will add prefix definitions, and use them for creating @prefix definitions, and minting QNames
13
+ #
14
+ # @example Obtaining a RDF/XML writer class
15
+ # RDF::Writer.for(:rdf) #=> RDF::RDFXML::Writer
16
+ # RDF::Writer.for("etc/test.rdf")
17
+ # RDF::Writer.for(:file_name => "etc/test.rdf")
18
+ # RDF::Writer.for(:file_extension => "rdf")
19
+ # RDF::Writer.for(:content_type => "application/rdf+xml")
20
+ #
21
+ # @example Serializing RDF graph into an RDF/XML file
22
+ # RDF::RDFXML::Write.open("etc/test.rdf") do |writer|
23
+ # writer << graph
24
+ # end
25
+ #
26
+ # @example Serializing RDF statements into an RDF/XML file
27
+ # RDF::RDFXML::Writer.open("etc/test.rdf") do |writer|
28
+ # graph.each_statement do |statement|
29
+ # writer << statement
30
+ # end
31
+ # end
32
+ #
33
+ # @example Serializing RDF statements into an RDF/XML string
34
+ # RDF::RDFXML::Writer.buffer do |writer|
35
+ # graph.each_statement do |statement|
36
+ # writer << statement
37
+ # end
38
+ # end
39
+ #
40
+ # @example Creating @base and @prefix definitions in output
41
+ # RDF::RDFXML::Writer.buffer(:base_uri => "http://example.com/", :prefixes => {
42
+ # nil => "http://example.com/ns#",
43
+ # :foaf => "http://xmlns.com/foaf/0.1/"}
44
+ # ) do |writer|
45
+ # graph.each_statement do |statement|
46
+ # writer << statement
47
+ # end
48
+ # end
49
+ #
50
+ # @author [Gregg Kellogg](http://kellogg-assoc.com/)
51
+ class Writer < RDF::Writer
52
+ format RDF::RDFXML::Format
53
+
54
+ VALID_ATTRIBUTES = [:none, :untyped, :typed]
55
+
56
+ # @return [Graph] Graph of statements serialized
57
+ attr_accessor :graph
58
+ # @return [URI] Base URI used for relativizing URIs
59
+ attr_accessor :base_uri
60
+
61
+ ##
62
+ # Initializes the RDF/XML writer instance.
63
+ #
64
+ # @param [IO, File] output
65
+ # the output stream
66
+ # @param [Hash{Symbol => Object}] options
67
+ # any additional options
68
+ # @option options [Boolean] :canonicalize (false)
69
+ # whether to canonicalize literals when serializing
70
+ # @option options [Hash] :prefixes (Hash.new)
71
+ # the prefix mappings to use (not supported by all writers)
72
+ # @option options [#to_s] :base_uri (nil)
73
+ # the base URI to use when constructing relative URIs
74
+ # @option options [Integer] :max_depth (3)
75
+ # Maximum depth for recursively defining resources
76
+ # @option options [#to_s] :lang (nil)
77
+ # Output as root xml:lang attribute, and avoid generation _xml:lang_ where possible
78
+ # @option options [Array] :attributes (nil)
79
+ # How to use XML attributes when serializing, one of :none, :untyped, :typed. The default is :none.
80
+ # @option options [Boolean] :standard_prefixes (false)
81
+ # Add standard prefixes to _prefixes_, if necessary.
82
+ # @option options [String] :default_namespace (nil)
83
+ # URI to use as default namespace, same as prefix(nil)
84
+ # @yield [writer]
85
+ # @yieldparam [RDF::Writer] writer
86
+ def initialize(output = $stdout, options = {}, &block)
87
+ super do
88
+ @graph = RDF::Graph.new
89
+ @uri_to_qname = {}
90
+ @uri_to_prefix = {}
91
+ block.call(self) if block_given?
92
+ end
93
+ end
94
+
95
+ ##
96
+ # Write whole graph
97
+ #
98
+ # @param [Graph] graph
99
+ # @return [void]
100
+ def write_graph(graph)
101
+ @graph = graph
102
+ end
103
+
104
+ ##
105
+ # Addes a statement to be serialized
106
+ # @param [RDF::Statement] statement
107
+ # @return [void]
108
+ def write_statement(statement)
109
+ @graph.insert(statement)
110
+ end
111
+
112
+ ##
113
+ # Addes a triple to be serialized
114
+ # @param [RDF::Resource] subject
115
+ # @param [RDF::URI] predicate
116
+ # @param [RDF::Value] object
117
+ # @return [void]
118
+ # @abstract
119
+ def write_triple(subject, predicate, object)
120
+ @graph.insert(Statement.new(subject, predicate, object))
121
+ end
122
+
123
+ ##
124
+ # Outputs the RDF/XML representation of all stored triples.
125
+ #
126
+ # @return [void]
127
+ # @raise [RDF::WriterError] when attempting to write non-conformant graph
128
+ # @see #write_triple
129
+ def write_epilogue
130
+ @force_RDF_about = {}
131
+ @max_depth = @options[:max_depth] || 3
132
+ @base_uri = @options[:base_uri]
133
+ @lang = @options[:lang]
134
+ @attributes = @options[:attributes] || :none
135
+ @debug = @options[:debug]
136
+ raise RDF::WriterError, "Invalid attribute option '#{@attributes}', should be one of #{VALID_ATTRIBUTES.to_sentence}" unless VALID_ATTRIBUTES.include?(@attributes.to_sym)
137
+ self.reset
138
+
139
+ doc = Nokogiri::XML::Document.new
140
+
141
+ add_debug "\nserialize: graph of size #{@graph.size}"
142
+ add_debug "options: #{@options.inspect}"
143
+
144
+ preprocess
145
+
146
+ prefix(:rdf, RDF.to_uri)
147
+ prefix(:xml, RDF::XML) if @base_uri || @lang
148
+
149
+ add_debug "\nserialize: graph namespaces: #{prefixes.inspect}"
150
+
151
+ doc.root = Nokogiri::XML::Element.new("rdf:RDF", doc)
152
+ doc.root["xml:lang"] = @lang if @lang
153
+ doc.root["xml:base"] = @base_uri if @base_uri
154
+
155
+ # Add statements for each subject
156
+ order_subjects.each do |subject|
157
+ #add_debug "subj: #{subject.inspect}"
158
+ subject(subject, doc.root)
159
+ end
160
+
161
+ prefixes.each_pair do |p, uri|
162
+ if p == nil
163
+ doc.root.default_namespace = uri.to_s
164
+ else
165
+ doc.root.add_namespace(p.to_s, uri.to_s)
166
+ end
167
+ end
168
+
169
+ add_debug "doc:\n #{doc.to_xml(:encoding => "UTF-8", :indent => 2)}"
170
+ doc.write_xml_to(@output, :encoding => "UTF-8", :indent => 2)
171
+ end
172
+
173
+ # Return a QName for the URI, or nil. Adds namespace of QName to defined prefixes
174
+ # @param [URI,#to_s] resource
175
+ # @param [Hash<Symbol => Object>] options
176
+ # @option [Boolean] :with_default (false) If a default mapping exists, use it, otherwise if a prefixed mapping exists, use it
177
+ # @return [String, nil] value to use to identify URI
178
+ def get_qname(resource, options = {})
179
+ case resource
180
+ when RDF::Node
181
+ add_debug "qname(#{resource.inspect}): #{resource}"
182
+ return resource.to_s
183
+ when RDF::URI
184
+ uri = resource.to_s
185
+ else
186
+ add_debug "qname(#{resource.inspect}): nil"
187
+ return nil
188
+ end
189
+
190
+ qname = case
191
+ when options[:with_default] && prefix(nil) && uri.index(prefix(nil)) == 0
192
+ # Don't cache
193
+ add_debug "qname(#{resource.inspect}): #{uri.sub(prefix(nil), '').inspect} (default)"
194
+ return uri.sub(prefix(nil), '')
195
+ when @uri_to_qname.has_key?(uri)
196
+ add_debug "qname(#{resource.inspect}): #{@uri_to_qname[uri].inspect} (cached)"
197
+ return @uri_to_qname[uri]
198
+ when u = @uri_to_prefix.keys.detect {|u| uri.index(u.to_s) == 0 && NC_REGEXP.match(uri[u.to_s.length..-1])}
199
+ # Use a defined prefix
200
+ prefix = @uri_to_prefix[u]
201
+ prefix(prefix, u) # Define for output
202
+ uri.sub(u.to_s, "#{prefix}:")
203
+ when @options[:standard_prefixes] && vocab = RDF::Vocabulary.detect {|v| uri.index(v.to_uri.to_s) == 0 && NC_REGEXP.match(uri[v.to_uri.to_s.length..-1])}
204
+ prefix = vocab.__name__.to_s.split('::').last.downcase
205
+ @uri_to_prefix[vocab.to_uri.to_s] = prefix
206
+ prefix(prefix, vocab.to_uri) # Define for output
207
+ uri.sub(vocab.to_uri.to_s, "#{prefix}:")
208
+ else
209
+
210
+ # No vocabulary found, invent one
211
+ # Add bindings for predicates not already having bindings
212
+ # From RDF/XML Syntax and Processing:
213
+ # An XML namespace-qualified name (QName) has restrictions on the legal characters such that not all
214
+ # property URIs can be expressed as these names. It is recommended that implementors of RDF serializers,
215
+ # in order to break a URI into a namespace name and a local name, split it after the last XML non-NCName
216
+ # character, ensuring that the first character of the name is a Letter or '_'. If the URI ends in a
217
+ # non-NCName character then throw a "this graph cannot be serialized in RDF/XML" exception or error.
218
+ separation = uri.rindex(%r{[^a-zA-Z_0-9-][a-zA-Z_][a-z0-9A-Z_-]*$})
219
+ return @uri_to_qname[uri] = nil unless separation
220
+ base_uri = uri.to_s[0..separation]
221
+ suffix = uri.to_s[separation+1..-1]
222
+ @gen_prefix = @gen_prefix ? @gen_prefix.succ : "ns0"
223
+ @uri_to_prefix[base_uri] = @gen_prefix
224
+ prefix(@gen_prefix, base_uri)
225
+ "#{@gen_prefix}:#{suffix}"
226
+ end
227
+
228
+ add_debug "qname(#{resource.inspect}): #{qname.inspect}"
229
+ @uri_to_qname[uri] = qname
230
+ rescue Addressable::URI::InvalidURIError => e
231
+ raise RDF::WriterError, "Invalid URI #{uri.inspect}: #{e.message}"
232
+ end
233
+
234
+ protected
235
+ # If @base_uri is defined, use it to try to make uri relative
236
+ # @param [#to_s] uri
237
+ # @return [String]
238
+ def relativize(uri)
239
+ uri = uri.to_s
240
+ @base_uri ? uri.sub(@base_uri.to_s, "") : uri
241
+ end
242
+
243
+ # Defines rdf:type of subjects to be emitted at the beginning of the graph. Defaults to none
244
+ # @return [Array<URI>]
245
+ def top_classes; []; end
246
+
247
+ # Defines order of predicates to to emit at begninning of a resource description. Defaults to
248
+ # [rdf:type, rdfs:label, dc:title]
249
+ # @return [Array<URI>]
250
+ def predicate_order; [RDF.type, RDF::RDFS.label, RDF::DC.title]; end
251
+
252
+ # Order subjects for output. Override this to output subjects in another order.
253
+ #
254
+ # Uses top_classes
255
+ # @return [Array<Resource>] Ordered list of subjects
256
+ def order_subjects
257
+ seen = {}
258
+ subjects = []
259
+
260
+ top_classes.each do |class_uri|
261
+ graph.query(:predicate => RDF.type, :object => class_uri).map {|st| st.subject}.sort.uniq.each do |subject|
262
+ #add_debug "order_subjects: #{subject.inspect}"
263
+ subjects << subject
264
+ seen[subject] = @top_levels[subject] = true
265
+ end
266
+ end
267
+
268
+ # Sort subjects by resources over bnodes, ref_counts and the subject URI itself
269
+ recursable = @subjects.keys.
270
+ select {|s| !seen.include?(s)}.
271
+ map {|r| [(r.is_a?(RDF::Node) ? 1 : 0) + ref_count(r), r]}.
272
+ sort_by {|l| l.first }
273
+
274
+ subjects += recursable.map{|r| r.last}
275
+ end
276
+
277
+ # Perform any preprocessing of statements required
278
+ def preprocess
279
+ default_namespace = @options[:default_namespace] || prefix(nil)
280
+
281
+ # Load defined prefixes
282
+ (@options[:prefixes] || {}).each_pair do |k, v|
283
+ @uri_to_prefix[v.to_s] = k
284
+ end
285
+ @options[:prefixes] = {} # Will define actual used when matched
286
+
287
+ if default_namespace
288
+ add_debug("preprocess: default_namespace: #{default_namespace}")
289
+ prefix(nil, default_namespace)
290
+ end
291
+
292
+ @graph.each {|statement| preprocess_statement(statement)}
293
+ end
294
+
295
+ # Perform any statement preprocessing required. This is used to perform reference counts and determine required
296
+ # prefixes.
297
+ # @param [Statement] statement
298
+ def preprocess_statement(statement)
299
+ #add_debug "preprocess: #{statement.inspect}"
300
+ references = ref_count(statement.object) + 1
301
+ @references[statement.object] = references
302
+ @subjects[statement.subject] = true
303
+ end
304
+
305
+ # Returns indent string multiplied by the depth
306
+ # @param [Integer] modifier Increase depth by specified amount
307
+ # @return [String] A number of spaces, depending on current depth
308
+ def indent(modifier = 0)
309
+ " " * (@depth + modifier)
310
+ end
311
+
312
+ def reset
313
+ @depth = 0
314
+ @lists = {}
315
+ prefixes = {}
316
+ @references = {}
317
+ @serialized = {}
318
+ @subjects = {}
319
+ @top_levels = {}
320
+ end
321
+
322
+ private
323
+ def subject(subject, parent_node)
324
+ node = nil
325
+
326
+ raise RDF::WriterError, "Illegal use of subject #{subject.inspect}, not supported in RDF/XML" unless subject.resource?
327
+
328
+ if !is_done?(subject)
329
+ subject_done(subject)
330
+ properties = @graph.properties(subject)
331
+ add_debug "subject: #{subject.inspect}, props: #{properties.inspect}"
332
+
333
+ @graph.query(:subject => subject).each do |st|
334
+ raise RDF::WriterError, "Illegal use of predicate #{st.predicate.inspect}, not supported in RDF/XML" unless st.predicate.uri?
335
+ end
336
+
337
+ rdf_type, *rest = properties.fetch(RDF.type.to_s, [])
338
+ qname = get_qname(rdf_type, :with_default => true)
339
+ if rdf_type.is_a?(RDF::Node)
340
+ # Must serialize with an element
341
+ qname = rdf_type = nil
342
+ elsif rest.empty?
343
+ properties.delete(RDF.type.to_s)
344
+ else
345
+ properties[RDF.type.to_s] = [rest].flatten.compact
346
+ end
347
+ prop_list = order_properties(properties)
348
+ add_debug "=> property order: #{prop_list.to_sentence}"
349
+
350
+ if qname
351
+ rdf_type = nil
352
+ else
353
+ qname = "rdf:Description"
354
+ prefixes[:rdf] = RDF.to_uri
355
+ end
356
+
357
+ node = Nokogiri::XML::Element.new(qname, parent_node.document)
358
+
359
+ node["rdf:type"] = rdf_type if rdf_type
360
+
361
+ if subject.is_a?(RDF::Node)
362
+ # Only need nodeID if it's referenced elsewhere
363
+ if ref_count(subject) > (@depth == 0 ? 0 : 1)
364
+ node["rdf:nodeID"] = subject.id
365
+ else
366
+ node.add_child(Nokogiri::XML::Comment.new(node.document, "Serialization for #{subject}")) if RDF::RDFXML::debug?
367
+ end
368
+ else
369
+ node["rdf:about"] = relativize(subject)
370
+ end
371
+
372
+ prop_list.each do |prop|
373
+ prop_ref = RDF::URI.intern(prop)
374
+
375
+ properties[prop].each do |object|
376
+ raise RDF::WriterError, "Illegal use of object #{object.inspect}, not supported in RDF/XML" unless object.resource? || object.literal?
377
+
378
+ @depth += 1
379
+ predicate(prop_ref, object, node, properties[prop].length == 1)
380
+ @depth -= 1
381
+ end
382
+ end
383
+ elsif @force_RDF_about.include?(subject)
384
+ add_debug "subject: #{subject.inspect}, force about"
385
+ node = Nokogiri::XML::Element.new("rdf:Description", parent_node.document)
386
+ if subject.is_a?(RDF::Node)
387
+ node["rdf:nodeID"] = subject.id
388
+ else
389
+ node["rdf:about"] = relativize(subject)
390
+ end
391
+ end
392
+ @force_RDF_about.delete(subject)
393
+
394
+ parent_node.add_child(node) if node
395
+ end
396
+
397
+ # Output a predicate into the specified node.
398
+ #
399
+ # If _is_unique_ is true, this predicate may be able to be serialized as an attribute
400
+ def predicate(prop, object, node, is_unique)
401
+ as_attr = predicate_as_attribute?(prop, object) && is_unique
402
+
403
+ qname = get_qname(prop, :with_default => !as_attr)
404
+ raise RDF::WriterError, "No qname generated for <#{prop}>" unless qname
405
+
406
+ add_debug "predicate: #{qname}, as_attr: #{as_attr}, object: #{object.inspect}, done: #{is_done?(object)}, subject: #{@subjects.include?(object)}"
407
+ #qname = "rdf:li" if qname.match(/rdf:_\d+/)
408
+ pred_node = Nokogiri::XML::Element.new(qname, node.document)
409
+
410
+ o_props = @graph.properties(object)
411
+
412
+ col = RDF::List.new(object, @graph).to_a
413
+ conformant_list = col.all? {|item| !item.literal?} && o_props[RDF.first.to_s]
414
+ args = xml_args(object)
415
+ attrs = args.pop
416
+
417
+ # Check to see if it can be serialized as a collection
418
+ if conformant_list
419
+ add_debug("=> as collection: [#{col.map(&:to_s).join(", ")}]")
420
+ # Serialize list as parseType="Collection"
421
+ pred_node.add_child(Nokogiri::XML::Comment.new(node.document, "Serialization for #{object}")) if RDF::RDFXML::debug?
422
+ pred_node["rdf:parseType"] = "Collection"
423
+ while o_props[RDF.first.to_s]
424
+ # Object is used only for referencing collection item and next
425
+ subject_done(object)
426
+ item = o_props[RDF.first.to_s].first
427
+ object = o_props[RDF.rest.to_s].first
428
+ o_props = @graph.properties(object)
429
+ add_debug("=> li first: #{item}, rest: #{object}")
430
+ @force_RDF_about[item] = true
431
+ subject(item, pred_node)
432
+ end
433
+ elsif as_attr
434
+ # Serialize as attribute
435
+ pred_node.unlink
436
+ pred_node = nil
437
+ node[qname] = object.is_a?(RDF::URI) ? relativize(object) : object.value
438
+ add_debug("=> as attribute: node[#{qname}]=#{node[qname]}, #{object.class}")
439
+ elsif object.literal?
440
+ # Serialize as element
441
+ add_debug("predicate as element: #{attrs.inspect}")
442
+ attrs.each_pair do |a, av|
443
+ next if a.to_s == "xml:lang" && av.to_s == @lang # Lang already specified, don't repeat
444
+ add_debug "=> elt attr #{a}=#{av}"
445
+ pred_node[a] = av.to_s
446
+ end
447
+ add_debug "=> elt #{'xmllit ' if object.literal? && object.datatype == RDF.XMLLiteral}content=#{args.first}" if !args.empty?
448
+ if object.datatype == RDF.XMLLiteral
449
+ pred_node.inner_html = args.first.to_s
450
+ elsif args.first
451
+ pred_node.content = args.first
452
+ end
453
+ elsif @depth < @max_depth && !is_done?(object) && @subjects.include?(object)
454
+ add_debug(" as element (recurse)")
455
+ @depth += 1
456
+ subject(object, pred_node)
457
+ @depth -= 1
458
+ elsif object.is_a?(RDF::Node)
459
+ add_debug("=> as element (nodeID)")
460
+ pred_node["rdf:nodeID"] = object.id
461
+ else
462
+ add_debug("=> as element (resource)")
463
+ pred_node["rdf:resource"] = relativize(object)
464
+ end
465
+
466
+ node.add_child(pred_node) if pred_node
467
+ end
468
+
469
+ # Mark a subject as done.
470
+ def subject_done(subject)
471
+ add_debug("subject_done: #{subject}")
472
+ @serialized[subject] = true
473
+ end
474
+
475
+ # Return the number of times this node has been referenced in the object position
476
+ def ref_count(node)
477
+ @references.fetch(node, 0)
478
+ end
479
+
480
+ def is_done?(subject)
481
+ #add_debug("is_done?(#{subject}): #{@serialized.include?(subject)}")
482
+ @serialized.include?(subject)
483
+ end
484
+
485
+ # See if we can serialize as attribute.
486
+ # * untyped attributes that aren't duplicated where xml:lang == @lang
487
+ # * typed attributes that aren't duplicated if @dt_as_attr is true
488
+ # * rdf:type
489
+ def predicate_as_attribute?(prop, object)
490
+ [:untyped, :typed].include?(@attributes) && (
491
+ prop == RDF.type ||
492
+ [:typed].include?(@attributes) && object.literal? && object.typed? ||
493
+ (object.literal? && object.plain? || @lang && object.language.to_s == @lang.to_s)
494
+ )
495
+ end
496
+
497
+ # Take a hash from predicate uris to lists of values.
498
+ # Sort the lists of values. Return a sorted list of properties.
499
+ # @param [Hash{String => Array<Resource>}] properties A hash of Property to Resource mappings
500
+ # @return [Array<String>}] Ordered list of properties. Uses predicate_order.
501
+ def order_properties(properties)
502
+ properties.keys.each do |k|
503
+ properties[k] = properties[k].sort do |a, b|
504
+ a_li = a.is_a?(RDF::URI) && get_qname(a) && get_qname(a).to_s =~ /:_\d+$/ ? a.to_i : a.to_s
505
+ b_li = b.is_a?(RDF::URI) && get_qname(b) && get_qname(b).to_s =~ /:_\d+$/ ? b.to_i : b.to_s
506
+
507
+ a_li <=> b_li
508
+ end
509
+ end
510
+
511
+ # Make sorted list of properties
512
+ prop_list = []
513
+
514
+ predicate_order.each do |prop|
515
+ next unless properties[prop]
516
+ prop_list << prop.to_s
517
+ end
518
+
519
+ properties.keys.sort.each do |prop|
520
+ next if prop_list.include?(prop.to_s)
521
+ prop_list << prop.to_s
522
+ end
523
+
524
+ prop_list
525
+ end
526
+
527
+ # XML content and arguments for serialization
528
+ # Encoding.the_null_encoding.xml_args("foo", "en-US") => ["foo", {"xml:lang" => "en-US"}]
529
+ def xml_args(object)
530
+ case object
531
+ when RDF::Literal
532
+ if object.plain?
533
+ [object.value, {}]
534
+ elsif object.has_language?
535
+ [object.value, {"xml:lang" => object.language}]
536
+ elsif object.datatype == RDF.XMLLiteral
537
+ [object.value, {"rdf:parseType" => "Literal"}]
538
+ else
539
+ [object.value, {"rdf:datatype" => object.datatype.to_s}]
540
+ end
541
+ when RDF::Node
542
+ [{"rdf:nodeID" => object.id}]
543
+ when RDF::URI
544
+ [{"rdf:resource" => object.to_s}]
545
+ else
546
+ raise RDF::WriterError, "Attempt to serialize #{object.inspect}, not supported in RDF/XML"
547
+ end
548
+ end
549
+
550
+ # Add debug event to debug array, if specified
551
+ #
552
+ # @param [String] message::
553
+ def add_debug(message)
554
+ msg = "#{indent}#{message}"
555
+ STDERR.puts msg if ::RDF::RDFXML.debug?
556
+ @debug << msg if @debug.is_a?(Array)
557
+ end
558
+ end
559
+ end