buildframework/helium/tools/common/packages/xml2tree.pm
changeset 1 be27ed110b50
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildframework/helium/tools/common/packages/xml2tree.pm	Wed Oct 28 14:39:48 2009 +0000
@@ -0,0 +1,322 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+#
+#****h*	lib/xml2tree.pm
+#	NAME
+#		xml2tree.pm
+#	DESCRIPTION
+#		This module	is used	to parse the data	from a xml file and convert it to tree like data structure for further processing
+#  		Each node is connected two way and looks like as follows
+#	   +---------+------+------------+------------+--------------+----------------------+
+#	   |prev			|el_name	 |attr		  |value	  	 |next               	|
+#	   |(Reference to 	|(Name of    |(Hash of the|(String value)|Reference of array to	|
+#	   |the parent node)|the element)|atrributes) |		         |next child elements)	|
+#	   +----------------+------------+------------+--------------+----------------------+	 
+#	RETURN VALUE
+#   	0 if successfull, 1 on error
+# 	EXAMPLE
+#		use xml2tree;
+#		.
+#		.
+#   	my $pr = xml2tree->new();
+#		$pr->parseFile(dct5_release_note.xml);
+#		.
+#		.
+#		my $trees = $getNode('Document');
+#	SEE ALSO
+#		sbt/data//subcon/dct5_release_note.xml
+#   	sbt/make_dct5_upload.pl
+#   	sbt/lib/sbt_common.pm
+#	HISTORY
+#		Version			:	0.1
+#		Date				:	
+#		Author			:	rownak
+#   TODO
+#		Case insensitive search
+#		Support non recursive search in case of attachment
+#******
+
+
+
+
+package	xml2tree;
+
+use	strict;
+use	XML::Parser;
+
+    	
+my %entities = ();
+my %root;
+my $parser;
+my $curr_elem;
+
+my $xml_file;
+my $count=0;
+
+#my @found_nodes;
+
+#==========================================================
+#		Intialization Part
+#
+#		Constructor. and others
+#==========================================================
+
+#usage(); 
+#exit 0;
+
+sub	new{
+	
+	$parser	= new	XML::Parser(ParseParamEnt	=> 1,Handlers	=> 
+				{Entity	=> \&entityHandler,	
+				 Char	=> \&charHandler,
+				 Start =>	\&startHandler,
+				 End =>	\&endHandler});
+
+	 
+	
+}
+
+#   Parse a given XML file.
+sub parseFile{
+     my $file = shift; 
+     $parser->parsefile($file);
+}		
+
+#==========================================================
+#		Data Processing Part
+#
+#		
+#==========================================================
+
+#   XML::Parser uses this function when it finds  an xml entity.
+sub entityHandler{
+    my ($p, $name, $val) = @_;
+    		
+    eval {$entities{$name} = $val;};
+    die ("Error in handling xml characters " .
+        "at line $p->current_line") if $@;
+        
+}
+
+#   XML::Parser uses this function when it finds an xml element start entry.
+sub startHandler{
+    my ($p, $element, %attr) = @_;
+    #Root of the tree
+	
+    if($element eq ''){
+    	return;
+	}
+	$p->{cdata_buffer}='';
+	#making a two way linked list of tree value
+	if(not defined($curr_elem)){
+    	$root{'el_name'} = $element;
+    	$root{'attr'} = \%attr;
+    	$root{'prev'} = 0;
+    	$root{'next'} = 0;
+    	$root{'value'}= 0;
+    	
+    	$curr_elem = \%root;
+    }else{
+	   	my %element;
+		
+		$element{'el_name'} = $element;
+		$element{'attr'} = \%attr;
+		$element{'prev'} = $curr_elem;
+		$element{'next'} = 0;
+		$element{'value'}= 0;
+		if($curr_elem->{'next'} == 0){
+			my @child_element;
+			push(@child_element,\%element);	
+			$curr_elem->{'next'}=\@child_element;
+		
+		}
+		else{
+			my $child_element = $curr_elem->{'next'};
+			push(@$child_element,\%element);	
+			$curr_elem->{'next'}=$child_element;
+		
+		}
+	
+		$curr_elem = \%element;
+   	}
+}
+
+#   XML::Parser uses this function when it finds  an xml element end entry.
+sub endHandler{
+	my($p) = @_;
+	$curr_elem->{'value'} = $p->{cdata_buffer} ;
+	$curr_elem = $curr_elem->{'prev'};
+}
+
+
+#   XML::Parser uses this function when it finds an xml character entry.
+sub charHandler{
+
+	my ($p, $str) = @_;
+    my $element;
+    my @context = $p->context;
+    $str =~ s/^\s+//;
+    $str =~ s/\s+$//;
+	
+	if($str eq ""){
+		return;
+	}
+	$p->{cdata_buffer} .= $str;
+	
+
+}
+
+
+
+
+##==========================================================
+##		External interface part
+##
+##		This methods will be used by its client
+##==========================================================
+
+#
+
+sub usage
+{
+   
+    print"\n\n";
+    print "Functionality: \n";
+    print"======================\n";
+    print "it parse any xml and convert the data into a two way trre like linked list \n\n";
+    print "use xml2tree\n";
+	print "\.\n";
+	print "\.\n";
+   	print 'my $pr = xml2tree->new()'."\n";
+	print '$pr->parseFile(dct5_release_note.xml)'."\n";
+	print "\.\n";
+	print "\.\n";
+	print 'my $trees = $getNode(\'Document\')'."\n";
+        
+}
+
+#Depending on the search criteria it returns array of nodes.
+# Input is 
+# 	el_name    => element name of searching node(compulsory)
+# 	attributes => Hash input of attributes to be searched. It will retun true even if it is a subset.(optional)
+# 	value      => value of the element(optional)
+#
+#Output is 
+#	Array of nodes that has been found . Each node has following type of structure
+#	   +---------+------+------------+------------+--------------+----------------------+
+#	   |prev			|el_name	 |attr		  |value	  	 |next               	|
+#	   |(Reference to 	|(Name of    |(Hash of the|(String value)|Reference of array to	|
+#	   |the parent node)|the element)|atrributes) |		         |next child elements)	|
+#	   +----------------+------------+------------+--------------+----------------------+	 
+sub getNode{
+	my $tmp_el_name  = shift;
+	my $tmp_attr     = shift;
+	my $tmp_value    = shift;
+	my @found_nodes=();	
+	if ($tmp_el_name eq '0' ){
+		return;	
+	}
+	
+	if(not defined $tmp_attr){$tmp_attr=0;}
+	if(not defined $tmp_value){$tmp_value=0;}
+	
+	
+	
+	searchTree($root{'next'},$tmp_el_name,$tmp_attr,  $tmp_value,\@found_nodes);
+	
+	return \@found_nodes; 
+}
+
+sub getPrevSibling{
+	my $curr_element = shift;
+	my $parent = $curr_element->{'prev'}; 	
+	my $child_array = $parent->{'next'};
+	my $prevSibling=undef;
+	foreach my $tmp_sibling (@$child_array){
+		if ($tmp_sibling == $curr_element){
+			last;	
+			
+		}
+	} 
+	return $prevSibling
+} 
+sub getEntities{
+	return \%entities;
+}
+
+sub getRoot{
+	return \%root;
+}
+##==========================================================
+##		Private functions part
+##
+##		This functions  will be used by external interface part
+##==========================================================
+
+#
+sub searchTree{
+	my $xml_sub_tree = shift;
+	my $tmp_el_name  = shift;
+	my $tmp_attr     = shift;
+	my $tmp_value    = shift;
+	my $found_nodes_ref = shift;
+	my $is_attr_exist = 0; 
+	my $is_value_exists=0;
+	my $is_el_name_exists=0;
+	if($xml_sub_tree eq '0'){return;}
+	foreach my $node (@$xml_sub_tree){
+			
+		my $prev_node = $node->{'prev'}; 
+		my $tmp_attr_node= $node->{'attr'};
+		if($tmp_attr ne '0'){
+			$is_attr_exist = is_LsubsetR($tmp_attr,$tmp_attr_node); 
+		}
+		
+		if((($tmp_el_name eq '0')||(($tmp_el_name ne '0') && ($node->{'el_name'} eq $tmp_el_name))) &&
+			(($tmp_value eq '0')||(($tmp_value ne '0') && ($node->{'value'} eq $tmp_value)))&&
+			(($tmp_attr eq '0')||(($tmp_attr ne '0') && $is_attr_exist))){
+			
+			push (@$found_nodes_ref, $node)		
+	    }
+		  
+		searchTree ($node->{'next'}, $tmp_el_name, $tmp_attr, $tmp_value, $found_nodes_ref);
+	}
+}
+
+
+sub is_LsubsetR(){
+	my $left_hash  = shift;
+	my $right_hash = shift;
+	if ((keys(%$left_hash) == 0) || (keys(%$right_hash) ==0)){
+		return 0;	
+		
+	}
+	my $is_match=1;
+	my $is_match_single;
+	
+	while(my($key, $value) = each(%$left_hash)){
+		$is_match_single=0;
+		while(my ($r_key,$r_value) = each(%$right_hash)){
+			if(($key eq $r_key ) && ($value eq $r_value)){
+				$is_match_single=1;
+			}
+		}
+		$is_match = $is_match & $is_match_single;
+	} 
+	return $is_match;
+}
+
+
+1;
\ No newline at end of file