use strict; use XML::LibXML; my %testHash; ## create a test hash $testHash{root}{testEl1}{currentValue} = 0; $testHash{root}{testEl1}{comment} = "System test element 1"; $testHash{root}{testEl1}{enable} = 1; $testHash{root}{testEl2}{currentValue} = 0; $testHash{root}{testEl2}{comment} = "System test element 2"; $testHash{root}{testEl2}{enable} = 1; $testHash{root}{testEl2}{newLevel}{enable1} = 1; $testHash{root}{testEl2}{newLevel}{enable2} = 1; $testHash{root}{testEl2}{newLevel}{enable3} = 1; $testHash{root}{testEl3}{newLevel}{enable} = 1; $testHash{root}{testEl2}{reference} = $testHash{root}{testEl1}; ## call the hash processor! my $string = myHash2Xml( \%testHash ); ## create the output XML open FILEOUT, ">myHash2Xml.xml"; print FILEOUT "$string\n"; close FILEOUT; ## end of script ## covert our hash to XML, this is a wrapper to create the ## document and pass it back as a string sub myHash2Xml { my ($hash) = @_; ## create a new xml document! my $xmlDoc = XML::LibXML::Document->new( '1.0', 'UTF-8' ); ## create the root element and a pointer to it! my $root = $xmlDoc->createElement("testDoc"); $xmlDoc->setDocumentElement($root); examineHash( $hash, \$xmlDoc, \$root ); # process the hash my $xmlString = $xmlDoc->toString(1); print "$xmlString\n"; return $xmlString; } ## wrapper for the recurser, sub examineHash { my ( $hash, $xmlDoc, $lastElement ) = @_; my %refsHash; # hash ref counter, used to prevent/detect circular refs examineHashRecurse( \%refsHash, $hash, $xmlDoc, $lastElement ); # here we go } ## recurser! sub examineHashRecurse { my ( $refsHash, $hash, $xmlDoc, $lastElement ) = @_; foreach my $key ( sort { $a cmp $b } keys( %{$hash} ) ) { # go through keys at current level if ( ( $$hash{$key} . "" ) =~ /HASH\(/ ) { # is it another hash? ## its another hash, go deeper! if ( !exists $$refsHash{ $$hash{$key} } ) { # check if its in the reference hash $$refsHash{ $$hash{$key} } = 1; # print "create element $key\n"; my $newElement = $$xmlDoc->createElement($key); # create new element $$lastElement->appendChild($newElement); # add element to our doc under the last element ## remember to pass the new element as a reference. examineHashRecurse( $refsHash, $$hash{$key}, $xmlDoc, \$newElement ); } ## else, this has alread been examined! stops circular continuation else { # do something with a circular reference??? $$refsHash{ $$hash{$key} }++; } } else { # print "create attribute $key with value " . $$hash{$key} . "\n"; $$lastElement->setAttribute( "$key", $$hash{$key} ); # add attribute to the last element! } } }