XML比较。

最近帮别人写了一个XML的比较的小程序,分享一下

module XMLTool

	class Node
		
		attr_reader :nodes, :name, :text, :attributes
		
		def initialize name, text, attributes = {}, ancestor_nodes = []
			@name = name
			@attributes = attributes
			@text = text
			@ancestor_nodes = ancestor_nodes.clone
			@nodes ||= {}
		end
		
		def ancestor_nodes
			@ancestor_nodes.clone
		end
		
		
		def add_node node
			@nodes[node.name] ||= []
			@nodes[node.name] << node
		end
		
		# blk params: node name, node array
		def each &blk
			@nodes.each &blk
		end
		
		
		def has_children?
			[email protected]?
		end
				
		def compare_with a_node, failed_nodes = [], passed_nodes = []#, *ignore_nodes
			#puts "Current Node: #{self.name}, Compared Node: #{a_node.name}"
			#failed_nodes = failed_nodes.clone
			pass_fg = true
			if 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 = false
							break
						else
							children_nodes.each do |child_node|
								ps_fg = false
								a_node.nodes[name].each do |a_child|
									if child_node.attributes == a_child.attributes
										if child_node.compare_with(a_child, failed_nodes, passed_nodes)[0]
											ps_fg = true
											break
										end
									end
								end
								if ps_fg
									next
								else
									pass_fg = false
									break
								end
							end							
						end
					end
					#puts "Not Found. Node: #{name}, #{attributes}, #{text}" if !pass_fg
				else
					# "Structure Error."
					pass_fg = false
				end				
			else
				if a_node.has_children?
					# "Structure Error: Node :#{name}, #{a_node.name}"
					pass_fg = false
				else
					if 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 = false
					end
				end
			end
			#puts error_msg.join("\n") if !error_msg.empty?
			if pass_fg
				#puts self.name
				passed_nodes << self
				failed_nodes.delete(self) if failed_nodes.include?(self)
			else
				failed_nodes << self if !passed_nodes.include? (self)
			end
			return([pass_fg, failed_nodes])
		end
	
	end

end


module XMLTool
	
	class Tree
		
		attr_reader :root
		
		def initialize xml_file
			require '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))
			end
		end
	
		def compare_with another_tree, *ignore_nodes
			
		end
		
		def self.filter_failed_nodes failed_nodes
			rets = []
			failed_nodes.each do |node|
				ancestor_chain = node.ancestor_nodes << node
				rets << ancestor_chain if rets.empty?
				rets.each do |ret|
					if (ret & ancestor_chain) == ret
						rets.delete ret
						rets << ancestor_chain
					else
						if (ret & ancestor_chain) != ancestor_chain
							rets << ancestor_chain
						end
					end
				end
			end
			return rets
		end
		
		private
		# Fill Node according element
		def parse_xml element, node			
			#puts element.name
			#puts node.ancestor_nodes
			if element.has_elements?
				element.elements.each do |sub_ele|
					ancestor_nodes = node.ancestor_nodes << node
					if 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))
					else
						node.add_node(Node.new(sub_ele.name, sub_ele.text, sub_ele.attributes, ancestor_nodes))
					end
				end
			end
			node
		end
		
	
	end

end

测试代码
$LOAD_PATH << File.dirname(__FILE__) unless $LOAD_PATH.include? File.dirname(__FILE__)
require 'xmltool'


include XMLTool
root1 = Tree.new('Completion090_MsgValue_XML.xml').root
root2 = 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
#end

ret = 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} ->"
	end
	puts ancestor_chain.last.text
	puts "------------------"
end

#puts ret[1][0].name
#puts ret[1][0].attributes
#puts ret[1][1].name
#puts ret[1][1].attributes


之前都没做过XML的东西,nokogiri看了一下不会用,就用rexml解析xml,目前可能还有点bug,不过能凑合用,由于时间跟观众太少的关系,就不解释了。

你可能感兴趣的:(Ruby)