Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

using xml::simple with unknown xml structure

by ctaustin (Sexton)
on Jul 14, 2005 at 14:05 UTC ( #474874=perlquestion: print w/ replies, xml ) Need Help??
ctaustin has asked for the wisdom of the Perl Monks concerning the following question:

I have an xml file whose structure basically contains one known tag, the root, and several tags within this that are not known.
<tables> <junk1 type="junk1" name="rates" requiredfields="date,rate"/> <junk2 type="junk2" name="demands" requiredfields=""/> <detail name="schema.detail" requiredfields="date,rate,scenarioname" +> <date mnemonic="date" name="The_Date" type="date" size="8"/> <rate mnemonic="rate" name="RATE" type="number" size=""/> </detail> <xyz name="schema.xyz" requiredfields="obsdate,wac,wala,wam"> <obsdate mnemonic="obsdate" name="asofdate" type="summed" calc="to +_char(asofdate,'mm/dd/yyyy')" size="8" required="false" cohort="true" +/> <model mnemonic="model" name="model" type="summed" size="" require +d="true" cohort="true" calc="trim('model')"/> <new mnemonic="new" name="ISNEW" type="char" size="" required="fal +se" cohort="true"/> <loancount mnemonic="loancount" name="LoanCount" type="summed" siz +e="8" required="false" cohort="fale" calc="sum(LOANCOUNT)"/> <cpr mnemonic="cpr" name="CPR" type="summed" size="8" calc="CASE WHEN SUM(a) != 0 THEN round((1-power(1-sum(b/ +100*a)/sum(a),12))*100,2) ELSE SUM(0) END" required="true" cohort="fa +lse"/> </xyz> </tables

I need to produce an output file from this that looks like:
table name   field name   type   size   required   calc

I am trying to use XML::Simple to do this. However all of the examples I have found use a XML file that has a more defined form so that you can reference specific nodes. The issue I have is that new tables are being added to, so I need be be able to loop over these items generically.

I tried the following:
my $xml = XMLin($xfile,ForceArray=>1)||die("unable to perform 'in' n") +; foreach $table (keys %{$xml->{tables}}){ print "$table\n"; }
thinking this would give me junk1, junk2, detail, and xyz but it actually doesn't return anything. It runs, but nothing is output. I thought that if I could this, I could then reference the tag elements like mnemonic and name with something like  $name=$xml->{$table}->{name};.

Comment on using xml::simple with unknown xml structure
Select or Download Code
Re: using xml::simple with unknown xml structure
by shiza (Hermit) on Jul 14, 2005 at 16:15 UTC
    This code worked for me (using OO interface):
    #!/usr/bin/perl use strict; use XML::Simple; use Data::Dumper; my $xml_obj = XML::Simple->new(ForceArray => ['tables']); # xml my $xml = $xml_obj->XMLin('test.xml'); print Dumper($xml); exit;
    Also, double check for any errors in your xml file.

    Output:
    Code w/ loop:
      What is happening is that the top level tag doesnt exist in the input structure. This is always the case with XML::Simple from what i know. So for your file, the top-level keys in the $xml hash will be the tags directly under the outer enclosing table tag.

      Just started using XML::Simple a couple weeks ago myself, it takes a bit to get used to, but becomes quite powerful once you get used to it.

        It looks like the object oriented method is getting me what I needed. I don't see a whole lot of difference with what I tried, but I am thrilled that it is working. Thanks everyone for the support.
Re: using xml::simple with unknown xml structure
by injunjoel (Priest) on Jul 14, 2005 at 17:50 UTC
    Greetings all,
    A bit off topic but here is a little script I use to investigate how XML::Simple is parsing my *.xml files
    This is meant to be run from the same directory that contains the xml files. Nothing novel but I find it useful.
    #!/usr/bin/perl -w use strict; use XML::Simple; use Data::Dumper; #get all the .xml files from this base directory unless(opendir(CNF, '.')){ die "Unable to open directory for reading\n"; } my @config_files = sort grep { /\.xml$/ && -f "$_"} readdir(CNF); #clean up close CNF; DISPLAY: { print "Please select a file for parsing:\n"; for(my $i = 1; $i-1 < scalar(@config_files); $i++){ print "\t$i. $config_files[$i-1]\n"; } print "\n\t# "; } my ($filenum, $filename); chomp($filenum = <STDIN>); if($filenum !~ /^\d$/){ print "Please select the number\n"; goto DISPLAY; }else{ $filename = $config_files[$filenum-1]; } unless(open(CNF, $filename)){ die "unable to open XML config file". $!; }else{ my $file = do {local $/ = undef; <CNF>}; close CNF; my $xs = new XML::Simple(); my $ref = $xs->XMLin($file); print "\nXML structure (current).\n"; print Dumper($ref); print "\n"; ENDING:{ print "\n Q to quit\n"; my $key; chomp($key = <STDIN>); unless($key =~ /q/i){ goto ENDING; }else{ exit; } } }


    -InjunJoel
    "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://474874]
Approved by g0n
Front-paged by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2015-07-06 23:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (85 votes), past polls