XML比较。
最近帮别人写了一个XML的比较的小程序,分享一下
module XMLToolclass Nodeattr_reader :nodes, :name, :text, :attributesdef initialize name, text, attributes = {}, ancestor_nodes = []@name = name@attributes = attributes@text = text@ancestor_nodes = ancestor_nodes.clone@nodes ||= {}enddef ancestor_nodes@ancestor_nodes.cloneenddef add_node node@nodes[node.name] ||= []@nodes[node.name] << nodeend# blk params: node name, node arraydef each &blk@nodes.each &blkenddef has_children?!@nodes.empty?enddef compare_with a_node, failed_nodes = [], passed_nodes = []#, *ignore_nodes#puts "Current Node: #{self.name}, Compared Node: #{a_node.name}"#failed_nodes = failed_nodes.clonepass_fg = trueif has_children?if a_node.has_children?each do |name, children_nodes|if a_node.nodes[name].nil?#puts "Not Found. Node: #{name}, #{attributes}, #{text}"pass_fg = falsebreakelsechildren_nodes.each do |child_node|ps_fg = falsea_node.nodes[name].each do |a_child|if child_node.attributes == a_child.attributesif child_node.compare_with(a_child, failed_nodes, passed_nodes)[0]ps_fg = truebreakendendendif ps_fgnextelsepass_fg = falsebreakendendendend#puts "Not Found. Node: #{name}, #{attributes}, #{text}" if !pass_fgelse# "Structure Error."pass_fg = falseendelseif a_node.has_children?# "Structure Error: Node :#{name}, #{a_node.name}"pass_fg = falseelseif a_node.name != name || a_node.attributes != attributes || a_node.text != text#puts %Q{Node Error: #Node Name:#{name}, #{a_node.name}#Attributes: #{attributes}, #{a_node.attributes}#Value: #{text}, #{a_node.text}#}pass_fg = falseendendend#puts error_msg.join("\n") if !error_msg.empty?if pass_fg#puts self.namepassed_nodes << selffailed_nodes.delete(self) if failed_nodes.include?(self)elsefailed_nodes << self if !passed_nodes.include? (self)endreturn([pass_fg, failed_nodes])endendend
module XMLToolclass Treeattr_reader :rootdef initialize xml_filerequire 'rexml/document'File.open(xml_file) do |file|doc = REXML::Document.new(file)@root = parse_xml(doc.root, Node.new(doc.root.name, doc.root.text, doc.root.attributes))endenddef compare_with another_tree, *ignore_nodesenddef self.filter_failed_nodes failed_nodesrets = []failed_nodes.each do |node|ancestor_chain = node.ancestor_nodes << noderets << ancestor_chain if rets.empty?rets.each do |ret|if (ret & ancestor_chain) == retrets.delete retrets << ancestor_chainelseif (ret & ancestor_chain) != ancestor_chainrets << ancestor_chainendendendendreturn retsendprivate# Fill Node according elementdef parse_xml element, node#puts element.name#puts node.ancestor_nodesif element.has_elements?element.elements.each do |sub_ele|ancestor_nodes = node.ancestor_nodes << nodeif sub_ele.has_elements?child_node = Node.new(sub_ele.name, sub_ele.text, sub_ele.attributes, ancestor_nodes)node.add_node(parse_xml(sub_ele, child_node))elsenode.add_node(Node.new(sub_ele.name, sub_ele.text, sub_ele.attributes, ancestor_nodes))endendendnodeendendend
$LOAD_PATH << File.dirname(__FILE__) unless $LOAD_PATH.include? File.dirname(__FILE__)require 'xmltool'include XMLToolroot1 = Tree.new('Completion090_MsgValue_XML.xml').rootroot2 = Tree.new('Completion090_MsgValue_XML5.xml').root#tree.nodes[0].nodes[0].nodes[0].nodes.each do |e|#puts e.tag_name#puts e.text#endret = root1.compare_with(root2)#ret = root2.compare_with(root1)puts ret[0]Tree.filter_failed_nodes(ret[1]).each do |ancestor_chain|ancestor_chain.each_with_index do |node, i|puts "#{"\s" * 2 * i}#{node.name} #{node.attributes} ->"endputs ancestor_chain.last.textputs "------------------"end#puts ret[1][0].name#puts ret[1][0].attributes#puts ret[1][1].name#puts ret[1][1].attributes