merged cont.
[opensuse:yast-rest-service.git] / webservice / lib / base_model / serializers / xml_serializer.rb
1 #--
2 # Webyast Webservice framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19 module BaseModel
20   module Serialization
21     # Serializes model to XML
22     #
23     # +WARNING+:: keys from hash is get to tags unescaped, so don't use hash with keys which can break XML tag (this behavior might change in future)
24     # options:: recognizes common Builder::XmlMarkup options (if root is not given, it uses singular of model name )
25     # block:: not used now
26     def to_xml(options={:indent => 2},&block)
27       serializer = XmlSerializer.new(self,options)
28       block_given? ? serializer.serialize(&block) : serializer.serialize
29     end
30
31     # loads model from xml
32     def from_xml(xml)
33       load(Hash.from_xml(xml).values.first)
34       self
35     end
36
37     class XmlSerializer < BaseModel::Serialization::Serializer
38       def serialize
39         root = options[:root] || @model.class.model_name.singular
40         builder = options[:builder] || Builder::XmlMarkup.new(options)
41         builder.instruct! unless options[:skip_instruct]
42         builder.tag!(root){
43           @attributes.each do |attr|
44             value = @model.instance_variable_get(attr)
45             name = attr.to_s[1..-1]
46             serialize_value(name,value,builder) unless value.nil?
47           end
48         }
49       end
50
51       protected
52       #place for all types for special serializing
53       def serialize_value(name,value,builder)
54         if value.is_a? Array
55           builder.tag!(name,{:type => "array"}) do
56             value.each do |v|
57               serialize_value(name,v,builder)
58             end
59           end
60         elsif value.is_a? Hash
61         builder.tag!(name) do
62             value.each do |k,v|
63               serialize_value(k,v,builder)
64             end
65           end
66         elsif value.respond_to? :to_xml #value has own serialization method
67           value.to_xml :root => name, :skip_instruct => true, :builder => builder
68         else
69           type = XML_TYPE_NAMES[value.class.to_s]
70           opts = {}
71           opts[:type] = type if type
72           #NOTE: can be optimalized for primitive types like boolean or numbers to avoid XML escaping
73           builder.tag!(name,value.to_s,opts)
74         end
75       end
76
77       XML_TYPE_NAMES = { #type conversion
78           "Symbol"     => "symbol",
79           "Fixnum"     => "integer",
80           "Bignum"     => "integer",
81           "BigDecimal" => "decimal",
82           "Float"      => "float",
83           "TrueClass"  => "boolean",
84           "FalseClass" => "boolean",
85           "Date"       => "date",
86           "DateTime"   => "datetime",
87           "Time"       => "datetime",
88           "ActiveSupport::TimeWithZone" => "datetime"
89         } unless defined?(XML_TYPE_NAMES)
90
91     end
92   end
93 end