require 'net/http' require 'rexml/document' module XmlUtils BASIC_HEADER = '' def self.get_url_root(url) xml = Net::HTTP.get(URI(url)) return nil if !xml xdoc = REXML::Document.new(xml) return nil if !xdoc root = xdoc.root end def self.get_xml_root(xml) xdoc = REXML::Document.new(xml) return nil if !xdoc root = xdoc.root end def self.get_file_root(aFilename) get_xml_root(MiscUtils.string_from_file(aFilename)) end def self.single_node(node,xpath,default=nil) return default if node.nil? || xpath.nil? || xpath=='' val = REXML::XPath.first(node,xpath) return val.nil? ? default : val end def self.peek_node(node,xpath,default=nil) return default if node.nil? || xpath.nil? || xpath=='' val = REXML::XPath.first(node,xpath) return val.nil? ? default : val.to_s end def self.peek_node_value(node,xpath,default=nil) peek_node(node,xpath+'/text()',default) end # convert onetwo to {'a' => 'one', 'b' => 'two'} def self.hash_from_elements(aXMLRoot) result = {} aXMLRoot.elements.each{|e| result[e.name] = e.text} return result end # given 'textblah' returns {:name=>"tag", :text=>"textblah", "a"=>"1", "b"=>"2"} def self.hash_from_tag(aTagString) result = {} tag = get_xml_root(aTagString) return nil if !tag tag.attributes.each_attribute {|attr| result[attr.expanded_name] = attr.value } result[:name] = tag.name result[:text] = tag.text if tag.text return result end # given {:name=>"tag", :text=>"textblah", "a"=>"1", "b"=>"2"} returns 'textblah' def self.tag_from_hash(aHash,aName=nil,aText=nil) aName ||= aHash[:name] aText ||= aHash[:text] result = "<#{aName}" aHash.each {|k,v| result += " #{k}=\"#{encode(v.to_s)}\"" if k.is_a? String} result += aText ? " >#{aText}" : " />" end def self.hash_to_xml(aHash,aRootName,aDocHeader=true) xdoc = REXML::Document.new(BASIC_HEADER) root = xdoc.add_element(aRootName) aHash.each do |n,v| root.add_element(n).add_text(v) end return xdoc end def self.read_simple_items(aRoot,aParentXPath) result = {} REXML::XPath.each(aRoot, aParentXPath+'/Item') do |item| result[item.attribute('Name').to_s] = item.text end return result end def self.quick_write_simple_items(aHash,aParent) return "<#{aParent} />\n" if !aHash || aHash.empty? result = "<#{aParent}>\n" aHash.each {|key,value| result += "\t#{value.to_s}\n" } result += "<#{aParent}/>\n" return result end def self.read_config_values(aXmlConfig) xmlRoot = get_file_root(aXmlConfig) return read_simple_items(xmlRoot,'/Config/SimpleItems') end # Takes a node or xml string and writes it out formatted nicely. # aOutput may be given eg. a stream or nil can be given to get a returned string def self.format_nicely(aXml,aOutput=nil) aXml = REXML::Document.new(aXml) unless aXml.is_a?(REXML::Element) f = REXML::Formatters::Pretty.new(2,true) f.compact = true f.width = 120 aOutput ||= '' f.write(aXml,aOutput) return aOutput end def self.encode(aString) result = aString.clone; result.gsub!('&','&') result.gsub!('<','<') result.gsub!('>','>') result.gsub!('"','"') result.gsub!("'",''') result.gsub!(/[\x80-\xFF]/) {|c| "&#x#{'%X' % c[0]};"} return result end def self.hash_to_deflist(aHash,aBuilder=nil) aBuilder ||= Builder::XmlMarkup.new(:indent => 2) aBuilder.dl do aHash.each do |k,v| aBuilder.dt(k.to_s) aBuilder.dd(v.to_s) end end end def self.data_to_table(aRowHashes,aCaption=nil,aColNames=nil,aBuilder=nil) aBuilder ||= Builder::XmlMarkup.new(:indent => 2) aBuilder.table do if aCaption.is_a? String aBuilder.caption(aCaption) elsif aCaption.is_a? Hash aBuilder.caption do XmlUtils.hash_to_deflist(aCaption,aBuilder) end end aColNames ||= aRowHashes.first.keys aBuilder.thead do aBuilder.tr do aColNames.each do |name| aBuilder.td(name.to_s) end end end aBuilder.tbody do aRowHashes.each do |row| aBuilder.tr do aColNames.each do |name| aBuilder.td(row[name].to_s) end end end end end end end