Module: Doodle::XML

Extended by:
NokogiriAdapter, REXMLAdapter
Includes:
Utils
Included in:
Document
Defined in:
lib/doodle/xml.rb

Overview

adds to_xml and from_xml methods for serializing and deserializing Doodle object graphs to and from XML

works for me but YMMV

Defined Under Namespace

Modules: NokogiriAdapter, REXMLAdapter Classes: Document

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NokogiriAdapter

get_root, parse_xml, text_node?

Methods included from REXMLAdapter

get_root, parse_xml, text_node?

Methods included from Utils::ClassMethods

#const_lookup, #const_resolve, #deep_copy, #doodle_caller, #flatten_first_level, #normalize_const, #normalize_keys, #normalize_keys!, #pluralize, #snake_case, #stringify_keys, #stringify_keys!, #symbolize_keys, #symbolize_keys!, #try

Class Method Details

.from_xml(ctx, str) ⇒ Object

parse XML str into a Doodle object graph, using ctx as the root namespace (can be module or class)

this is the entry point - most of the heavy lifting is done by from_xml_elem



91
92
93
94
95
# File 'lib/doodle/xml.rb', line 91

def from_xml(ctx, str)
  doc = parse_xml(str)
  root = get_root(doc)
  from_xml_elem(ctx, root)
end

.from_xml_elem(ctx, root) ⇒ Object

helper function to handle recursion



98
99
100
101
102
103
104
105
106
# File 'lib/doodle/xml.rb', line 98

def from_xml_elem(ctx, root)
  attributes = root.attributes.inject({ }) { |hash, (k, v)| hash[k] = EscapeXML.unescape(v.to_s); hash}
  text, children = root.children.partition{ |x| text_node?(x) }
  text = text.map{ |x| x.to_s}.reject{ |s| s =~ /^\s*$/}.join('')
  oroot = Utils.const_lookup(root.name, ctx).new(text, attributes) {
    from_xml_elem(root)
  }
  oroot
end

Instance Method Details

#format_attributes(attributes) ⇒ Object

override this to define a specialised attributes format



134
135
136
137
138
139
140
# File 'lib/doodle/xml.rb', line 134

def format_attributes(attributes)
  if attributes.size > 0
    " " + attributes.map{ |k, v| %[#{ k }="#{ v }"]}.join(" ")
  else
    ""
  end
end

#format_tag(tag, attributes, body) ⇒ Object

override this to define a specialised tag format



143
144
145
146
147
148
149
# File 'lib/doodle/xml.rb', line 143

def format_tag(tag, attributes, body)
  if body.size > 0
    ["<#{tag}#{format_attributes(attributes)}>", body, "</#{tag}>"]
  else
    ["<#{tag}#{format_attributes(attributes)} />"]
  end.join('')
end

#tagObject

override this to define a tag name for output - the default is to use the classname (wthout namespacing)



128
129
130
131
# File 'lib/doodle/xml.rb', line 128

def tag
  #self.class.to_s.split(/::/)[-1].downcase
  self.class.to_s.split(/::/)[-1]
end

#to_xmlObject

output Doodle object graph as xml



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/doodle/xml.rb', line 152

def to_xml
  body = []
  attributes = []
  self.doodle.attributes.map do |k, attr|
    next if self.default?(k)
    # arbitrary
    if k == :_text_
      body << self._text_
      next
    end
    v = send(k)
    if v.kind_of?(Doodle)
      body << v.to_xml
    elsif v.kind_of?(Array)
      body << v.map{ |x| x.to_xml }
    else
      attributes << [k, EscapeXML.escape(v)]
    end
  end
  format_tag(tag, attributes, body)
end