perl Data structure to XML

Hi ALL.

I like to share with you solution for issue I had face it and come with way to solve it.

I was in need of some module that take any kind of hash or array or any combination of those two and convert them to xml file.

will, yes there are other module that do this task but not as need it.

so here my way to do this task:

also please point to any error in my code or any other best way to do the same thing. ^_^

use strict; use warnings; use XML::LibXML; my %TV = ( flintstones => { series => "flintstones", nights => [ "monday", "thursday", "friday" ], members => [ { name => "fred", role => "husband", age => 36, }, { name => "wilma", role => "wife", age => 31, }, { name => "pebbles", role => "kid", age => 4, }, ], }, jetsons => { series => "jetsons", nights => [ "wednesday", "saturday" ], members => [ { name => "george", role => "husband", age => 41, }, { name => "jane", role => "wife", age => 39, }, { name => "elroy", role => "kid", age => 9, }, ], }, simpsons => { series => "simpsons", nights => [ "monday" ], members => [ { name => "homer", role => "husband", age => 34, }, { name => "marge", role => "wife", age => 37, }, { name => "bart", role => "kid", age => 11, }, ], }, ); my $xmlString = HASH2XML(\%TV,'TV_SERIES'); print $xmlString; ###################################################################### +######################## sub HASH2XML{ my ($inHashRef) = $_[0]; my ($inName) = $_[1]; if(!defined $inName){$inName = 'rootNode';} my $doc = XML::LibXML::Document->new('1.0', 'utf-8'); # to + create XML doc my $rootNode = $doc->createElement("$inName"); # to create xml +root node $rootNode->setAttribute('Profile_id'=> "$inName"); # add some A +ttribute to the node _OBJ2XML_($doc,$rootNode,$inHashRef,$inName); $doc->setDocumentElement($rootNode); # print $doc->toString(); return $doc->toString(1); } sub _OBJ2XML_{ my ($doc) = $_[0]; my ($inNode) = $_[1]; my ($inRef) = $_[2]; my ($inName) = $_[3]; if(!defined $inName){$inName = 'Node';} if(ref($inRef) eq 'HASH'){ for my $key (sort keys %{$inRef}) { if(ref($inRef->{$key}) eq 'HASH'){ my $tag = $doc->createElement($key); # $tag->setAttribute('dataType'=> "HASH"); $inNode->appendChild($tag); _OBJ2XML_($doc,$tag,$inRef->{$key},$key); }else{ _OBJ2XML_($doc,$inNode,$inRef->{$key},$key); } } }elsif(ref($inRef) eq 'ARRAY'){ my $Len = @{$inRef}; for(my $i = 0; $i < $Len; $i++){ if(ref(@{$inRef}[$i]) eq 'HASH' or ref(@{$inRef}[$i]) eq ' +ARRAY'){ my $tag = $doc->createElement($inName); # $tag->setAttribute('dataType'=> "ARRAY"); $inNode->appendChild($tag); _OBJ2XML_($doc,$tag,@{$inRef}[$i],$inName); }else{ _OBJ2XML_($doc,$inNode,@{$inRef}[$i],$inName); } } }elsif(ref($inRef) eq 'CODE'){ print "--End to CODE ref @ LINE:".__LINE__."\n"; return 0; }elsif(ref($inRef) eq 'SCALAR'){ print "--End to SCALAR ref @ LINE:".__LINE__."\n"; return 0; }else{ my $tag = $doc->createElement($inName); # $tag->setAttribute('dataType'=> "data"); $tag->appendTextNode($inRef); $inNode->appendChild($tag); return 0; } return 0; }

-----------------------------------------------------------------

and below is the sample for the output:

# ------------------------------------------# # the XML output after doing pretty print # # ------------------------------------------# <?xml version="1.0" encoding="utf-8"?> <TV_SERIES Profile_id="TV_SERIES"> <flintstones> <members> <age>36</age> <name>fred</name> <role>husband</role> </members> <members> <age>31</age> <name>wilma</name> <role>wife</role> </members> <members> <age>4</age> <name>pebbles</name> <role>kid</role> </members> <nights>monday</nights> <nights>thursday</nights> <nights>friday</nights> <series>flintstones</series> </flintstones> <jetsons> <members> <age>41</age> <name>george</name> <role>husband</role> </members> <members> <age>39</age> <name>jane</name> <role>wife</role> </members> <members> <age>9</age> <name>elroy</name> <role>kid</role> </members> <nights>wednesday</nights> <nights>saturday</nights> <series>jetsons</series> </jetsons> <simpsons> <members> <age>34</age> <name>homer</name> <role>husband</role> </members> <members> <age>37</age> <name>marge</name> <role>wife</role> </members> <members> <age>11</age> <name>bart</name> <role>kid</role> </members> <nights>monday</nights> <series>simpsons</series> </simpsons> </TV_SERIES>

Replies are listed 'Best First'.
Re: perl Data structure to XML
by locked_user sundialsvc4 (Abbot) on May 29, 2015 at 14:22 UTC

    The first thing that I observe from looking at your Perl data-structure, vs. the resulting XML output, is that the two are not the same.   For example:

    members => [ { name => "george", role => "husband", age => 41, }, { name => "jane", role => "wife", age => 39, }, { name => "elroy", role => "kid", age => 9, },
    would correspond to a list of three nodes, each having three attributes apiece.   Any XML-writer would immediately produce such an XML output.

    Given that this is not what you want, you should transform your hash so that its structure does match what you want.   In place of three hashes, create three arrays.   (None of the elements in your desired output are to have any “attributes” at all.)   Consult the Perldoc to see what the data structure needs to look like.   Once you have done this, and have done it in the most simple-and-obvious way possible, you can hand this data structure to an XML-writer and get your XML.

      Hi,

      Well, we I was creating this code I kept this idea in my mind: I do not know the structure of the data beforehand, It can be any nasty hash in array in array in hash.... and so on.

      I can see your point here (about the attributes), And it raise new Q here:

      How can we decide what is Node and what is attribute without knowing the hash structure beforehand?

      we can add keywords to determine what is node and what is attribute, or maybe you have better idea. any help.

      Hosen