joec_ has asked for the wisdom of the Perl Monks concerning the following question:

Hi

This one has been driving me crazy and i'm sure its pretty simple. I have to create an xml document that looks like this (note xml modules are not an option - i have to hard code the tags)

<views> <view id="123456" name="all"> <parameter id="123">Param 1</parameter> <parameter id="124">Param 2</parameter> </view> <view id="123457" name="detail"> <parameter id="125">Param 3</parameter> <parameter id="126">Param 4</parameter> <parameter id="127">Param 5</parameter> <parameter id="128">Param 6</parameter> </view> </views>
As you can see, views may have many parameters, and my root element <views> may have many views. This data is coming from a database that returns a table like this:
VIEW_ID VIEW_NAME PARAM_ID PARAM_NAME ---------------------------------------------- 123456 all 123 Param 1 123456 all 124 Param 2 123457 detail 125 Param 3 123457 detail 126 Param 4 123457 detail 127 Param 5 123457 detail 128 Param 6

I have tried lots of variations on while loops, keeping track of ids etc, but cannot quite seem to grasp it. Some code is below that i have tried

$xml = "<views>\n"; while ($row = $sth->fetchrow_arrayref){ if (!defined($id{$row->[0]})){ $xml .= $xml . "<view id=\"$row->[0]\" name=\"".$row->[1]."\"> +\n"; $id{$row->[0]} = $row->[0]; if (!defined($param{$row->[3]})){ $xml .= $xml . "<parameter id=\"$row->[3]\">".$row->[4]."< +/parameter>\n"; $id{$row->[3]} = $row->[3]; } }elsif(defined($id{$row->[0]})){ if (!defined($param{$row->[3]})){ $xml .= $xml . "<parameter id=\"$row->[3]\">".$row->[4]."< +/parameter>\n"; } } }
There are a few confusing points for me (where would i put the closing </view> tags for example?)

If anyone has any ideas (if using a module, i will try to get it installed as hard as i can), i would be grateful!

Thanks

Joe

-----

Eschew obfuscation, espouse elucidation!

Replies are listed 'Best First'.
Re: Creating simple XML from a DB query
by GrandFather (Saint) on Apr 01, 2009 at 02:44 UTC

    I'm not sure why 'hard code the tags' is a hurdle to using modules, but Yes, even you can use CPAN may provide some options.

    Generating simple XML with clean data (nothing that needs to be encoded as entities) ought be simple. For example (neglecting error checking and the XML header):

    use strict; use warnings; print "<views>\n"; my $currId; while (<DATA>) { my ($viewId, $viewName, $paramId, $paramName) = split; print " </view>\n" if defined $currId && $currId ne $viewId; if (! defined $currId || $viewId ne $currId) { print qq( <view id="$viewId" name="$viewName">\n); $currId = $viewId; } print qq( <parameter id="$paramId">$paramName</parameter>\n +); } print " </view>\n</views>\n"; __DATA__ 123456 all 123 Param 1 123456 all 124 Param 2 123457 detail 125 Param 3 123457 detail 126 Param 4 123457 detail 127 Param 5 123457 detail 128 Param 6

    Prints:

    <views> <view id="123456" name="all"> <parameter id="123">Param</parameter> <parameter id="124">Param</parameter> </view> <view id="123457" name="detail"> <parameter id="125">Param</parameter> <parameter id="126">Param</parameter> <parameter id="127">Param</parameter> <parameter id="128">Param</parameter> </view> </views>

    True laziness is hard work
Re: Creating simple XML from a DB query
by Your Mother (Archbishop) on Apr 01, 2009 at 05:23 UTC

    There are many ways to cobble this together and do a decent job as GrandFather shows above. Consider doing it right™ however, as GrandFather also alludes with the CPAN link.

    Using the right tools is painful at first but forgoing them is false economy and will waste drastically more time and effort. Learning to do it right is also the way to get your resume to the top of the pile. One of the right ways to do XML is XML::LibXML (there are others but not many and writing your own parsing code is definitely not one of them).

    use strict; use warnings; use XML::LibXML; my $doc = XML::LibXML::Document->new(); my $root = $doc->createElement("views"); $doc->setDocumentElement($root); while ( <DATA> ) { chomp; my ( $view_id, $view_name, $param_id, $param_name ) = split /\s+/, + $_, 4; # find or create... my ( $view_node ) = $root->findnodes("//view[\@id=$view_id]"); unless ( $view_node ) { $view_node = $doc->createElement("view"); $view_node->setAttribute("name",$view_name); $view_node->setAttribute("id",$view_id); $root->appendChild($view_node); } my $param_node = $doc->createElement("parameter"); $param_node->setAttribute("id", $param_id); $param_name = $doc->createTextNode($param_name); $param_node->appendChild($param_name); $view_node->appendChild($param_node); } print $doc->serialize(1); __DATA__ 123456 all 123 Param 1 123456 all 124 Param 2 123457 detail 125 Param 3 123457 detail 126 Param 4 123457 detail 127 Param 5 123457 detail 128 Param 6
    <?xml version="1.0"?> <views> <view name="all" id="123456"> <parameter id="123">Param 1</parameter> <parameter id="124">Param 2</parameter> </view> <view name="detail" id="123457"> <parameter id="125">Param 3</parameter> <parameter id="126">Param 4</parameter> <parameter id="127">Param 5</parameter> <parameter id="128">Param 6</parameter> </view> </views>
      Brilliant - thanks!

      -----

      Eschew obfuscation, espouse elucidation!