Module: Sequel::Plugins::XmlSerializer::InstanceMethods

Defined in:
lib/sequel/plugins/xml_serializer.rb

Instance Method Summary collapse

Instance Method Details

#from_xml(xml, opts = {}) ⇒ Object

Update the contents of this instance based on the given XML. Accepts the following options:

:name_proc

Proc or Hash that accepts a string and returns a string, used to convert tag names to column or association names.

:underscore

Sets the :name_proc option to one that calls underscore on the input string. Requires that you load the inflector extension or another library that adds String#underscore.



219
220
221
222
223
224
# File 'lib/sequel/plugins/xml_serializer.rb', line 219

def from_xml(xml, opts={})
  if opts[:all_associations] || opts[:all_columns]
    Sequel::Deprecation.deprecate("The from_xml :all_associations and :all_columns", 'You need to explicitly specify the associations and columns via the :associations and :fields options')
  end
  from_xml_node(Nokogiri::XML(xml).children.first, opts)
end

#from_xml_node(parent, opts = {}) ⇒ Object

Update the contents of this instance based on the given XML node, which should be a Nokogiri::XML::Node instance. By default, just calls set with a hash created from the content of the node.

Options:

:all_associations

Indicates that all associations supported by the model should be tried. This option also cascades to associations if used. It is better to use the :associations option instead of this option. This option only exists for backwards compatibility.

:all_columns

Overrides the setting logic allowing all setter methods be used, even if access to the setter method is restricted. This option cascades to associations if used, and can be reset in those associations using the :all_columns=>false or :fields options. This option is considered a security risk, and only exists for backwards compatibility. It is better to use the :fields option appropriately instead of this option, or no option at all.

:associations

Indicates that the associations cache should be updated by creating a new associated object using data from the hash. Should be a Symbol for a single association, an array of symbols for multiple associations, or a hash with symbol keys and dependent association option hash values.

:fields

Changes the behavior to call set_fields using the provided fields, instead of calling set.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/sequel/plugins/xml_serializer.rb', line 246

def from_xml_node(parent, opts={})
  unless parent
    raise Error, "Malformed XML used"
  end
  if !parent.children.empty? && parent.children.all?{|node| node.is_a?(Nokogiri::XML::Text)}
    raise Error, "XML consisting of just text nodes used"
  end

  unless assocs = opts[:associations]
    if opts[:all_associations]
      assocs = {}
      model.associations.each{|v| assocs[v] = {:all_associations=>true}}
    end
  end

  if assocs
    assocs = case assocs
    when Symbol
      {assocs=>{}}
    when Array
      assocs_tmp = {}
      assocs.each{|v| assocs_tmp[v] = {}}
      assocs_tmp
    when Hash
      assocs
    else
      raise Error, ":associations should be Symbol, Array, or Hash if present"
    end

    if opts[:all_columns]
      assocs.each_value do |assoc_opts|
        assoc_opts[:all_columns] = true unless assoc_opts.has_key?(:fields) || assoc_opts.has_key?(:all_columns)
      end
    end

    assocs_hash = {}
    assocs.each{|k,v| assocs_hash[k.to_s] = v}
    assocs_present = []
  end

  hash = {}
  name_proc = model.xml_deserialize_name_proc(opts)
  parent.children.each do |node|
    next if node.is_a?(Nokogiri::XML::Text)
    k = name_proc[node.name]
    if assocs_hash && assocs_hash[k]
      assocs_present << [k.to_sym, node]
    else
      hash[k] = node.key?('nil') ? nil : node.children.first.to_s
    end
  end

  if assocs_present
    assocs_present.each do |assoc, node|
      assoc_opts = assocs[assoc]

      unless r = model.association_reflection(assoc)
        raise Error, "Association #{assoc} is not defined for #{model}"
      end

      associations[assoc] = if r.returns_array?
        node.children.reject{|c| c.is_a?(Nokogiri::XML::Text)}.map{|c| r.associated_class.from_xml_node(c, assoc_opts)}
      else
        r.associated_class.from_xml_node(node, assoc_opts)
      end
    end
  end

  if fields = opts[:fields]
    set_fields(hash, fields, opts)
  elsif opts[:all_columns]
    meths = methods.collect{|x| x.to_s}.grep(Model::SETTER_METHOD_REGEXP) - Model::RESTRICTED_SETTER_METHODS
    hash.each do |k, v|
      if meths.include?(setter_meth = "#{k}=")
        send(setter_meth, v)
      else
        raise Error, "Entry in XML does not have a matching setter method: #{k}"
      end
    end
  else
    set(hash)
  end

  self
end

#to_xml(opts = {}) ⇒ Object

Return a string in XML format. If a block is given, yields the XML builder object so you can add additional XML tags. Accepts the following options:

:builder

The builder instance used to build the XML, which should be an instance of Nokogiri::XML::Node. This is necessary if you are serializing entire object graphs, like associated objects.

:builder_opts

Options to pass to the Nokogiri::XML::Builder initializer, if the :builder option is not provided.

:camelize

Sets the :name_proc option to one that calls camelize on the input string. Requires that you load the inflector extension or another library that adds String#camelize.

:dasherize

Sets the :name_proc option to one that calls dasherize on the input string. Requires that you load the inflector extension or another library that adds String#dasherize.

:encoding

The encoding to use for the XML output, passed to the Nokogiri::XML::Builder initializer.

:except

Symbol or Array of Symbols of columns not to include in the XML output.

:include

Symbol, Array of Symbols, or a Hash with Symbol keys and Hash values specifying associations or other non-column attributes to include in the XML output. Using a nested hash, you can pass options to associations to affect the XML used for associated objects.

:name_proc

Proc or Hash that accepts a string and returns a string, used to format tag names.

:only

Symbol or Array of Symbols of columns to only include in the JSON output, ignoring all other columns.

:root_name

The base name to use for the XML tag that contains the data for this instance. This will be the name of the root node if you are only serializing a single object, but not if you are serializing an array of objects using Model.to_xml or Dataset#to_xml.

:types

Set to true to include type information for all of the columns, pulled from the db_schema.



370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/sequel/plugins/xml_serializer.rb', line 370

def to_xml(opts={})
  vals = values
  types = opts[:types]
  inc = opts[:include]

  cols = if only = opts[:only]
    Array(only)
  else
    vals.keys - Array(opts[:except])
  end

  name_proc = model.xml_serialize_name_proc(opts)
  x = model.xml_builder(opts)
  x.send(name_proc[opts.fetch(:root_name, model.send(:underscore, model.name).gsub('/', '__')).to_s]) do |x1|
    cols.each do |c|
      attrs = {}
      if types
        attrs[:type] = db_schema.fetch(c, {})[:type]
      end
      v = vals[c]
      if v.nil?
        attrs[:nil] = ''
      end
      x1.send(name_proc[c.to_s], v, attrs)
    end
    if inc.is_a?(Hash)
      inc.each{|k, v| to_xml_include(x1, k, v)}
    else
      Array(inc).each{|i| to_xml_include(x1, i)}
    end
    yield x1 if block_given?
  end
  x.to_xml
end