Here's what I needed for my project:
Input
data = { "my_tag_one" => "Rats off to ya!", "pril" => "tooth paste", "gambit" => "contents here"}
Output
<?xml version="1.0" encoding="iso-8859-1"?>
<contents>
<content id="my_tag_one">
<string>
Rats off to ya!
</string>
</content>
<content id="pril">
<string>
tooth_paste
</string>
</content>
<content id="gambit">
<string>
contents here
</string>
</content>
</contents>
The code it took to accomplish this was:
htx = HashToXml.new
htx.mode = :basic # expects a data hash like { "id" => "value" }
# htx.mode = :advanced # expects data hash like { "id" => { "child_element_or_attribute1" => "some value", "child_element_or_attribute2" => "value for second child element" }
htx.parents = ["contents"] # allows you to specify parent nodes
htx.element = "content" # specify the element name
htx.element_attributes = { "id" => :key } # specify any attributes
# This allows us to specify the attribute to
# be named "id" and have it's value be
# :key which points to the key in the data hash
htx.child_elements = ["string"] # if it were in advanced mode... you'd have more. But not allowed in basic
#htx.child_attributes = nil
htx.child_values = [:value]
data = htx.go(data)
puts data
Rubish or rubyish? I come from a C# background, so I might be misusing hashes completely, and coming at it in an odd way =/
Here's the class (probably a little more bloated and erratic due to my noviceship):
class HashToXml
attr_accessor :mode, :parents, :element, :value, :element_attributes, :child_elements, :child_values
def go(data)
case @mode
when :basic
#puts "basic expects the data hash to be a simple series of key value pairs."
return basic(data)
end
end
private
def basic(data)
output_string = ""
header = '<?xml version="1.0" encoding="iso-8859-1"?>'
output_string += header + "\n"
output_string << open_parents
attribs = get_attributes(data)
output_string << compile_elements(data, attribs) # attribs = [" id="kara", " id="rockefeller"]
output_string << close_parents
return output_string
end
def compile_elements(data, attribs=nil)
ret_string = ""
tabs = (@parents.length).times.map{" "}.join
i = 0
data.each do |key, val|
@child_elements.each do |child_elements|
ret_string << tabs + "<#{@element}#{attribs[i]}>\n"
ret_string << tabs + " " + "<#{child_elements}>\n"
ret_string << tabs + " " + val + "\n"
ret_string << tabs + " " + "</#{child_elements}>\n"
ret_string << tabs + "</#{@element}>\n"
end
i += 1
end
return ret_string
end
# This function will figure out what the attributes payload will be for each
# element all at once.
def get_attributes(data)
ret_array = []
i = 0
data.each do |key, val| # for each data pair in the data population
# only tested for it iterating once...
@element_attributes.each do |attribute_name, attribute_pointer| # for each element pair in the specifier
tag_name = key if attribute_name == :key
tag_name = val if attribute_name == :value
tag_name = attribute_name if attribute_name.is_a?(String)
raise 'element_attributes was set improperly...' if tag_name.nil?
value = key if attribute_pointer == :key
value = val if attribute_pointer == :value
value = attribute_pointer if attribute_pointer.is_a?(String) #untested
raise 'element_attributes was set improperly...' if value.nil?
ret_array << " #{tag_name}=\"#{value}\""
end
#puts ret_string
end
ret_array = nil if ret_array.empty? # untested
return ret_array
end
def open_parents
ret_string = ""
i = 0
@parents.each do |parent|
tabs = i.times.map { " " }.join
ret_string += tabs + "<#{parent}>\n"
i += 1
end
return ret_string
end
def close_parents
ret_string = ""
i = @parents.length-1
@parents.reverse.each do |parent|
tabs = i.times.map { " " }.join
ret_string += tabs + "</#{parent}>\n"
i -= 1
end
return ret_string
end
end
The class is very much unfinished since I only needed it in one very narrow test case. If you guys think the ruby world needs it though, I'd start a gem and begin writing up test cases and all that.
This post has been edited by NotarySojac: 12 December 2011 - 05:12 PM

New Topic/Question
Reply




MultiQuote



|